Tutorial: Sending data to multiple Google Analytics properties

Past entries

Ever since I started creating HTML5 games, I have always used Google Analytics. I usually create one new account and property per website, and then read the data when I need to.

Though, I sometimes find it pretty useful to send data to multiple properties. For instance, I have one global account and property for all my games. Each of my games sends data to its respective property, but also to the global property.

Since I have around 20 games that I need to send data to, I didn't want to change every one of them, so I wrote some Javascript to address my need.

This solution, though very simple, has some limitations:

  • It doesn't support more advanced Google Analytics features. I decided to only support page views and events. This is the only data I'm interested in, so that's perfectly fine to me.
  • It doesn't allow to send data to specific properties. It sends the exact same data to all accounts, only a prefix is added (if needed).
  • It doesn't work with certain specific usage of the Google Analytics API, but you can probably edit the code to fit your needs.
  • It's probably not the most elegant way to do it. But, as I previously said, I needed to apply it to a lot of games and I couldn't change the tracking system on every single one of them. If you can create your own abstraction layer, then you should probably do it.

If these issues are not a problem for you, then you might consider using my solution. It will allow you to update your existing code pretty quickly. Otherwise you can always find some inspiration from it to create your own.

The first thing we're gonna do is to remove the old API invokation. You probably already have something similar to this in your <head>:

<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-Y', 'example.com');
	ga('send','pageview');
</script>

Just remove it, because we're going to invoke the API somewhere else.

Now, let's add the new code somewhere in your existing JS:

(function(){
	if(!window.gaProperties){
		console.warn('Google Analytics properties not set. Please setup window.gaProperties to enable tracking.');
	}else{
		// Regular analytics code, no need to load it from anywhere else
		(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','gao'); // putting the API in gao()
		
		// Creating trackers in the original GA object
		for(var i = 0 ; i < window.gaProperties.length ; i++){
			gao('create', window.gaProperties[i].property, 'none',{
				name : 'tracker' + i
			});
		}
        
		// Creating a ga() function that will redirect everything to 
		// the right trackers.
		window.ga = function(){
			var action = arguments[0],
				args,
				trackerAction,
				otherArgs = Array.prototype.slice.call(arguments,1);
            
			for(var i = 0 ; i < window.gaProperties.length ; i++){
				// Basically, we replace each action by trackerID.action.
				// Since we have tracker0, tracker1..., we can do
				// tracker0.send, tracker1.send... instead of just send.
				
				trackerAction = 'tracker' + i + '.' + action;
				args = [trackerAction].concat(otherArgs);
				
				// Adding a prefix
				for(var j = 2 ; j < args.length ; j++){
					if(typeof args[j] === 'string'){
						if(args[j].indexOf('/') == 0){
							// For pageviews, adding the prefix after the slash
							args[j] = '/' + (window.gaProperties[i].prefix || '') + args[j].substr(1);
						}else{
							args[j] = (window.gaProperties[i].prefix || '') + args[j];
						}
				   }
				}
				gao.apply(window,args);
			}
            
            // Delaying the next heartbeat
            clearInterval(hbInterval);
            hbInterval = setInterval(hb,15000);
		};
        
        var lastInteraction = 0;
        var interacted = function(){
            lastInteraction = Date.now();
        }
	}
})();

Alright, so what does it do exactly?

The first thing this code does is that it checks if a window.gaProperties object is already set. This object has to be set before the code above will be run. This object is only an array containing the settings for the different properties.

Here is an example:

window.gaProperties = [{
	property : 'UA-XXXXXXXX-Y'
},{
	property : 'UA-XXXXXXXX-Y',
	prefix : 'mywebsite-'
}
//...
];

This part is important, since the script won't be able to know which property to send the data to if you don't specify it. You can find your property IDs in Google Analytics. They will look like UA-12345678-1.

You can also specify a prefix. This prefix will be added to every page view or event parameter. This is useful for global accounts, so you can differentiate which website they're relative to.

Anyway, the important part is that you have to declare this object before the above script is run.

Once the script detects that property IDs are set, it includes the Google Analytics API, which creates a gao() function, then creates a tracker for each property, and finally creates a ga() function. This is where the magic lies.

Usually, when you send data to Google Analytics, you probably use the ga() function, which is specified when you included the API. Here, we are using a gao() function instead. The only difference is the name. GAO stands for Google Analytics Original.

Though, we then create a ga() function that will send data to all properties through gao(). In other words, when you call ga(), it will then make several calls to gao() that will send the data to the trackers. It means that you shouldn't have to edit your existing calls to ga()!

If you're interested in knowing how to work with multiple tracking objects, you should read this page.

One last thing: this code creates trackers and redirects ga() calls to gao(), but if you don't already make calls to ga() in your code, it won't work. You need to send a page view (at least), like for example:

ga('send','pageview','/mycoolpage.html');

Note: if you don't add the slash at the beginning of the page name, it won't work, unless you modify the script.

That's all, I hope you will find it useful!

< Analyzing action movies' plots since 1950
Portfolio update >