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

Begin migration from classic to universal Google Analytics #549

Merged
merged 24 commits into from
Feb 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a5580a7
Create analytics trackers with common interface
fofr Feb 17, 2015
417e688
Shorten naming of trackers
fofr Feb 19, 2015
222edbd
Ensure that the GA queue exists for classic
fofr Feb 19, 2015
bf793cd
Set pixel density and http status code dimensions
fofr Feb 19, 2015
d2556c3
Shim next page parameters cookie into universal
fofr Feb 19, 2015
4f1710d
Remove analytics tracking code from template
fofr Feb 19, 2015
2d585d0
Intercept injected custom vars, send to universal
fofr Feb 19, 2015
fdd3d33
Initialise analytics tracker immediately
fofr Feb 19, 2015
cb35cb5
Include the non-interaction param in event call
fofr Feb 19, 2015
4660c13
Switch scroll tracking to use universal
fofr Feb 20, 2015
7b2be0d
Protect against ga function not being present
fofr Feb 20, 2015
7e6d9f2
Rename GOVUK.Analytics.tracker to GOVUK.analytics
fofr Feb 20, 2015
c6a5dde
Track satisfaction survey events in universal
fofr Feb 20, 2015
11d22ea
Delete unused sendToAnalytics method
fofr Feb 20, 2015
b359ad1
Avoid using poorly named `Analytics` namespace
fofr Feb 20, 2015
459087a
Track print intent and js errors in Universal
fofr Feb 20, 2015
b799a2e
Use document.domain as cookie domain for preview
fofr Feb 20, 2015
076debf
Include analytics sooner
fofr Feb 20, 2015
7fd17c6
Track browser-check in universal analytics
fofr Feb 20, 2015
47d1ff0
Use bind rather than `self = this`
fofr Feb 23, 2015
5a60c08
Remove cross domain tracking from universal
fofr Feb 23, 2015
df477da
Pass named options to trackEvent
fofr Feb 24, 2015
ff058c2
Use named arguments when creating tracker
fofr Feb 25, 2015
b18f3ca
Add helpers for setting dimensions
fofr Feb 25, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion app/assets/javascripts/analytics.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
//= require analytics/tracking
//= require analytics/google-analytics-universal-tracker
//= require analytics/google-analytics-classic-tracker
//= require analytics/tracker
//= require analytics/init

//= require analytics/print-tracking
//= require analytics/print-intent
//= require analytics/scroll-tracker
Expand Down
13 changes: 5 additions & 8 deletions app/assets/javascripts/analytics/error-tracking.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
"use strict";
var trackJavaScriptError = function (e) {
var errorSource = e.filename + ': ' + e.lineno;
_gaq.push([
'_trackEvent',
'JavaScript Error',
e.message,
errorSource,
1, // Set our value to 1, though we could look to tally session errors here
true // nonInteractive so bounce rate isn't affected
]);
GOVUK.analytics.trackEvent('JavaScript Error', e.message, {
label: errorSource,
value: 1,
nonInteraction: true
});
};

