Reputation: 63719
We have a custom Google Analytics plugin that will be sending commands to track custom pageviews and log events. Here's a simplified repro of our scenario:
// Version 1: only works with analytics.js, not with GTM
function GaPlugin(tracker, config) {
// Simplified for SO, we actually use the config argument
// to track more interesting pages and events...
ga(tracker.get('name') + ".send", "pageview", "/virtual/page/view");
}
var ga = window[window["GoogleAnalyticsObject"] || "ga"];
if (typeof ga == "function") {
ga("provide", "myAnalytics", GaPlugin);
ga("require", "myAnalytics", { /* omitted for simplicity */ });
}
This works fine if analytics.js
is included directly on the page. However, we're now including universal analytics on the page using the Google Tag Manager. Thus we ran into the dreaded error...
Command ignored. Unknown target: undefined
...as seen in the Google Analytics debugging Chrome plugin when the require
command is being executed.
This question and this blogpost imply the need to set a tracker name (in GTM, using: Edit Tag => More Settings => Advanced Configuration => Set Tracker Name checkbox) but the tooltip says "Use of named trackers is highly discouraged in GTM". So instead I changed things to this:
// Version 2: crashes with GTM because ga is loaded after this code
function GaPlugin(tracker, config) {
// Simplified for SO, we actually use the config argument
// to track more interesting pages and events...
ga(tracker.get('name') + ".send", "pageview", "/virtual/page/view");
}
var ga = window[window["GoogleAnalyticsObject"] || "ga"];
if (typeof ga == "function") {
ga("provide", "myAnalytics", GaPlugin);
ga(ga.getAll()[0].get("name") + ".require", "myAnalytics", { });
}
But now I'm met with an error because ga
is undefined
when the above executes, because GTM will load universal analytics asynchronously, where I want to run my code to bootstrap the plugin right away. This also means I cannot place a callback on the ga
command queue, because again: it doesn't exist yet.
In essence, the order of things (I think) is now:
The only workaround I could think of was this:
// Version 3: ugly workaround...
function GaPlugin(tracker, config) {
// Simplified for SO, we actually use the config argument
// to track more interesting pages and events...
ga(tracker.get('name') + ".send", "pageview", "/virtual/page/view");
}
var interval = setInterval(function() {
var ga = window[window["GoogleAnalyticsObject"] || "ga"];
if (typeof ga == "function" && typeof ga.getAll == "function") {
ga("provide", "myAnalytics", GaPlugin);
ga(ga.getAll()[0].get("name") + ".require", "myAnalytics", { });
clearInterval(interval);
}
}, 250);
Isn't there a better way to do this? The GTM documentation nor the GA Plugins documentation seems to have any info on this.
As a footnote, I just realized it might also work if I mimic the tracking snippet by creating ga
as a command queue myself. But that also feels like a workaround, not a solution...
Upvotes: 2
Views: 1963
Reputation: 63719
Not satisfying, but let me share my workaround as an answer nonetheless, as it is in fact the solution I'm using right now. It builds on the final footnote: mimicking what the Google Analytics bootstrapping snippet does.
I'm setting up the ga
object, or at least its q
property, myself:
function createGoogleAnalyticsQueueIfNeeded() {
// As a workaround for: http://stackoverflow.com/questions/40587544
// We mimick: https://developers.google.com/analytics/devguides/collection/analyticsjs/tracking-snippet-reference
var gaKey = window["GoogleAnalyticsObject"] || "ga";
var ga = window[gaKey] || function () {
(window[gaKey]["q"] = window[gaKey]["q"] || []).push(arguments);
};
window[gaKey] = ga;
return ga;
}
After calling the above, you can place a command on that queue which will be executed whenever GTM has finished loading GA (which also includes an optimization to run the plugin for all trackers):
var ga = createGoogleAnalyticsQueueIfNeeded();
ga(function() {
ga("provide", "myAnalytics", GaPlugin);
ga.getAll().forEach(function(t) {
ga(t.get("name") + ".require", "myAnalytics", { });
});
});
Et voila, the provide
and .require
calls now run whenever GA (loaded via GTM) hollers at the callback.
Upvotes: 1