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.