This guide describes plugins, an advanced feature allowing developers to package their custom tracking libraries into asynchronously loaded scripts that can interact directly with the analytics.js command queue.
Overview
Advanced users can often build up hundreds of lines of customized code to help manage tracking a complex site, or to provide extended features not already available in analytics.js. These custom libraries are typically loaded from a separate JavaScript file sourced throughout a site. In order to load these scripts quickly, without interrupting the loading and rendering of your website, we recommend that you always load such scripts asynchronously.
<script async src="myplugin.js"></script>
Since analytics.js is also loaded asynchronously, it can be challenging to
coordinate the execution of your custom tracking script with the analytics.js
command queue. The analytics.js plugin system solves this problem with two
simple commands: require and provide.
Require
The require command takes the name of a plugin and blocks
execution of any subquent commands until the target plugin has been loaded
and executed.
ga('create', 'UA-XXXXX-Y', 'auto');
ga('require', 'myplugin');
ga('send', 'pageview');
In the example above, if 'myplugin' has not yet been loaded,
the analytics.js command queue would pause until it becomes available. The
'send' command, and any subsequent commands in the page, would
be blocked until that time.
Provide
To register your custom plugin with analytics.js, use the provide
command. The provide command takes two arguments: the name of your
plugin, and a constructor function that creates new instances of your plugin.
function MyPlugin(tracker) {
alert('Loaded plugin on tracker ' + tracker.get('name'));
}
ga('provide', 'myplugin', MyPlugin);
In this example, myplugin.js contains a simple plugin function that pops up
an alert box when loaded. This function will be invoked each time
ga('require', 'myplugin'); is called.
Implementation
Now that we've covered the basics of the analytics.js plugin system, we can walk through the details involved in creating a plugin script, configuring plugin instances, and defining plugin methods.
Creating a Plugin Script
In addition to any other custom logic, each plugin script should include at
least one plugin constructor function, and a call to the provide
command to register that plugin. Since the plugin script needs to function
correctly even if the analytics.js snippet has been configured to use a
customized identifier for the ga global object, we can't simply
call the ga('provide', ..) command. Instead, we include
a copy of the providePlugin function shown below in each plugin
script and use it to register the plugin.
myplugin.js
// Provides a plugin name and constructor function to analytics.js. This
// function works even if the site has customized the ga global identifier.
function providePlugin(pluginName, pluginConstructor) {
var ga = window[window['GoogleAnalyticsObject'] || 'ga'];
if (ga) ga('provide', pluginName, pluginConstructor);
}
// Plugin constructor.
function MyPlugin(tracker) {
alert('Loaded myplugin on tracker ' + tracker.get('name'));
}
// Register the plugin.
providePlugin('myplugin', MyPlugin);
Configuring Plugin Instances
In addition to specifying the name of the plugin to load, the
require command allows you to pass a configuration object
used to initialize a plugin instance.
ga('create', 'UA-XXXXX-Y', 'auto');
ga('require', 'localHitSender', {path: '/log', debug: true});
ga('send', 'pageview');
The configuration object is passed to the plugin constructor as the second parameter.
function LocalHitSender(tracker, config) {
this.url = config.url;
this.debug = config.debug;
if (this.debug) {
alert('Enabled local hit sender for: ' + this.url);
}
}
providePlugin('localHitSender', LocalHitSender);
Defining Plugin Methods
Plugins can expose their own methods which can be invoked using the
ga command queue syntax:
ga('[targetName.][pluginName:]methodName', ...);
Where targetName is the name of the tracker. If
targetName is not specified, the default target name 't0' is used.
The pluginName is the name of the plugin. The
methodName is the name of a method on the plugin instance. If
methodName does not exist on the plugin or the plugin does not
exist, an error will occur.
Example plugin method calls:
// Execute the 'doStuff' method using the 'myplugin' plugin.
ga('create', 'UA-XXXXX-Y', 'auto');
ga('require', 'myplugin');
ga('myplugin:doStuff');
// Execute the 'setEnabled' method of the 'hitCopy' plugin on tracker 't3'.
ga('create', 'UA-XXXXX-Y', 'auto', {name: 't3'});
ga('t3.require', 'hitcopy');
ga('t3.hitcopy:setEnabled', false);
Example plugin method definitions:
// myplugin constructor.
var MyPlugin = function(tracker) {
};
// myplugin:doStuff method definition.
MyPlugin.prototype.doStuff = function() {
alert('doStuff method called!');
};
// hitcopy plugin.
var HitCopy = function(tracker) {
};
// hitcopy:setEnabled method definition.
HitCopy.prototype.setEnabled = function(isEnabled) {
this.isEnabled = isEnabled;
}:
Example
The following example plugin is designed to capture custom campaign values from a page's URL and pass them to the tracker. This plugin demonstrates how to define and register a plugin script, pass plugin configuration parameters, and define and call plugin methods.
campaign-loader.js
function providePlugin(pluginName, pluginConstructor) {
var ga = window[window['GoogleAnalyticsObject'] || 'ga'];
if (ga) ga('provide', pluginName, pluginConstructor);
}
/**
* Constructor for the campaignLoader plugin.
*/
var CampaignLoader = function(tracker, config) {
this.tracker = tracker;
this.nameParam = config.nameParam || 'name';
this.sourceParam = config.sourceParam || 'source';
this.mediumParam = config.mediumParam || 'medium';
this.isDebug = config.debug;
};
/**
* Loads campaign fields from the URL and updates the tracker.
*/
CampaignLoader.prototype.loadCampaignFields = function() {
this.debugMessage('Loading custom campaign parameters');
var nameValue = getUrlParam(this.nameParam);
if (nameValue) {
this.tracker.set('campaignName', nameValue);
this.debugMessage('Loaded campaign name: ' + nameValue);
}
var sourceValue = getUrlParam(this.sourceParam);
if (sourceValue) {
this.tracker.set('campaignSource', sourceValue);
this.debugMessage('Loaded campaign source: ' + sourceValue);
}
var mediumValue = getUrlParam(this.mediumParam);
if (mediumValue) {
this.tracker.set('campaignMedium', mediumValue);
this.debugMessage('Loaded campaign medium: ' + mediumValue);
}
};
/**
* Enables / disables debug output.
*/
CampaignLoader.prototype.setDebug = function(enabled) {
this.isDebug = enabled;
};
/**
* Displays a debug message in the console, if debugging is enabled.
*/
CampaignLoader.prototype.debugMessage = function(message) {
if (!this.isDebug) return;
if (console) console.debug(message);
};
/**
* Utility function to extract a URL parameter value.
*/
function getUrlParam(param) {
var match = document.location.search.match('(?:\\?|&)' + param + '=([^&#]*)');
return (match && match.length == 2) ? decodeURIComponent(match[1]) : '';
}
// Register the plugin.
providePlugin('campaignLoader', CampaignLoader);
index.html
<!DOCTYPE html>
<html>
<head>
<!-- Google Analytics Snippet-->
<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-XXXXX-Y', 'auto');
ga('require', 'campaignLoader', {
debug: true,
nameParam: 'cname',
sourceParam: 'csrc',
mediumParam: 'cmed'
});
ga('campaignLoader:loadCampaignFields');
ga('send', 'pageview');
</script>
<!-- Plugin Script (must be sourced after the analytics.js snippet) -->
<script async src="campaign-loader.js"></script>
</head>
...