Using Google Analytics in a (Durandal) SPA

I've been playing around with Durandal lately, and was wondering how you get a Durandal SPA to work with Google Analytics. The problem is the visitor is staying on the same html page. Yet you want analytics for your different views (so everytime the hash in the browsers navigation bar changes).

It turns out this is fairly easy. I'm putting this here for my own and anyone else's reference. It probably works with other SPA frameworks too (Angular for example).

There are a number of composition lifecycle functions that a Durandal viewmodel can implement, but instead of putting Google Analytics code in every viewmodel, it's easier to just include it once. Durandal provides an event when navigation has completed. Hook into that event and you can add a Google Analytics entry each time your user navigates to a new view:

router.on('router:navigation:complete', function(instance, instruction) {  
    ga('create', 'UA-XXXXXXXX-X', 'example.com');
    ga('send', 'pageview');
});

Put this in your main.js or shell.js file so it is hooked up early in your application's lifetime. In my case, I added it in the 'activate' method of the shell.js (you can see it in my GitHub repository). Last but not least, don't forget to include the usual Google Analytics code so the calls above actually work:

<script>  
    (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');
</script>

This is the newer code that works with 'Universal Analytics', but it works the same for the older code. You just have to split the code into the part that defines the function and the part that actually adds an entry on every navigation.

Update: Check out George's comment below, for less calls to Google's servers.