How to get Google Analytics to work for your Single Page Application

Posted by Marcus Hammarberg on May 7, 2015
Stats

One of the things that gets increasingly fascinating the older I get is the new stuff you pick up as you “do things for real”. Right now we have been building a site for my current organisation.

We built a little CMS to drive content and the whole page is a Single Page Application (SPA). As we approached being finished we of course wanted to add Google Analytics to the site. Dead simple.

Or not maybe … in this post I’ll describe how we got it to work for our Single Page Application. Google Analytics default was is not built for that. And many descriptions you will find out there is written based with a client-side framework in mind, like Backbone.js.

What I write about below only requires jQuery, and that’s mostly for convience.

One of the things that gets increasingly fascinating the older I get is the new stuff you pick up as you “do things for real”. Right now we have been building a site for my current organisation.

We built a little CMS to drive content and the whole page is a Single Page Application (SPA). As we approached being finished we of course wanted to add Google Analytics to the site. Dead simple.

Or not maybe … in this post I’ll describe how we got it to work for our Single Page Application. Google Analytics default was is not built for that. And many descriptions you will find out there is written based with a client-side framework in mind, like Backbone.js.

What I write about below only requires jQuery, and that’s mostly for convience. As with most things I learn it’s based on others knowledge that I just tweak and in this case I found a GREAT article that contained much of the information I need, but didn’t take me all the way. Go ahead and read it now!

Infrastructure

The first thing we did, based on the article above, was to create a custom javascript function for Google Analytics tracking. Here is where we ended up:

function gaTrack(path, title) {
$.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', 'UA-YOURID', 'auto');

  var track =  { page: path, title: title};
  ga('set', track);
  ga('send', 'pageview');
};
  • On line 1 we use jQuery (you can do this without jQuery if you check the end of the mentioned article) to dynamically load the Google Analytics script
  • Line 2 defines a ga function in our window
  • Line 3 is where your insert your tracking code from Google Analytics
  • On line 5 a little object with the page and title is created
  • This is set and passed to the ga function which tracks it, asynchronously, to Google Analytics

Updated version

After some great comments by Jim Geurts I understand that our solution went against the recommendations from the Google Analytics team. Our code is, and I quote Jim;

creates a new tracker every time you track a pageview.

I don’t really understand the full implications of that, but somehow as Jim kindly informed me when I asked, we need to create a tracker (line 2-4 above) only on the first load of the page. Here’s two new functions that does that:

function gaInit() {
  $.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', 'UA-62590784-1', 'auto');

  console.log("Initalized");
  return ga;
};

function gaTrack(path, title) {
  var track =  { page: path, title: title};

  ga = window.ga || gaInit();

  ga('set', track);
  ga('send', 'pageview');

  console.log("Tracked");
};

Basically I’ve just created a new gaInit function that returns the object it initializes, the ga object. In the gaTrack function I just check if the window.ga object is present, if not I call the gaInit() to create it, initializing ga just-in-time and only the first time.

The rest of the article works as described below, and was to my joy not needed to be updated.

Thanks Jim.

Using it

Now, this is where that article leaves us. And at least I felt a little bit abandoned at this point. Because now we need to use it… on A LOT of place. And I didn’t really felt like writing a onClick="ga()" on every thing click-able in our page.

The easy use

The first place we should use this function is on the main page of the application, in my case index.html. This is the tracking of your grandfathers, tracking the loading a new page.

Here’s my code for that, placed just above the &t;/body>-tag:

	<script>
      gaTrack("/", "Beranda");
    </script>
</body>

“Beranda” is Indonesian for “Home”, which is how we will refer to this page.

Well, that was easy.

Catch’em all

However, the problem is that once the page is downloaded there is no reload of the index.html. That’s the whole idea of a SPA, right? How to track all the client-side navigation then?

First problem to solve is to catch all the things that’s clicked on our page. Here jQuery comes to our help. For us, all things click-able are a-tags so we could write the following function:

$("a").click(function(evt) {
  // tracking code here
});

However, there are other ways to track this, should you have other tags that recieve clicks. For example you could catch all clicks in the main div, or even body tag, if you give it an id or a class. Let’s say that your main div is defined like this <div id="main">, then you can write the following function to “catch” all clicks:

$("#main").click(function(evt) {
  // tracking code here
});

Now let’s track’em

To track it we can simply use the gaTrack(path, title) we created before:

$("a").click(function(evt) {
  var path = evt.currentTarget.pathname + evt.currentTarget.hash;
  var title = evt.currentTarget.title || evt.currentTarget.text;
  gaTrack(path, title);
});

On line 2 we simply pull the pathname and the hash from the currentTarget which is the item clicked. This will be the page that we send to Google Analytics.

Line 3 requires a little more explanation. Should the a-tag contain text we use that from the .text property. Here’s an example of such a link:

<a class="page-scroll" href="#articles">Artikel</a>

However, sometimes the a-tag wraps a lot of other things, divs and images etc. and in that case we will get that html-code in the .text-property.

Here’s such an example:

<a href="#article-" class="modal-link" data-toggle="modal">
    <div class="list-item-hover">
        <div class="list-item-hover-content">
            <i class="fa fa-plus fa-3x"></i>
        </div>
    </div>
    <img src="" class="img-responsive" alt="">
</a>

The simple solution for us was just to add a title-attribute on the a-tag. This is a good practice anyway since that will displayed when the user hovers over an image for example.

Here’s an example on how that can look:

<a href="#article-" title="" class="modal-link" data-toggle="modal">

Now in our catch-all-click-handler we can check if the title-attribute is set and if not use the .text

var title = evt.currentTarget.title || evt.currentTarget.text;

Summary

With these simple functions we got very simple, client-side Google Analytics tracking on a granularity level of our choice.



Published by Marcus Hammarberg on Last updated