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.