Skip to content

Commit fc1e50e

Browse files
committed
Implement Segment TrustArc wrapper and add listeners for consent
1 parent b82486a commit fc1e50e

File tree

5 files changed

+212
-41
lines changed

5 files changed

+212
-41
lines changed

src/js/04-segment-analytics.js

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,83 @@
11
;(function () {
22
'use strict'
33

4+
// Get common properties from digitalData
5+
const getCommonProperties = () => {
6+
return window.digitalData?.page?.pageInfo?.segment?.commonProperties || {}
7+
}
8+
9+
/**
10+
* Track events with IBM Segment Common Schema
11+
* @param {string} name - Event name (e.g., "CTA Clicked", "UI Interaction")
12+
* @param {object} payload - Event properties
13+
*/
414
const trackEvent = (name, payload) => {
515
if (window.analytics) {
6-
window.analytics.track(name, payload || {})
16+
// Merge common properties with event-specific properties
17+
const eventProperties = {
18+
...getCommonProperties(),
19+
...(payload || {})
20+
}
21+
window.analytics.track(name, eventProperties)
722
}
823
}
924

25+
/**
26+
* Track link clicks with IBM Segment Common Schema
27+
* @param {HTMLElement} element - The link element
28+
* @param {string} name - Event name
29+
* @param {object} payload - Event properties
30+
*/
1031
const trackLinkEvent = (element, name, payload) => {
1132
if (window.analytics) {
12-
window.analytics.trackLink(element, name, payload || {})
33+
const eventProperties = {
34+
...getCommonProperties(),
35+
...(payload || {})
36+
}
37+
window.analytics.trackLink(element, name, eventProperties)
1338
}
1439
}
1540

16-
// Add click event listeners to all elements with a data-track attribute.
17-
if (window.analytics) {
41+
/**
42+
* Initialize data-attribute tracking for declarative analytics
43+
* Supports both legacy data-track and new IBM schema patterns
44+
*/
45+
const initDataAttributeTracking = () => {
46+
// Handle data-event attributes (IBM Schema pattern)
47+
const handleClick = (event) => {
48+
const target = event.target
49+
const trackingElement = target.closest('[data-event]')
50+
51+
if (!trackingElement) return
52+
53+
const eventName = trackingElement.dataset.event
54+
if (!eventName) return
55+
56+
const properties = {}
57+
58+
// Extract all data attributes and map to event properties
59+
Object.keys(trackingElement.dataset).forEach((key) => {
60+
if (key !== 'event') {
61+
// Map to IBM Segment property names (preserve exact casing per schema)
62+
let propertyKey = key
63+
64+
// Handle special IBM property mappings
65+
if (key === 'cta') propertyKey = 'CTA'
66+
else if (key === 'elementId') propertyKey = 'elementId'
67+
else if (key === 'topLevel') propertyKey = 'topLevel'
68+
else if (key === 'subLevel') propertyKey = 'subLevel'
69+
70+
properties[propertyKey] = trackingElement.dataset[key]
71+
}
72+
})
73+
74+
trackEvent(eventName, properties)
75+
}
76+
77+
document.removeEventListener('click', handleClick)
78+
document.addEventListener('click', handleClick)
79+
80+
// Legacy data-track support for backwards compatibility
1881
const trackedLinkElements = document.querySelectorAll('a[data-track]')
1982
const trackedElements = document.querySelectorAll('[data-track]:not(a)')
2083

@@ -29,7 +92,14 @@
2992
})
3093
}
3194

32-
// Expose trackEvent and trackLinkEvent to the global scope.
95+
// Initialize tracking when DOM is ready
96+
if (document.readyState === 'loading') {
97+
document.addEventListener('DOMContentLoaded', initDataAttributeTracking)
98+
} else {
99+
initDataAttributeTracking()
100+
}
101+
102+
// Expose functions to the global scope
33103
window.trackEvent = trackEvent
34104
window.trackLinkEvent = trackLinkEvent
35105
})()

