Jeroen
Jeroen

Reputation: 63719

How to send a ga command to a tracker with no name?

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:

  1. The GTM snippet starts loading (async).
  2. My own javascript code runs.
  3. GTM will start loading analytics (async).
  4. Analytics is loaded and ready to be used.

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

Answers (1)

Jeroen
Jeroen

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

Related Questions