Google Analytics Send Timeout in Ionic

August 25th 2017 Web Analytics Ionic 2/3

If you want to use Google Analytics as the analytics tool for your Ionic mobile application or progressive web application (PWA), there's an Ionic Native wrapper available for the Cordova plugin with support for mobile platforms as well as the browser (web) platform. Unfortunately, it consistently threw errors for me, when I tried to send a screenview event for the entry page:

Error: send timeout
    at UniversalAnalyticsProxy.js:184

Initializing Google Analytics

I wasn't doing anything strange, I simply followed the setup instructions:

  • I installed the Cordova plugin and the Ionic Native wrapper:

      cordova plugin add cordova-plugin-google-analytics --save
      npm install --save @ionic-native/google-analytics
    
  • I registered the Ionic Native wrapper in app.module.ts:

      import { GoogleAnalytics } from '@ionic-native/google-analytics';
    
      @NgModule({
        declarations: [
          // ...
        ],
        imports: [
          // ...
        ],
        bootstrap: [IonicApp],
        entryComponents: [
          // ...
        ],
        providers: [
          // ...
          GoogleAnalytics
        ]
      })
    
  • I initialized Google Analytics in app.component.ts (of course actual tracking ID must be used in place of <tracking ID>):

      import { GoogleAnalytics } from '@ionic-native/google-analytics';
    
      export class MyApp {
        constructor(platform: Platform, ga: GoogleAnalytics) {
          platform.ready().then(() => {
            // Okay, so the platform is ready and our plugins are available.
            // Here you can do any higher level native things you might need.
    
            ga.startTrackerWithId('<tracking ID>').then(() => {
              console.log('Google analytics is ready now');
            }).catch(error => {
              console.log('Error starting GoogleAnalytics', error);
            });
    
            // ...
          });
        }
      }
    
  • I tried to send a screenview event in home.ts once the page became active:

      import { GoogleAnalytics } from '@ionic-native/google-analytics';
    
      export class HomePage {
    
        constructor(private ga: GoogleAnalytics) { }
    
        ionViewDidEnter() {
          console.log('HomePage is now active');
          this.ga.trackView('HomePage');
        }
    
        // ...
      }
    

Running the Application in Browser

If you try to run the application with Cordova plugins using ionic serve, the plugins won't initialize even if they have support for the browser platform:

Native: tried calling GoogleAnalytics.startTrackerWithId, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator

For the Cordova plugins to actually initialize and work in the web browser, the project must be compiled for the browser platform:

cordova platform add browser --save
ionic build browser

This will generate the web application in the platforms/browser/www subfolder, however there's no built-in functionality in Ionic to serve the application from there - you need to use a web server for that. I'm using http-server:

npm install http-server -g
http-server

This will serve the application at http://localhost:8080 so that you can open it in the browser.

Fixing the Issue

Thanks to all the console.log() calls in my code, I figured out that the send timeout error was thrown because Google Analytics wasn't yet initialized with the tracking ID (i.e. startTrackerWithId() call wasn't complete) when I tried to send the event from HomePage:

20:00:04.663 home.ts:14 HomePage is now active
20:00:04.691 bootstrap.js:11 Ionic Native: deviceready event fired after 829 ms
20:00:04.891 main.js:250 Google analytics is ready now

To fix the issue, I created a wrapper to delay all other Google Analytics calls until the initialization was complete:

import { GoogleAnalytics } from '@ionic-native/google-analytics';
import { Injectable } from '@angular/core';

@Injectable()
export class DelayedGoogleAnalytics extends GoogleAnalytics {

  private resolveReadyFn: () => void;
  private rejectReadyFn: (reason?: any) => void;

  private readonly trackerReady = new Promise<void>((resolve, reject) => {
    this.resolveReadyFn = resolve;
    this.rejectReadyFn = reject;
  });

  startTrackerWithId(id: string, interval?: number): Promise<any> {
    return super.startTrackerWithId(id, interval).then(() => {
      super.debugMode().then(() => {
        this.resolveReadyFn();
      });
    }).catch(reason => {
      this.rejectReadyFn(reason);
    });
  }

  trackView(title: string, campaignUrl?: string, newSession?: boolean): Promise<any> {
    return this.trackerReady.then(() => {
      return super.trackView(title, campaignUrl, newSession);
    });
  }

  // wrappers for all other functions implemented by following the trackview example
}

In app.module.ts, I then registered this provider to be injected whenever the code requested GoogleAnalytics:

import { DelayedGoogleAnalytics } from './../providers/delayed-google-analytics';
import { GoogleAnalytics } from '@ionic-native/google-analytics';

@NgModule({
  declarations: [
    // ...
  ],
  imports: [
    // ...
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    // ...
  ],
  providers: [
    // ...
    {provide: GoogleAnalytics, useClass: DelayedGoogleAnalytics}
  ]
})

With this change, the first call to trackView() in HomePage still happened before the initialization was complete. However, my wrapper now delays the actual call to the underlying plugin until the initialization really is complete. The call happens a bit later, but succeeds.

I also included a call to debugMode() in my wrapper, which enables calls to console.debug() with all the details for each request sent to Google Analytics. This makes it easier to verify the calls without having to search for them in the browser network traffic viewer. It's worth mentioning though, that by default Chrome doesn't show debug output in its console. You need to change the output level to Verbose in order to see it:

Chrome console output levels

Copyright
Creative Commons License