jwegner
jwegner

Reputation: 7403

Trigger Google Analytics pageview for Angular App while using Google Tag Manager

I am building a SPA using Angular.js. We use Google Tag Manager to load in most of our analytics/marketing scripts, which includes Google Analytics. I am also using ui-router to manage states/views.

I would like to send pageview events off to Google Analytics whenever a user browses to a different state in my app. Part of the complexity in doing this with GTM is that GTM creates a named tracker. That means that all GA events need be prepended with the tracker name. That would usually look like this:

 ga('trackerName.send', 'pageview', {page: '/a/path/', title: 'A Title'});

GTM uses a randomly generated tracker name, so the tracker name needs to be grabbed at runtime. That can be done fairly simply with GA's getAll function. If you want to send the pageview event to all trackers, you would simply do:

 var allTrackers = ga.getAll();
 for(var i=0; i<allTrackers.length; i++) {
   ga.send(allTrackers[i].getName()+".send", "pageview", {page: '/a/path', title: 'A Title'});
 }

This works great for most of my pageview events. However, there is a race condition between when ui-router fires the initial view's $stateChangeSuccess (which is where I trigger the GA pageview), and when analytics.js is loaded.

Prior to analytics.js being loaded, Google Analytic's snippet creates a faux ga object, that you can send events to. This faux object does not have the rest of the ga functions on it, so you can not run getAll. Without the getAll function, I cannot get the tracker name and I cannot send pageview events.

As far as I can tell, Google Analytics does not provide any callbacks or events for when analytics.js is finished loading, so there is no way to tell when I will be able to start sending events. Right now I am using an $interval to check for the existence of ga.getAll, but that is not a very performant or ideal solution. This is what I've got:

 gaCheckInterval = setInterval(function() {
   if(typeof(ga) !== 'undefined' && typeof(ga.getAll) == 'function') {
     clearInterval(gaCheckInterval);
     sendBackloggedEvents();
   }
 }, 200);

Is there any other way to recognize when analytics.js has finished loading? Or any other way to send events to a named tracker, without having access to getAll?

Upvotes: 3

Views: 3642

Answers (1)

lossleader
lossleader

Reputation: 13495

Attempting to configure and trigger individual trackers circumvents the purpose of using a tag manager. Instead do:

dataLayer.push({event:'spa.pageView', page:..., title:...});

Where:

  • dataLayer is optionally renamed in the gtm snippet

  • spa is a handy abbreviation for your app/project/company/whatever in case you need to distinguish its actions later.

  • page and title can be whatever you like, you will reference them by adding dataLayer macros in your GTM container.

Then, in the tag manager you configure:

  1. rule of {{event}} ends with pageView.
  2. dataLayer macros for the page, title you are pushing into the dataLayer.
  3. UA Tag (and later whatever else) to fire (1) and use the macros in (2) for the TAG parameters they override.
  4. Repeat (3) as many times as you like for different UA properties with additional blocking rules, alternate macros or more granular firing rules as necessary.

Now you can configure the specifics and add other tag types that reuse the rules and macros without modifying the application for each change.

Upvotes: 4

Related Questions