Reputation: 7403
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
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:
rule
of {{event}} ends with pageView
.dataLayer macros
for the page
, title
you are pushing into the dataLayer.UA Tag
(and later whatever else) to fire (1) and use the macros in (2) for the TAG parameters they override.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