Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port analytics API from static #162

Merged
merged 8 commits into from Mar 10, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion Gruntfile.js
Expand Up @@ -30,10 +30,13 @@ module.exports = function(grunt) {
javascripts: {
src: [
'node_modules/jquery-browser/lib/jquery.js',
'javascripts/govuk/analytics/google-analytics-classic-tracker.js',
'javascripts/govuk/analytics/google-analytics-universal-tracker.js',
'javascripts/govuk/analytics/tracker.js',
'javascripts/**/*.js'
],
options: {
specs: 'spec/unit/*Spec.js',
specs: 'spec/unit/**/*Spec.js',
helpers: 'spec/unit/*Helper.js'
}
}
Expand Down
7 changes: 7 additions & 0 deletions README.md
Expand Up @@ -120,6 +120,13 @@ In production:
* [Primary links](/docs/javascript.md#primary-links)
* [Stick at top when scrolling](/docs/javascript.md#stick-at-top-when-scrolling)
* [Selection buttons](/docs/javascript.md#selection-buttons)
* [Analytics](/docs/analytics.md)
* [Create an analytics tracker](/docs/analytics.md#create-an-analytics-tracker)
* [Virtual pageviews](/docs/analytics.md#virtual-pageviews)
* [Custom events](/docs/analytics.md#custom-events)
* [Custom dimensions and custom variables](/docs/analytics.md#custom-dimensions-and-custom-variables)
* [Print tracking](/docs/analytics.md#print-tracking)
* [Error tracking](/docs/analytics.md#error-tracking)

## Licence

Expand Down
158 changes: 158 additions & 0 deletions docs/analytics.md
@@ -0,0 +1,158 @@
# Analytics

The toolkit provides an abstraction around analytics to make tracking pageviews, events and dimensions across multiple analytics providers easier. Specifically it was created to ease the migration from Google’s Classic Analytics to Universal Analytics. It includes:

* a Google Analytics classic tracker
* a Google Analytics universal tracker
* code to asynchronously load these libraries
* a generic Analytics tracker that combines these into a single API
* sensible defaults such as anonymising IPs
* data coercion into the format required by Google Analytics (eg a custom event value must be a number, a custom dimension’s value must be a string)

## Create an analytics tracker

The minimum you need to use the analytics function is:

1. Include the following files from /javascripts/govuk/analytics in your project:
* google-analytics-classic-tracker.js
* google-analytics-universal-tracker.js
* tracker.js
2. Copy the following `init` script into your own project and replace the dummy IDs with your own (they begin with `UA-`).
* This initialisation can occur immediately as this API has no dependencies.
* Load and create the analytics tracker at the earliest opportunity so that:
* the time until the first pageview is tracked is kept small and pageviews aren’t missed
* javascript that depends on `GOVUK.analytics` runs after the tracker has been created

```js
(function() {
"use strict";

// Load Google Analytics libraries
GOVUK.Tracker.load();

// Use document.domain in dev, preview and staging so that tracking works
// Otherwise explicitly set the domain as www.gov.uk (and not gov.uk).
var cookieDomain = (document.domain === 'www.gov.uk') ? '.www.gov.uk' : document.domain;

// Configure profiles and make interface public
// for custom dimensions, virtual pageviews and events
GOVUK.analytics = new GOVUK.Tracker({
universalId: 'UA-XXXXXXXX-X',
classicId: 'UA-XXXXXXXX-X',
cookieDomain: cookieDomain
});

// Set custom dimensions before tracking pageviews
// GOVUK.analytics.setDimension(…)

// Track initial pageview
GOVUK.analytics.trackPageview();
})();
```

Once instantiated, the `GOVUK.analytics` object can be used to track virtual pageviews, custom events and custom dimensions.

## Virtual pageviews

> Page tracking allows you to measure the number of views you had of a particular page on your web site.

* [Classic Analytics](https://developers.google.com/analytics/devguides/collection/gajs/asyncMigrationExamples#VirtualPageviews)
* [Universal Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/pages)

Argument | Description
---------|------------
`path` (optional) | Custom path, eg `/path`
`title` (optional) | Custom page title, Universal only


```js
// Track current page
GOVUK.analytics.trackPageview();

// Track a custom path
GOVUK.analytics.trackPageview('/path');

// Track a custom path and custom page title
GOVUK.analytics.trackPageview('/path', 'Title');
```

## Custom events

> Event tracking allows you to measure how users interact with the content of your website. For example, you might want to measure how many times a button was pressed, or how many times a particular item was used.

* [Classic Analytics](https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide)
* [Universal Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/events)

Argument | Description
---------|------------
`category` (required) | Typically the object that was interacted with, eg "JavaScript error"
`action` (required) | The type of interaction, eg a Javascript error message
`options` (optional) | Optional parameters to further describe event

Option | Description
-------|------------
`label` | Useful for categorising events, eg Javascript error source
`value` | Values must be non-negative. Useful to pass counts, eg error happened 5 times
`nonInteraction` | Defaults to false. When set the event will not affect bounce rate

```js
// Track a custom event with required category and action fields
GOVUK.analytics.trackEvent('category', 'action');

// Track a custom event with optional label, value and nonInteraction options
GOVUK.analytics.trackEvent('category', 'action', {
label: 'label',
value: 1,
nonInteraction: true // event will not affect bounce rate
});
```

## Custom dimensions and custom variables

> Custom dimensions and metrics are a powerful way to send custom data to Google Analytics. Use custom dimensions and metrics to segment and measure differences between: logged in and logged out users, authors of pages, or any other business data you have on a page.

* [Classic Analytics](https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingCustomVariables)
* [Universal Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/custom-dims-mets)

Universal custom dimensions are configured within analytics. Classic custom variables rely on the javascript to additionally pass in the name and scope of the variable.

### Set custom dimensions before tracking pageviews

Many page level custom dimensions must be set before the initial pageview is tracked. Calls to `setDimension` should typically be made before the initial `trackPageview` is sent to analytics.

### Custom dimensions and variables must have matching indexes

When calling `setDimension`, the first argument (`index`) becomes the index of the Universal custom dimension as well as the slot of the Classic custom variable.

Argument | Description
---------|------------
`index` (required) | The Universal dimension’s index and and Classic variable’s slot. These must be configured to the same slot and index within analytics profiles.
`value` (required) | Value of the custom dimension/variable
`name` (required) | The name of the custom variable (classic only)
`scope` (optional) | The scope of the custom variable (classic only), defaults to a [page level scope](https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingCustomVariables#pagelevel) (3) if omitted

```js
// Set a custom dimension at index 1 with value and name
GOVUK.analytics.setDimension(1, 'value', 'name');

// Set a custom dimension with an alternative scope
GOVUK.analytics.setDimension(1, 'value', 'name', 2);
```

### Create custom dimension helpers

Because dimensions and variables rely on names and indexes being set correctly, it’s helpful to create methods that abstract away the details. For example:

```js
function setPixelDensityDimension(pixelDensity) {
GOVUK.analytics.setDimension(1, pixelDensity, 'PixelDensity', 2);
}
```

## Print tracking

Pull `print-intent.js` into your project, after analytics has been initialised, to track when users are attempting to print content.

## Error tracking

Pull `error-tracking.js` into your project, after analytics has been initialised, to track JavaScript errors.
22 changes: 22 additions & 0 deletions javascripts/govuk/analytics/error-tracking.js
@@ -0,0 +1,22 @@
// Extension to track errors using google analytics as a data store.
(function() {

"use strict";
var trackJavaScriptError = function (e) {
var errorSource = e.filename + ': ' + e.lineno;
GOVUK.analytics.trackEvent('JavaScript Error', e.message, {
label: errorSource,
value: 1,
nonInteraction: true
});
};

if (window.addEventListener) {
window.addEventListener('error', trackJavaScriptError, false);
} else if (window.attachEvent) {
window.attachEvent('onerror', trackJavaScriptError);
} else {
window.onerror = trackJavaScriptError;
}

}());
111 changes: 111 additions & 0 deletions javascripts/govuk/analytics/google-analytics-classic-tracker.js
@@ -0,0 +1,111 @@
(function() {
"use strict";
window.GOVUK = window.GOVUK || {};

var GoogleAnalyticsClassicTracker = function(id, cookieDomain) {
window._gaq = window._gaq || [];
configureProfile(id, cookieDomain);
allowCrossDomainTracking();
anonymizeIp();

function configureProfile(id, cookieDomain) {
_gaq.push(['_setAccount', id]);
_gaq.push(['_setDomainName', cookieDomain]);
}

function allowCrossDomainTracking() {
_gaq.push(['_setAllowLinker', true]);
}

// https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApi_gat#_gat._anonymizeIp
function anonymizeIp() {
_gaq.push(['_gat._anonymizeIp']);
}
};

GoogleAnalyticsClassicTracker.load = function() {
var ga = document.createElement('script'),
s = document.getElementsByTagName('script')[0];

ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
s.parentNode.insertBefore(ga, s);
};

// https://developers.google.com/analytics/devguides/collection/gajs/asyncMigrationExamples#VirtualPageviews
GoogleAnalyticsClassicTracker.prototype.trackPageview = function(path) {
var pageview = ['_trackPageview'];

if (typeof path === "string") {
pageview.push(path);
}

_gaq.push(pageview);
};

// https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide
GoogleAnalyticsClassicTracker.prototype.trackEvent = function(category, action, options) {
var value,
options = options || {},
hasLabel = false,
hasValue = false,
evt = ["_trackEvent", category, action];

// Label is optional
if (typeof options.label === "string") {
hasLabel = true;
evt.push(options.label);
}

// Value is optional, but when used must be an
// integer, otherwise the event will be invalid
// and not logged
if (options.value || options.value === 0) {
value = parseInt(options.value, 10);
if (typeof value === "number" && !isNaN(value)) {
hasValue = true;

// Push an empty label if not set for correct final argument order
if (!hasLabel) {
evt.push('');
}

evt.push(value);
}
}

// Prevents an event from affecting bounce rate
// https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide#non-interaction
if (options.nonInteraction) {

// Push empty label/value if not already set, for correct final argument order
if (!hasValue) {
if (!hasLabel) {
evt.push('');
}
evt.push(0);
}

evt.push(true);
}

_gaq.push(evt);
};

/*
https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApiSocialTracking
network – The network on which the action occurs (e.g. Facebook, Twitter)
action – The type of action that happens (e.g. Like, Send, Tweet)
target – The text value that indicates the subject of the action
*/
GoogleAnalyticsClassicTracker.prototype.trackSocial = function(network, action, target) {
_gaq.push(['_trackSocial', network, action, target]);
};

// https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingCustomVariables
GoogleAnalyticsClassicTracker.prototype.setCustomVariable = function(index, value, name, scope) {
_gaq.push(['_setCustomVar', index, name, String(value), scope]);
};

GOVUK.GoogleAnalyticsClassicTracker = GoogleAnalyticsClassicTracker;
})();