;(function (global) { 'use strict' var GOVUK = global.GOVUK || {} var EMAIL_PATTERN = /[^\s=/?&]+(?:@|%40)[^\s=/?&]+/g var POSTCODE_PATTERN = /[A-PR-UWYZ][A-HJ-Z]?[0-9][0-9A-HJKMNPR-Y]?(?:[\s+]|%20)*[0-9][ABD-HJLNPQ-Z]{2}/gi // For usage and initialisation see: // https://github.com/alphagov/govuk_frontend_toolkit/blob/master/docs/analytics.md#create-an-analytics-tracker var Analytics = function (config) { this.stripPostcodePII = false if (typeof config.stripPostcodePII !== 'undefined') { this.stripPostcodePII = (config.stripPostcodePII === true) // remove the option so we don't pass it to other trackers - it's not // their concern delete config.stripPostcodePII } this.trackers = [] if (typeof config.universalId !== 'undefined') { var universalId = config.universalId delete config.universalId this.trackers.push(new GOVUK.GoogleAnalyticsUniversalTracker(universalId, config)) } if (typeof config.govukTrackerUrl !== 'undefined') { var govukTrackerUrl = config.govukTrackerUrl delete config.govukTrackerUrl this.trackers.push(new GOVUK.GOVUKTracker(govukTrackerUrl)) } } var PIISafe = function (value) { this.value = value } Analytics.PIISafe = PIISafe Analytics.prototype.stripPII = function (value) { if (typeof value === 'string') { return this.stripPIIFromString(value) } else if (Object.prototype.toString.call(value) === '[object Array]' || Object.prototype.toString.call(value) === '[object Arguments]') { return this.stripPIIFromArray(value) } else if (typeof value === 'object') { return this.stripPIIFromObject(value) } else { return value } } Analytics.prototype.stripPIIFromString = function (string) { var emailStripped = string.replace(EMAIL_PATTERN, '[email]') if (this.stripPostcodePII === true) { return emailStripped.replace(POSTCODE_PATTERN, '[postcode]') } else { return emailStripped } } Analytics.prototype.stripPIIFromObject = function (object) { if (object instanceof Analytics.PIISafe) { return object.value } else { for (var property in object) { var value = object[property] object[property] = this.stripPII(value) } return object } } Analytics.prototype.stripPIIFromArray = function (array) { for (var i = 0, l = array.length; i < l; i++) { var elem = array[i] array[i] = this.stripPII(elem) } return array } Analytics.prototype.sendToTrackers = function (method, args) { for (var i = 0, l = this.trackers.length; i < l; i++) { var tracker = this.trackers[i] var fn = tracker[method] if (typeof fn === 'function') { fn.apply(tracker, args) } } } Analytics.load = function () { GOVUK.GoogleAnalyticsUniversalTracker.load() GOVUK.GOVUKTracker.load() } Analytics.prototype.defaultPathForTrackPageview = function (location) { // Get the page path including querystring, but ignoring the anchor // as per default behaviour of GA (see: https://developers.google.com/analytics/devguides/collection/analyticsjs/pages#overview) // we ignore the possibility of there being campaign variables in the // anchor because we wouldn't know how to detect and parse them if they // were present return this.stripPIIFromString(location.href.substring(location.origin.length).split('#')[0]) } Analytics.prototype.trackPageview = function (path, title, options) { arguments[0] = arguments[0] || this.defaultPathForTrackPageview(window.location) if (arguments.length === 0) { arguments.length = 1 } this.sendToTrackers('trackPageview', this.stripPII(arguments)) } /* https://developers.google.com/analytics/devguides/collection/analyticsjs/events options.label – Useful for categorizing events (eg nav buttons) options.value – Values must be non-negative. Useful to pass counts options.nonInteraction – Prevent event from impacting bounce rate */ Analytics.prototype.trackEvent = function (category, action, options) { this.sendToTrackers('trackEvent', this.stripPII(arguments)) } Analytics.prototype.trackShare = function (network, options) { this.sendToTrackers('trackSocial', this.stripPII([network, 'share', global.location.pathname, options])) } /* The custom dimension index must be configured within the Universal Analytics profile */ Analytics.prototype.setDimension = function (index, value) { this.sendToTrackers('setDimension', this.stripPII(arguments)) } /* Add a beacon to track a page in another GA account on another domain. */ Analytics.prototype.addLinkedTrackerDomain = function (trackerId, name, domain) { this.sendToTrackers('addLinkedTrackerDomain', arguments) } GOVUK.Analytics = Analytics global.GOVUK = GOVUK })(window)