src/js/10-trustarc-consent.js

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/partials/footer.hbs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@
2424
target="_blank"
2525
data-track="Footer Terms of Use Link Clicked"
2626
>Terms of use</a>
27-
{{#with site.keys.ketchSmartTagUrl}}
27+
{{#with site.keys.ibmAnalyticsEnabled}}
2828
<span id="preferenceCenterContainer">
2929
|
3030
<a
3131
id="preferenceCenterLink"
32-
href="https://www.datastax.com/preferences?redirect_to={{{../site.url}}}{{{../page.url}}}"
32+
href="#"
33+
onclick="event.preventDefault(); if (typeof window.truste !== 'undefined' && window.truste.eu && window.truste.eu.clickListener) { window.truste.eu.clickListener(); }"
3334
data-track="Footer Consent Preference Link Clicked"
3435
>Manage Privacy Choices</a>
3536
</span>
@@ -93,4 +94,4 @@
9394
9495
</p>
9596
</div>
96-
</footer>
97+
</footer>

src/partials/head-scripts.hbs

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,111 @@
11
{{#with site.keys.segment}}
22
<script>
3-
!function(){var i="analytics",analytics=window[i]=window[i]||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","screen","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware","register"];analytics.factory=function(e){return function(){if(window[i].initialized)return window[i][e].apply(window[i],arguments);var n=Array.prototype.slice.call(arguments);if(["track","screen","alias","group","page","identify"].indexOf(e)>-1){var c=document.querySelector("link[rel='canonical']");n.push({__t:"bpc",c:c&&c.getAttribute("href")||void 0,p:location.pathname,u:location.href,s:location.search,t:document.title,r:document.referrer})}n.unshift(e);analytics.push(n);return analytics}};for(var n=0;n<analytics.methods.length;n++){var key=analytics.methods[n];analytics[key]=analytics.factory(key)}analytics.load=function(key,n){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.setAttribute("data-global-segment-analytics-key",i);t.src="https://cdn.segment.com/analytics.js/v1/" + key + "/analytics.min.js";var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r);analytics._loadOptions=n};analytics._writeKey="{{this}}";;analytics.SNIPPET_VERSION="5.2.1";
4-
analytics.load("{{this}}");
5-
}}();
3+
!function(){var i="analytics",analytics=window[i]=window[i]||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","screen","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware","register"];analytics.factory=function(e){return function(){if(window[i].initialized)return window[i][e].apply(window[i],arguments);var n=Array.prototype.slice.call(arguments);if(["track","screen","alias","group","page","identify"].indexOf(e)>-1){var c=document.querySelector("link[rel='canonical']");n.push({__t:"bpc",c:c&&c.getAttribute("href")||void 0,p:location.pathname,u:location.href,s:location.search,t:document.title,r:document.referrer})}n.unshift(e);analytics.push(n);return analytics}};for(var n=0;n<analytics.methods.length;n++){var key=analytics.methods[n];analytics[key]=analytics.factory(key)}analytics.load=function(key,n){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.setAttribute("data-global-segment-analytics-key",i);t.src="https://cdn.segment.com/analytics.js/v1/" + key + "/analytics.min.js";var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r);analytics._loadOptions=n};analytics._writeKey="{{this}}";;analytics.SNIPPET_VERSION="5.2.1";}}();
4+
</script>
5+
<script src="https://consent.trustarc.com/get?name=trustarc-segment-wrapper-v1.1.js" async></script>
6+
<script>
7+
(function() {
8+
function initSegmentWithTrustArc() {
9+
if (typeof TrustArcWrapper !== 'undefined' && window.analytics) {
10+
TrustArcWrapper.withTrustArc(window.analytics).load('{{this}}');
11+
} else {
12+
setTimeout(initSegmentWithTrustArc, 100);
13+
}
14+
}
15+
initSegmentWithTrustArc();
16+
})();
617
</script>
718
{{/with}}
819

920
{{#with site.keys.ibmAnalyticsEnabled}}
21+
<script>
22+
/* eslint-disable */
23+
// IBM Segment Common Properties - Required for all events
24+
const SEGMENT_COMMON_PROPERTIES = {
25+
productTitle: '<ADD>',
26+
productCode: '<ADD>',
27+
productCodeType: '<ADD>',
28+
ut30: '<ADD>'
29+
};
30+
31+
// IBM Analytics Configuration
32+
window._ibmAnalytics = {
33+
"settings": {
34+
"name": "DataStax",
35+
"tealiumProfileName": "ibm-subsidiary",
36+
},
37+
"trustarc": {
38+
"privacyPolicyLink": "https://ibm.com/privacy"
39+
},
40+
"digitalData.page.services.google.enabled": true
41+
};
42+
43+
window.digitalData = {
44+
"page": {
45+
"pageInfo": {
46+
"ibm": {
47+
"siteId": "IBM_" + _ibmAnalytics.settings.name,
48+
},
49+
"segment": {
50+
"enabled": true,
51+
"env": "prod",
52+
"coremetrics": false,
53+
"carbonComponentEvents": false,
54+
"commonProperties": SEGMENT_COMMON_PROPERTIES
55+
}
56+
},
57+
"category": {
58+
"primaryCategory": "PC230"
59+
}
60+
}
61+
};
62+
63+
// Google Consent Mode v2 - Set defaults before Google tags load
64+
window.dataLayer = window.dataLayer || [];
65+
function gtag(){dataLayer.push(arguments);}
66+
67+
// Set default consent to denied
68+
gtag('consent', 'default', {
69+
'ad_storage': 'denied',
70+
'ad_user_data': 'denied',
71+
'ad_personalization': 'denied',
72+
'analytics_storage': 'denied'
73+
});
74+
75+
// TrustArc Consent Update Listener for Google Consent Mode
76+
(function() {
77+
function updateGoogleConsent() {
78+
if (typeof window.truste !== 'undefined' && window.truste.cma) {
79+
var consent = window.truste.cma.callApi('getConsent', window.location.href) || {};
80+
81+
// Map TrustArc categories to Google consent types
82+
// Category 0 = Required, 1 = Functional, 2 = Advertising, 3 = Analytics
83+
var hasAdvertising = consent[2] === 1;
84+
var hasAnalytics = consent[3] === 1;
85+
86+
gtag('consent', 'update', {
87+
'ad_storage': hasAdvertising ? 'granted' : 'denied',
88+
'ad_user_data': hasAdvertising ? 'granted' : 'denied',
89+
'ad_personalization': hasAdvertising ? 'granted' : 'denied',
90+
'analytics_storage': hasAnalytics ? 'granted' : 'denied'
91+
});
92+
}
93+
}
94+
95+
// Listen for consent changes
96+
if (window.addEventListener) {
97+
window.addEventListener('cm_data_subject_consent_changed', updateGoogleConsent);
98+
window.addEventListener('cm_consent_preferences_set', updateGoogleConsent);
99+
}
100+
101+
// Initial check after TrustArc loads
102+
if (document.readyState === 'complete') {
103+
updateGoogleConsent();
104+
} else {
105+
window.addEventListener('load', updateGoogleConsent);
106+
}
107+
})();
108+
</script>
10109
<script src="//1.www.s81c.com/common/stats/ibm-common.js" type="text/javascript" async="async"></script>
11110
{{/with}}
12111

src/partials/intercom.hbs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,35 @@
11
{{#with site.keys.intercom}}
22
<script>
3-
window.intercomSettings = {
4-
app_id: "{{this}}",
5-
api_base: "https://api-iam.intercom.io"
6-
};
7-
</script>
8-
<script>
9-
!function(){var t=window,e=t.Intercom;if("function"==typeof e)e("reattach_activator"),e("update",t.intercomSettings);else{var n=document,a=function(){a.c(arguments)};a.q=[],a.c=function(t){a.q.push(t)},t.Intercom=a;var c=function(){var t=n.createElement("script");t.type="text/javascript",t.async=!0,t.src="https://widget.intercom.io/widget/{{this}}";var e=n.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e)};t.attachEvent?t.attachEvent("onload",c):t.addEventListener("load",c,!1)}}();
3+
(function() {
4+
function loadIntercom() {
5+
// Check for functional consent (category 1)
6+
if (typeof window.truste !== 'undefined' && window.truste.cma) {
7+
var consent = window.truste.cma.callApi('getConsent', window.location.href) || {};
8+
var hasFunctional = consent[1] === 1;
9+
10+
if (hasFunctional) {
11+
window.intercomSettings = {
12+
app_id: "{{this}}",
13+
api_base: "https://api-iam.intercom.io"
14+
};
15+
16+
!function(){var t=window,e=t.Intercom;if("function"==typeof e)e("reattach_activator"),e("update",t.intercomSettings);else{var n=document,a=function(){a.c(arguments)};a.q=[],a.c=function(t){a.q.push(t)},t.Intercom=a;var c=function(){var t=n.createElement("script");t.type="text/javascript",t.async=!0,t.src="https://widget.intercom.io/widget/{{this}}";var e=n.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e)};t.attachEvent?t.attachEvent("onload",c):t.addEventListener("load",c,!1)}}();
17+
}
18+
}
19+
}
20+
21+
// Listen for consent changes
22+
if (window.addEventListener) {
23+
window.addEventListener('cm_data_subject_consent_changed', loadIntercom);
24+
window.addEventListener('cm_consent_preferences_set', loadIntercom);
25+
}
26+
27+
// Initial check
28+
if (document.readyState === 'complete') {
29+
loadIntercom();
30+
} else {
31+
window.addEventListener('load', loadIntercom);
32+
}
33+
})();
1034
</script>
1135
{{/with}}

0 commit comments

Comments
 (0)