Skip to content

Commit

Permalink
Merge pull request #3905 from alphagov/ga4-fix-callout-tracking
Browse files Browse the repository at this point in the history
Reintroduce GA4 callout tracking and fix link tracker compatibility
  • Loading branch information
AshGDS authored Mar 11, 2024
2 parents 65d9214 + cee3305 commit 5da37a7
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 9 deletions.
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

* Reintroduce GA4 callout tracking and fix link tracker compatibility ([PR #3905](https://github.com/alphagov/govuk_publishing_components/pull/3905))

## 37.6.1

* Include single consent api package ([PR #3908](https://github.com/alphagov/govuk_publishing_components/pull/3908))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,33 @@ window.GOVUK.analyticsGa4.analyticsModules = window.GOVUK.analyticsGa4.analytics
return
}

// don't track this link if it's already being tracked by the another tracker (e.g. the link tracker or ecommerce tracker)
if (element.closest('[data-ga4-link]') || element.closest('[data-ga4-ecommerce-path]')) {
// Don't track this link if it's already being tracked by the ecommerce tracker
if (element.closest('[data-ga4-ecommerce-path]')) {
return
}

// Code below ensures the tracker plays nicely with the other link tracker
var otherLinkTracker = element.closest('[data-ga4-link]')
if (otherLinkTracker) {
var limitToElementClass = otherLinkTracker.getAttribute('data-ga4-limit-to-element-class')

if (!limitToElementClass) {
// If this link is inside the other link tracker, and the other link tracker IS NOT limiting itself to specific classes,
// then stop this tracker from firing, as the other tracker is responsible for this link.
return
} else {
// If this link is inside the other link tracker, but the other link tracker IS limiting itself to specific classes,
// then track the link here only if it is not within the specified classes that the other tracker is looking for.
var classes = limitToElementClass.split(',')

for (var i = 0; i < classes.length; i++) {
if (element.closest('.' + classes[i].trim())) {
return
}
}
}
}

var href = element.getAttribute('href')

if (!href) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,20 @@
classes << "disable-youtube" if disable_youtube_expansions
classes << "gem-c-govspeak--inverse" if inverse

disable_ga4 ||= false

data_modules = "govspeak"
data_modules << " ga4-link-tracker" unless disable_ga4
data_attributes = { module: data_modules }

unless disable_ga4
data_attributes.merge!({
ga4_track_links_only: "",
ga4_limit_to_element_class: "call-to-action, info-notice, help-notice, advisory",
ga4_link: { "event_name": "navigation", "type": "callout" }.to_json,
})
end

%>
<%= tag.div(class: "gem-c-govspeak govuk-govspeak " + classes.join(" "), data: data_attributes) do %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -914,3 +914,12 @@ examples:
<p>Deforested area. Credit: Blue Ventures-Garth Cripps</p>
</figcaption>
</figure>
without_ga4_tracking:
description: |
Disables GA4 tracking on the component. Tracking is enabled by default. This adds a data module and data-attributes with JSON data. See the [ga4-link-tracker documentation](https://github.com/alphagov/govuk_publishing_components/blob/main/docs/analytics-ga4/ga4-link-tracker.md) for more information.
data:
block: |
<p>
<a href='https://www.gov.uk'>Hello World</a>
</p>
disable_ga4: true
23 changes: 23 additions & 0 deletions spec/components/govspeak_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,27 @@ def component_name

expect(rendered).to include("content-via-block")
end

it "adds GA4 tracking" do
render_component(
content: "<h1>content</h1>".html_safe,
)

assert_select ".gem-c-govspeak[data-module='govspeak ga4-link-tracker']"
assert_select ".gem-c-govspeak[data-ga4-track-links-only]"
assert_select ".gem-c-govspeak[data-ga4-limit-to-element-class='call-to-action, info-notice, help-notice, advisory']"
assert_select '.gem-c-govspeak[data-ga4-link="{\"event_name\":\"navigation\",\"type\":\"callout\"}"]'
end

it "can disable GA4 tracking" do
render_component(
content: "<h1>content</h1>".html_safe,
disable_ga4: true,
)

assert_no_selector ".gem-c-govspeak[data-module='govspeak ga4-link-tracker']"
assert_no_selector ".gem-c-govspeak[data-ga4-track-links-only]"
assert_no_selector ".gem-c-govspeak[data-ga4-limit-to-element-class]"
assert_no_selector ".gem-c-govspeak[data-ga4-link]"
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ describe('A specialist link tracker', function () {
afterEach(function () {
body.removeEventListener('click', preventDefault)
links.remove()
linkTracker.stopTracking()
})

it('detects external click events on well structured external links', function () {
Expand Down Expand Up @@ -357,7 +356,6 @@ describe('A specialist link tracker', function () {
afterEach(function () {
body.removeEventListener('click', preventDefault)
links.remove()
linkTracker.stopTracking()
})

it('detects download clicks on fully structured gov.uk download links', function () {
Expand Down Expand Up @@ -543,7 +541,6 @@ describe('A specialist link tracker', function () {
afterEach(function () {
body.removeEventListener('click', preventDefault)
links.remove()
linkTracker.stopTracking()
})

it('detects email events on mailto links', function () {
Expand Down Expand Up @@ -584,7 +581,6 @@ describe('A specialist link tracker', function () {
afterEach(function () {
body.removeEventListener('click', preventDefault)
links.remove()
linkTracker.stopTracking()
})

it('removes _ga and _gl from href query parameters', function () {
Expand Down Expand Up @@ -660,7 +656,6 @@ describe('A specialist link tracker', function () {
afterEach(function () {
body.removeEventListener('click', preventDefault)
links.remove()
linkTracker.stopTracking()
})

it('redacts postcodes and dates from the URL', function () {
Expand Down Expand Up @@ -702,7 +697,6 @@ describe('A specialist link tracker', function () {
afterEach(function () {
body.removeEventListener('click', preventDefault)
links.remove()
linkTracker.stopTracking()
})

it('sets the text property to image', function () {
Expand All @@ -715,4 +709,78 @@ describe('A specialist link tracker', function () {
}
})
})

describe('when data-ga4-link and data-ga4-limit-to-element-class are on the parent', function () {
var specialistLinkTracker

beforeEach(function () {
window.dataLayer = []
links = document.createElement('div')
links.setAttribute('data-module', 'ga4-link-tracker')
links.setAttribute('data-ga4-track-links-only', '')
links.setAttribute('data-ga4-limit-to-element-class', 'hello')
links.setAttribute('data-ga4-link', JSON.stringify({ event_name: 'navigation', type: 'callout' }))

links.innerHTML =
'<div class="hello">' +
'<a class="otherLink" href="https://example.com">GA4 Link Tracker</a>' +
'</div>' +
'<a class="specialistLink" href="https://example.co.uk">Specialist Link Tracker</a>'

body.appendChild(links)
body.addEventListener('click', preventDefault)

GOVUK.setCookie('cookies_policy', '{"essential":true,"settings":true,"usage":true,"campaigns":true}')

var otherLinkTracker = new GOVUK.Modules.Ga4LinkTracker(links)
otherLinkTracker.init()

specialistLinkTracker = GOVUK.analyticsGa4.analyticsModules.Ga4SpecialistLinkTracker
specialistLinkTracker.init()
})

afterEach(function () {
GOVUK.cookie('cookies_policy', null)
body.removeEventListener('click', preventDefault)
links.remove()
})

it('does not fire the specialist tracker if the link should be tracked by the other link tracker', function () {
var otherLink = document.querySelector('.otherLink')
otherLink.click()

expected = new GOVUK.analyticsGa4.Schemas().eventSchema()
expected.event = 'event_data'
expected.event_data.event_name = 'navigation'
expected.event_data.type = 'callout'
expected.event_data.method = 'primary click'
expected.event_data.external = 'true'
expected.govuk_gem_version = 'aVersion'
expected.event_data.url = 'https://example.com'
expected.event_data.text = 'GA4 Link Tracker'
expected.event_data.link_domain = 'https://example.com'
expected.timestamp = '123456'
expect(window.dataLayer[0]).toEqual(expected)
expect(window.dataLayer.length).toEqual(1)
})

it('still fires the specialist tracker if the link is within the other tracker, but outside the classes it is looking for', function () {
var specialistLink = document.querySelector('.specialistLink')
specialistLink.click()

expected = new GOVUK.analyticsGa4.Schemas().eventSchema()
expected.event = 'event_data'
expected.event_data.event_name = 'navigation'
expected.event_data.type = 'generic link'
expected.event_data.method = 'primary click'
expected.event_data.external = 'true'
expected.govuk_gem_version = 'aVersion'
expected.event_data.url = 'https://example.co.uk'
expected.event_data.text = 'Specialist Link Tracker'
expected.event_data.link_domain = 'https://example.co.uk'
expected.timestamp = '123456'
expect(window.dataLayer[0]).toEqual(expected)
expect(window.dataLayer.length).toEqual(1)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ describe('Initialising GA4', function () {
var GOVUK = window.GOVUK

afterEach(function () {
GOVUK.analyticsGa4.analyticsModules.Ga4SpecialistLinkTracker.stopTracking()
window.dataLayer = []
window.removeEventListener('cookie-consent', window.GOVUK.analyticsGa4.init)
})
Expand Down
1 change: 1 addition & 0 deletions spec/javascripts/helpers/SpecHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ beforeEach(function () {
})

afterEach(function () {
GOVUK.analyticsGa4.analyticsModules.Ga4SpecialistLinkTracker.stopTracking()
resetCookies()
window.GOVUK.analyticsVars = savedUaVars
})

0 comments on commit 5da37a7

Please sign in to comment.