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

Ensure analytics stops firing if a user disables usage cookies on our cookie settings page #3893

Merged
merged 1 commit into from
Mar 4, 2024
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
useful summary for people upgrading their application, not a replication
of the commit log.

## Unreleased

* Ensure analytics stops firing if a user disables usage cookies on our cookie settings page ([PR #3893](https://github.com/alphagov/govuk_publishing_components/pull/3893))

## 37.5.1

* Remove GA4 callout tracking from govspeak component ([PR #3889](https://github.com/alphagov/govuk_publishing_components/pull/3889))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {};
},

sendData: function (data) {
// Allows us to stop sending tracking at the moment a user sets their usage cookies to "false" on the cookie settings page.
if (window.GOVUK.stopSendingAnalytics) {
return false
}

data.govuk_gem_version = this.getGemVersion()
data.timestamp = this.getTimestamp()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
Analytics.PIISafe = PIISafe

Analytics.prototype.sendToTrackers = function (method, args) {
// Allows us to stop sending tracking at the moment a user sets their usage cookies to "false" on the cookie settings page.
if (window.GOVUK.stopSendingAnalytics) {
return false
}

for (var i = 0, l = this.trackers.length; i < l; i++) {
var tracker = this.trackers[i]
var fn = tracker[method]
Expand Down Expand Up @@ -49,7 +54,7 @@
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.pii.stripPII(arguments))
return this.sendToTrackers('trackPageview', this.pii.stripPII(arguments))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andysellick sendToTrackers isn't a public function, so I can't access it in the tests. Therefore I return the value of it in the functions that are publicly accessible trackPageview / trackEvent / trackShare so that I can verify in the tests that analytics is disabled.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to check, this doesn't impact the outcome? As in, does returning this.sendToTracker instead of executing it still call that function?

Copy link
Contributor Author

@AshGDS AshGDS Mar 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andysellick It's still being executed, the result of the execution is what is returned. If it didn't have ('trackPageview', this.pii.stripPII(arguments)) on the function, then the function would be being returned instead of executed.

Example here if you want to play around with it: https://jsfiddle.net/spLfjez5/2/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, no worries, just wanted to be sure 👍

}

/*
Expand All @@ -59,26 +64,26 @@
options.nonInteraction – Prevent event from impacting bounce rate
*/
Analytics.prototype.trackEvent = function (category, action, options) {
this.sendToTrackers('trackEvent', this.pii.stripPII(arguments))
return this.sendToTrackers('trackEvent', this.pii.stripPII(arguments))
}

Analytics.prototype.trackShare = function (network, options) {
this.sendToTrackers('trackSocial', this.pii.stripPII([network, 'share', global.location.pathname, options]))
return this.sendToTrackers('trackSocial', this.pii.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.pii.stripPII(arguments))
return this.sendToTrackers('setDimension', this.pii.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)
return this.sendToTrackers('addLinkedTrackerDomain', arguments)
}

GOVUK.Analytics = Analytics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
var value = input.value === 'on'

options[name] = value

if (name === 'usage' && !value) {
window.GOVUK.stopSendingAnalytics = true
window.GOVUK.LUX = {}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ describe('GA4 core', function () {
})
})

it('does not push data to the dataLayer if window.GOVUK.stopSendingAnalytics is true', function () {
window.GOVUK.stopSendingAnalytics = true
GOVUK.analyticsGa4.core.sendData({})
expect(window.dataLayer[0]).toEqual(undefined)
expect(GOVUK.analyticsGa4.core.sendData()).toEqual(false)
})

describe('query strings allow pushing to a fake dataLayer', function () {
var data

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,22 @@ describe('GOVUK.Analytics', function () {
expect(allArgs).toContain(['test3.send', 'pageview'])
})
})

describe('when window.GOVUK.stopSendingAnalytics is true', function () {
beforeEach(function () {
window.GOVUK.stopSendingAnalytics = true
})

it('disables pageview tracking', function () {
expect(analytics.trackPageview()).toEqual(false)
})

it('disables share tracking', function () {
expect(analytics.trackShare()).toEqual(false)
})

it('disables event tracking', function () {
expect(analytics.trackShare()).toEqual(false)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ describe('cookieSettings', function () {
'<form data-module="cookie-settings">' +
'<input type="radio" id="settings-on" name="cookies-settings" value="on">' +
'<input type="radio" id="settings-off" name="cookies-settings" value="off">' +
'<input type="radio" name="cookies-usage" value="on">' +
'<input type="radio" name="cookies-usage" value="off">' +
'<input type="radio" id="usage-on" name="cookies-usage" value="on">' +
'<input type="radio" id="usage-off" name="cookies-usage" value="off">' +
'<input type="radio" name="cookies-campaigns" value="on">' +
'<input type="radio" name="cookies-campaigns" value="off">' +
'<button id="submit-button" type="submit">Submit</button>' +
Expand Down Expand Up @@ -136,10 +136,13 @@ describe('cookieSettings', function () {
element.querySelector('#settings-on').checked = false
element.querySelector('#settings-off').checked = true

element.querySelector('#usage-on').checked = true
element.querySelector('#usage-off').checked = false

var button = element.querySelector('#submit-button')
button.click()

expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith('cookieSettings', 'Save changes', { label: 'settings-no usage-no campaigns-no ' })
expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith('cookieSettings', 'Save changes', { label: 'settings-no usage-yes campaigns-no ' })
})
})

Expand Down Expand Up @@ -195,4 +198,43 @@ describe('cookieSettings', function () {
expect(confirmationMessage.style.display).toEqual('block')
})
})

describe('when setting usage cookies to false', function () {
beforeEach(function () {
spyOn(GOVUK.analyticsGa4.core, 'getGemVersion').and.returnValue('aVersion')
})
it('stops analytics tracking', function () {
var analytics = new GOVUK.Analytics({
universalId: 'universal-id',
cookieDomain: '.www.gov.uk',
siteSpeedSampleRate: 100
})
window.dataLayer = []

// Expect the default return value when you send an analytics event
expect(analytics.trackEvent()).toEqual(undefined)
expect(analytics.trackShare()).toEqual(undefined)
expect(analytics.trackPageview()).toEqual(undefined)
expect(GOVUK.analyticsGa4.core.sendData({})).toEqual(undefined)

new GOVUK.Modules.CookieSettings(element).init()

element.querySelector('#usage-on').checked = false
element.querySelector('#usage-off').checked = true

var button = element.querySelector('#submit-button')
button.click()

expect(window.GOVUK.stopSendingAnalytics).toEqual(true)

// Expect a false return value now when you send an analytics event

expect(analytics.trackEvent()).toEqual(false)
expect(analytics.trackShare()).toEqual(false)
expect(analytics.trackPageview()).toEqual(false)
expect(window.GOVUK.analyticsGa4.core.sendData()).toEqual(false)

expect(window.GOVUK.LUX).toEqual({})
})
})
})
1 change: 1 addition & 0 deletions spec/javascripts/helpers/SpecHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ beforeEach(function () {

// load-analytics.js modifies the universal analytics vars, so we need to ensure they are reset each time.
savedUaVars = window.GOVUK.extendObject(window.GOVUK.analyticsVars)
window.GOVUK.stopSendingAnalytics = false
})

afterEach(function () {
Expand Down