Tracking Google Analytics Page Views with Angular.js

I'm setting up a new app using Angular.JS as the frontend. Everything on the client side is done with HTML5 pushstate and I'd like to be able to track my page views in Google Analytics.

If you're using ng-view in your Angular app you can listen for the $viewContentLoaded event and push a tracking event to Google Analytics.

Assuming you've setup your tracking code in your main index.html file with a name of var _gaq and MyCtrl is what you've defined in the ng-controller directive.

function MyCtrl($scope, $location, $window) {
  $scope.$on('$viewContentLoaded', function(event) {
    $window._gaq.push(['_trackPageview', $location.url()]);
  });
}

UPDATE: for new version of google-analytics use this one

$window.ga('send', 'pageview', { page: $location.url() });

When a new view is loaded in AngularJS, Google Analytics does not count it as a new page load. Fortunately there is a way to manually tell GA to log a url as a new pageview.

_gaq.push(['_trackPageview', '<url>']); would do the job, but how to bind that with AngularJS?

Here is a service which you could use:

(function(angular) { 

  angular.module('analytics', ['ng']).service('analytics', [
    '$rootScope', '$window', '$location', function($rootScope, $window, $location) {
      var track = function() {
        $window._gaq.push(['_trackPageview', $location.path()]);
      };
      $rootScope.$on('$viewContentLoaded', track);
    }
  ]);

}(window.angular));

When you define your angular module, include the analytics module like so:

angular.module('myappname', ['analytics']);

Just a quick addition. If you're using the new analytics.js, then:

var track = function() {     
 ga('send', 'pageview', {'page': $location.path()});                
};

Additionally one tip is that google analytics will not fire on localhost. So if you are testing on localhost, use the following instead of the default create (full documentation)

ga('create', 'UA-XXXX-Y', {'cookieDomain': 'none'});

app.run(function ($rootScope, $location) {
    $rootScope.$on('$routeChangeSuccess', function(){
        ga('send', 'pageview', $location.path());
    });
});

I've created a service + filter that could help you guys with this, and maybe also with some other providers if you choose to add them in the future.

Check out https://github.com/mgonto/angularytics and let me know how this works out for you.

Thanks!

I've created a simple example on github using the above approach.

https://github.com/isamuelson/angularjs-googleanalytics

Merging the answers by wynnwu and dpineda was what worked for me.

angular.module('app', [])
  .run(['$rootScope', '$location', '$window',
    function($rootScope, $location, $window) {
      $rootScope.$on('$routeChangeSuccess',
        function(event) {
          if (!$window.ga) {
            return;
          }
          $window.ga('send', 'pageview', {
            page: $location.path()
          });
        });
    }
  ]);

Setting the third parameter as an object (instead of just $location.path()) and using $routeChangeSuccess instead of $stateChangeSuccess did the trick.

Hope this helps.

If someone wants to implement using directives then, identify (or create) a div in the index.html (just under the body tag, or at same DOM level)

<div class="google-analytics"/>

and then add the following code in the directive

myApp.directive('googleAnalytics', function ( $location, $window ) {
  return {
    scope: true,
    link: function (scope) {
      scope.$on( '$routeChangeSuccess', function () {
        $window._gaq.push(['_trackPageview', $location.path()]);
      });
    }
  };
});

The best way to do this is using Google Tag Manager to fire your Google Analytics tags based on history listeners. These are built in to the GTM interface and easily allow tracking on client side HTML5 interactions .

Enable the built in History variables and create a trigger to fire an event based on history changes.

In your index.html, copy and paste the ga snippet but remove the line ga('send', 'pageview');

<!-- Google Analytics: change UA-XXXXX-X to be your site's ID -->
<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');
</script>

I like to give it it's own factory file my-google-analytics.js with self injection:

angular.module('myApp')
  .factory('myGoogleAnalytics', [
    '$rootScope', '$window', '$location', 
    function ($rootScope, $window, $location) {

      var myGoogleAnalytics = {};

      /**
       * Set the page to the current location path
       * and then send a pageview to log path change.
       */
      myGoogleAnalytics.sendPageview = function() {
        if ($window.ga) {
          $window.ga('set', 'page', $location.path());
          $window.ga('send', 'pageview');
        }
      }

      // subscribe to events
      $rootScope.$on('$viewContentLoaded', myGoogleAnalytics.sendPageview);

      return myGoogleAnalytics;
    }
  ])
  .run([
    'myGoogleAnalytics', 
    function(myGoogleAnalytics) {
        // inject self
    }
  ]);

I am using ui-router and my code looks like this:

$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams){
  /* Google analytics */
  var path = toState.url;
  for(var i in toParams){
    path = path.replace(':' + i, toParams[i]);
  }
  /* global ga */
  ga('send', 'pageview', path);
});

This way I can track different states. Maybe someone will find it usefull.

Merging even more with Pedro Lopez's answer,

I added this to my ngGoogleAnalytis module(which I reuse in many apps):

var base = $('base').attr('href').replace(/\/$/, "");

in this case, I have a tag in my index link:

  <base href="/store/">

it's useful when using html5 mode on angular.js v1.3

(remove the replace() function call if your base tag doesn't finish with a slash /)

angular.module("ngGoogleAnalytics", []).run(['$rootScope', '$location', '$window',
    function($rootScope, $location, $window) {
      $rootScope.$on('$routeChangeSuccess',
        function(event) {
          if (!$window.ga) { return; }
          var base = $('base').attr('href').replace(/\/$/, "");

          $window.ga('send', 'pageview', {
            page: base + $location.path()
          });
        }
      );
    }
  ]);

I have created angularJS directive for google analytics. It can be added as module dependency in your existing angularJS application. Checkout https://github.com/varunhooda/angular-google-analytics-directive

If you are looking for full control of Google Analytics's new tracking code, you could use my very own Angular-GA.

It makes ga available through injection, so it's easy to test. It doesn't do any magic, apart from setting the path on every routeChange. You still have to send the pageview like here.

app.run(function ($rootScope, $location, ga) {
    $rootScope.$on('$routeChangeSuccess', function(){
        ga('send', 'pageview');
    });
});

Additionaly there is a directive ga which allows to bind multiple analytics functions to events, like this:

<a href="#" ga="[['set', 'metric1', 10], ['send', 'event', 'player', 'play', video.id]]"></a>