Understanding the Google Analytics tracking code

In March 2013, Google launched the public beta of Universal Analytics, and with it new tracking code. The new tracking code makes use of modern JavaScript minification techniques, and its functionality is not immediately obvious. This page analyses and explains the new code.

The tracking code

The tracking code consists of four lines of minified JavaScript:

1
2
3
4
(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');

Adding whitespace

After adding some whitespace, the structure of the tracking code becomes more apparent:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
(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');

We can now see that it is an immediately invoked functional expression (IIFE) with seven parameters. Only five arguments are passed to the function, with the other two parameters being used to create variables without requiring a var statement, in order to save a few more characters. (The same technique is used in the minified version of the runOnLoad function.)

In minified code, function parameters are usually named either alphabetically or mnemonically (for example, with the w parameter being passed the window object). In this case the parameters have been named to spell the word isogram, which appropriately is a term for a word without repeating letters.

Substituting the parameters

Substituting in the parameter values, and replacing string indices with properties on objects, produces the following code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
(function(){
  window.GoogleAnalyticsObject = 'ga';
  window.ga = window.ga || function(){
    (window.ga.q = window.ga.q || []).push(arguments)
  },
  window.ga.l =1 * new Date();
  var a = document.createElement('script'),
  var m = document.getElementsByTagName('script')[0];
  a.async = 1;
  a.src = '//www.google-analytics.com/analytics.js';
  m.parentNode.insertBefore(a, m)
})();

Note that the use of the g and r parameters, corresponding to the Google Analytics script address and object name, actually increase the size of the minified code. However, passing them as arguments separates functionality from configuration, which is good practice in software development.

The commented code

We are now in a position to rewrite the code, replacing minification tricks with more readable structures and adding comments:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
(function(){

  // store the name of the Analytics object
  window.GoogleAnalyticsObject = 'ga';

  // check whether the Analytics object is defined
  if (!('ga' in window)){

    // define the Analytics object
    window.ga = function(){

      // add the tasks to the queue
      window.ga.q.push(arguments);

    };

    // create the queue
    window.ga.q = [];

  }

  // store the current timestamp
  window.ga.l = (new Date()).getTime();

  // create a new script element
  var script   = document.createElement('script'),
  script.src   = '//www.google-analytics.com/analytics.js';
  script.async = true;

  // insert the script element into the document
  var firstScript = document.getElementsByTagName('script')[0];
  firstScript.parentNode.insertBefore(script, firstScript)

})();

Observations

The previous Google Analytics tracking code created a global variable called _gaq (an abbreviation for Google Analytics Queue). _gaq was created as an empty array, with tasks pushed on to it. The new tracking code creates a global variable called ga, with a property called q to hold the queue. ga is a function, which pushes its arguments array onto the queue.

The name ga is more generic than _gaq and hence more likely to clash with third-party code. Because of this, the tracking code allows it to be renamed by passing an alternative name into the functional expression. The name is stored in the global variable GoogleAnalyticsObject so that other code can look up the name used.

The new tracking code stores the timestamp of when it was executed in the l property of the ga variable.

The old tracking code checked document.location.protocol in order to determine whether to load the Analytics code over SSL. The new tracking code takes the simpler approach of using a protocol- (or scheme-) relative URL (technically called a network-path reference), which causes the code to be loaded using the same scheme as the containing page — either http or https.

Where now?

Found this useful? Share it:

Also in JavaScript: