Ajax Page Tracking with Google Universal Analytics

With the availability of html5 and ajax websites on the rise, how to elegantly integrate Google Universal Analytics into single page javascript applications?

Single Page Applications

Modern websites often use html5 pushstate and ajax to load content dynamically, providing a fluid user experience and improved performance. Such websites are often refered to as single page applications (SPA). Unlike traditional websites that load the analytics tracker on each full page load, SPA's require us to track virtual page views manually.

Google Universal Analytics

This tutorial is written in regards to Google Universal Analytics, launched in 2014, effectively replacing Classic Google Analytics. I am writing this guide because I could not find much information about using Universal Analytics in SPA's. Benefits of upgrading from Classic- to Universal Google Analytics, can be found here.

Default Tracking Code

For Universal Analytics, you are asked to copy and paste the following tracking code into every webpage you want to track. Basically, it injects the analytics script asynchronously into the page, initiates the tracker and tracks the page that loads:

Ref.: Introduction to Analytics.js

Custom Tracking Code

What if we don't want inline javascript junk floating around in our documents? What if we want to initiate analytics and track virtual pageviews from within our own javascript application? The tracking code can easily be converted into a custom function readable to humans:

function gaTracker(id){
  $.getScript('//www.google-analytics.com/analytics.js'); // jQuery shortcut
  window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
  ga('create', id, 'auto');
  ga('send', 'pageview');   
} 

Some would argue that this could delay tracking of the initial pageview, but personally I prefer to focus client resources on loading the native website application before applying unrelated resources. Furthermore, adding the tracker directly to our javascript application, makes sure we don't need to bloat page documents with the default tracking code.

Ref.: Analytics Advanced Configuration

Tracking Virtual Page Views

After initiating the tracker and loading virtual pages with our Ajax/html5 application, we can easily track each page by triggering the following analytics method:

ga('send', 'pageview');

The above will automatically use the path segment in the browser address bar, which you have likely updated already either with html5 pushstate or #hash. Personally, I prefer to wrap the page tracker inside my own function for additonal control:

function gaTrack(path, title) {
  ga('set', { page: path, title: title });
  ga('send', 'pageview');

}

The advantage of the above, is that it allows us to persistently set the page path and title for the current page. This is beneficial as it allows us to trigger the tracker even if the target page has not yet loaded. Also, it allows us to set page data for multiple hits, for instance if we want to track image clicks from within the same page.

Ref.: Single Page Application Tracking

Code summary

// Function to load and initiate the Analytics tracker
function gaTracker(id){
  $.getScript('//www.google-analytics.com/analytics.js'); // jQuery shortcut
  window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
  ga('create', id, 'auto');
  ga('send', 'pageview');
}

// If you are not using jQuery, replace $.getScript() line above with the following:
var script = document.createElement('script');
script.src = '//www.google-analytics.com/ga.js';
document.getElementsByTagName('head')[0].appendChild(script);

// Function to track a virtual page view
function gaTrack(path, title) {
  ga('set', { page: path, title: title });
  ga('send', 'pageview');
}

// Initiate the tracker after app has loaded
gaTracker('UA-XXXX-Y');

// Track a virtual page
gaTrack('/silence/golden/', 'Silence is Golden');

// If you don't need to set page path and title, skip the _gaTracker function, and use the native analytics page tracker instead:
ga('send', 'pageview')

Bonus: Track image clicks

On the topic of dynamic tracking, you might want to know how to track an image click event also:

// Track an image click event
ga('send', 'event', 'image', 'click', 'image click', 'filename.jpg');
// ga('send', 'event', 'category', 'action', 'label', 'value');

Ref.: Event Tracking