How to setup Google Analytics and event tracking in your Angular application

Posted on Saturday, 9th January 2016

Google have made installing Google Analytics on a website extremely easy, simply copy and paste the tracking code provided into your website and you’re done. But what happens when you want to set Google Analytics up on a single page application, say an Angular app? Having recently worked on an Angular application where I was tasked with registering page views and other various events within Google Analytics, I thought I’d take a moment to document how it was done and what I’d learned whilst doing it.

The problem with tracking code and single page applications

Traditionally, as your user navigates a normal website each page raises the Google Analytics pageview event (highlighted below).

<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');

  ga('create', 'UA-xxxxxxxx-x', 'auto');
  ga('send', 'pageview'); // Pageview event
</script>

However within the single page application space things are slightly different. Once your initial page has loaded, all subsequent pages or views are rendered within the application without the need for a page refresh or page load - this means no further pageview events will be raised. This would result in very inaccurate visitor data as Google Analytics would capture the initial page load, and then ignore the duration of their session.

The solution

Having had to deal with this very same issue (though I needed to raise multiple custom events when certain functionality was used) just recently the solution I eventually settled with was a simple one.

First of all we want to break our Analytics code into two, allowing our Google Analytics tracking code to be registered (notice how I’ve removed the pageview event - we will call this later).

This code should be added into your main index.html page or your base Layout/template page.

...
</head>
<body>
<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');

  ga('create', 'UA-xxxxxxxx-x', 'auto');
 // Pageview event removed so we can call it once the view has loaded.
</script>
<div class="wrapper">
...

Next we’re going to create a Google Analytics service (well call it GoogleAnalyticsService.js) that will be responsible for encapsulating our Analytics behaviour and used to manually raise our pageview event (and other events for that matter!) once the page has loaded. We can then inject our service into the appropriate Angular controllers and invoke the functions that will raise our Google Analytics events.

Take a moment to look at the Google Analytics page tracking documentation to see that we’re passing in a page path (excluding the domain - ie: /checkout/) to uniquely identify the page within our Analytics reports.

(function (angular, window) {

    "use strict";

    var ngModule = angular.module("ourAppModule");

    ngModule.factory("googleAnalyticsService", [
        "$window", function ($window) {

            var ga = $window.ga;

            var _pageView = function(page) {			
                ga("send" "pageview", {
                    page: page
                });
            };

            return {
                pageView: _pageView,
            };
        }
    ]);

})(window.angular);

Now that we’ve created our GoogleAnalyticsService we can simply inject it into our application’s controllers and invoke the pageView() function which in turn raises the Google Analytics pageview event.

Single page application version:

If your Angular application is a single page application then we can go one further and automatically call the pageview function once our view has loaded by adding the event to Angular’s $viewContentLoaded event listener, like so:

(function (angular, window) {

    "use strict";

    var ngModule = angular.module("ourAppModule");

    ngModule.factory("googleAnalyticsService", [
        "$window", function ($window) {

            var ga = $window.ga; //Google Analytics

            var _pageView = function(page) {			
                ga("send" "pageview", {
                    page: page
                });
            };

            var _viewChangePageView = function(scope, page) {
                if (scope){
                    scope.$on('$viewContentLoaded', function(event) {
                        _pageView(page)
                    });
                }
            };

            return {
                pageView: _pageView,
                viewChangePageView: _viewChangePageView // used for SPA
            };
        }
    ]);

})(window.angular);

From here all we need to do is invoke our method from our application’s controllers:

(function(angular, window) {

    'use strict';

    var app = angular.module('ourAppModule');
    app.controller('CheckoutController', ['$location', 'googleAnalyticsService', function($location, googleAnalyticsService) {
		...

		googleAnalyticsService.pageView($location.path());

		...
	}]);

})(window.angular);

Now when our user’s visit our application we should start seeing our visitors browsing data flooding into our Google Analytics account. You can verify this by setting Google Analytics into debug mode and using your browser’s console to see the events being raised. To do this simply replace the script source from analytics.js to analytics_debug.js.

<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_debug.js','ga'); //debug mode

  ga('create', 'UA-xxxxxxxx-x', 'auto');
</script>

Once we’ve verified that our events are being raised then switch your analytics path back to analytics.js and you’re good to go!