if (window.addEventListener) {
Expand Down
101 changes: 101 additions & 0 deletions app/assets/javascripts/analytics/google-analytics-classic-tracker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
(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/gaTrackingCustomVariables
GoogleAnalyticsClassicTracker.prototype.setCustomVariable = function(index, value, name, scope) {
_gaq.push(['_setCustomVar', index, name, String(value), scope]);
};

GOVUK.GoogleAnalyticsClassicTracker = GoogleAnalyticsClassicTracker;
})();
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
(function() {
"use strict";
window.GOVUK = window.GOVUK || {};

var GoogleAnalyticsUniversalTracker = function(id, cookieDomain) {
configureProfile(id, cookieDomain);
anonymizeIp();

function configureProfile(id, cookieDomain) {
sendToGa('create', id, {'cookieDomain': cookieDomain});
}

function anonymizeIp() {
// https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced#anonymizeip
sendToGa('set', 'anonymizeIp', true);
}
};

GoogleAnalyticsUniversalTracker.load = function() {
(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');
};

// https://developers.google.com/analytics/devguides/collection/analyticsjs/pages
GoogleAnalyticsUniversalTracker.prototype.trackPageview = function(path, title) {
if (typeof path === "string") {
var pageviewObject = {
page: path
};

if (typeof title === "string") {
pageviewObject.title = title;
}
sendToGa('send', 'pageview', pageviewObject);
} else {
sendToGa('send', 'pageview');
}
};

// https://developers.google.com/analytics/devguides/collection/analyticsjs/events
GoogleAnalyticsUniversalTracker.prototype.trackEvent = function(category, action, options) {
var value,
options = options || {},
evt = {
hitType: 'event',
eventCategory: category,
eventAction: action
};

// Label is optional
if (typeof options.label === "string") {
evt.eventLabel = 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)) {
evt.eventValue = value;
}
}

// Prevents an event from affecting bounce rate
// https://developers.google.com/analytics/devguides/collection/analyticsjs/events#implementation
if (options.nonInteraction) {
evt.nonInteraction = 1;
}

sendToGa('send', evt);
};

// https://developers.google.com/analytics/devguides/collection/analyticsjs/custom-dims-mets
GoogleAnalyticsUniversalTracker.prototype.setDimension = function(index, value) {
sendToGa('set', 'dimension' + index, String(value));
};

function sendToGa() {
if (typeof window.ga === "function") {
ga.apply(window, arguments);
}
}

GOVUK.GoogleAnalyticsUniversalTracker = GoogleAnalyticsUniversalTracker;
})();
20 changes: 20 additions & 0 deletions app/assets/javascripts/analytics/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
(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, setup custom vars, track initial pageview
var analytics = new GOVUK.Tracker({
universalId: 'UA-26179049-7',
classicId: 'UA-26179049-1',
cookieDomain: cookieDomain
});

// Make interface public for virtual pageviews and events
GOVUK.analytics = analytics;
})();
2 changes: 1 addition & 1 deletion app/assets/javascripts/analytics/print-intent.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

"use strict";
var printAttempt = (function() {
_gaq.push(['_trackEvent', 'Print Intent', document.location.pathname]);
GOVUK.analytics.trackEvent('Print Intent', document.location.pathname);
});

// Most browsers
Expand Down
17 changes: 9 additions & 8 deletions app/assets/javascripts/analytics/scroll-tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"use strict";

window.GOVUK = window.GOVUK || {};
window.GOVUK.Analytics = window.GOVUK.Analytics || {};

var CONFIG = {
'/': [
Expand Down Expand Up @@ -88,9 +87,11 @@
for ( var i=0; i<this.trackedNodes.length; i++ ) {
if ( this.trackedNodes[i].isVisible() && !this.trackedNodes[i].alreadySeen ) {
this.trackedNodes[i].alreadySeen = true;
GOVUK.sendToAnalytics(["_trackEvent"].concat(this.trackedNodes[i].eventData).concat([0, true]));
// Last 'true' sets non-interaction flag
// https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide#non-interaction

var action = this.trackedNodes[i].eventData.action,
label = this.trackedNodes[i].eventData.label;

GOVUK.analytics.trackEvent('ScrollTo', action, {label: label, nonInteraction: true});
}
}
};
Expand All @@ -99,7 +100,7 @@

ScrollTracker.PercentNode = function PercentNode(percentage) {
this.percentage = percentage;
this.eventData = ["ScrollTo", "Percent", String(percentage)];
this.eventData = {action: "Percent", label: String(percentage)};
};

ScrollTracker.PercentNode.prototype.isVisible = function isVisible() {
Expand All @@ -116,7 +117,7 @@

ScrollTracker.HeadingNode = function HeadingNode(headingText) {
this.$element = getHeadingElement(headingText);
this.eventData = ["ScrollTo", "Heading", headingText];
this.eventData = {action: "Heading", label: headingText};

function getHeadingElement(headingText) {
var $headings = $('h1, h2, h3, h4, h5, h6');
Expand All @@ -140,8 +141,8 @@


$().ready(function() {
window.GOVUK.Analytics.scrollTracker = new ScrollTracker(CONFIG);
window.GOVUK.scrollTracker = new ScrollTracker(CONFIG);
});

window.GOVUK.Analytics.ScrollTracker = ScrollTracker;
window.GOVUK.ScrollTracker = ScrollTracker;
}());
Loading