The Google Analytics tracking code

Published

I’ve recently been fiddling with some Google Analytics stuff (partly to help with a Google Analytics training course) which involves adjusting the tracking code to make use of some of the more advanced GA features. I wanted to understand what the snippet of JavaScript Google provides actually does.

Here’s the standard tracking code I get when checking a GA ‘property’:

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga("create", "UA-12345678-1", "auto");
ga("send", "pageview");

Note that this is using the relatively new analytics.js API, instead of the older ga.js.

The first part gets everything set up and defines a globally accessible function called ga, which can then be called repeatedly with a set of commands. The set-up code creates an anonymous function (to avoid namespace pollution) then calls it once. Of the seven formal parameters, the first five have values provided when the function is called. The last two are simply listed as parameters to define them, as a minified alternative to using var. Here’s an unminified and tidied-up version, with the function’s arguments inlined:

(function () {
    window.GoogleAnalyticsObject = "ga";
    window.ga = window.ga || function () {
        window.ga.q = window.ga.q || [];
        window.ga.q.push(arguments);
    };
    window.ga.l = 1 * new Date();

    var new_script = document.createElement("script");
    var first_script = document.getElementsByTagName("script")[0];
    new_script.async = 1;
    new_script.src = "//www.google-analytics.com/analytics.js";
    first_script.parentNode.insertBefore(new_script, first_script);
})();

ga("create", "UA-12345678-1", "auto");
ga("send", "pageview");

The set-up code first defines two global variables by storing them in the global namespace accessible through the window object. The first, GoogleAnalyticsObject, is used by the code in analytics.js to find out the name of the other global, ga. That one is a function which queues up requests by stuffing them in the array ga.q. (The array is stored as a property of the function itself, which is fine in JavaScript, since a function is just an object.) There’s no attempt here to interpret the commands in any way, they’re just stored for later processing in the analytics.js code. That means the page can be loaded and useable without waiting for the GA stuff to finish and send data to Google.

The ga.l value is set to a time stamp, presumably for measuring when events happen relative to when the page was loaded. The Date constructor will return an object representing the current date and time, and multiplying it by one will force conversion to a number. In the case of Date objects, this will be the object’s ‘primitive value’, which will be the number of milliseconds since the start of January 1st 1970. Basically it’s a Unix time_t value times a thousand. (Since JavaScript numbers are double precision floats, there’s no danger of this running running out of numbers in the next few hundred thousand years.) This is defined in the ECMAScript specification edition 5.1 §15.9.1.1 (I had to check since I hadn’t come across this date-to-number conversion trick before).

The final part of the tracking code starts off the downloading of the analytics.js, by first creating a new <script> element, setting its src attribute to the appropriate URL, and then inserting it just before the first existing <script> element (of which there must be at least one to be running the tracking code in the first place).

A few things to note. Firstly, the URL is scheme-relative, since it starts with //. So you’ll get either the HTTP or HTTPS version to match what you’re using on your own site. Secondly, the async attribute tells the browser not to delay parsing or anything which the script downloads. It’ll be run once it’s available, but shouldn’t slow things down in the meantime.