Skip to content

Instantly share code, notes, and snippets.

@sperand-io
Last active October 31, 2023 10:05
Show Gist options
  • Save sperand-io/4725e248a35d5005d68d810d8a8f7b29 to your computer and use it in GitHub Desktop.
Save sperand-io/4725e248a35d5005d68d810d8a8f7b29 to your computer and use it in GitHub Desktop.
Example of using analytics.js conditional loading with TrustArc Consent Manager
// To get started, make sure you're using the latest version of the analytics.js snippet (4.1.0 or above)
// and remove the analytics.load("YOUR_WRITE_KEY"); call (so that you can conditionally manage the loading process).
// optional, requires build step:
import fetch from 'isomorphic-fetch'
import {flatten, sortedUniqBy, sortBy} from 'lodash'
import inEU from '@segment/in-eu'
// CONFIG
const YOUR_DOMAIN = 'domain.com'
const WEBSITE_WRITE_KEY = 'writeKey'
const OTHER_WRITE_KEYS = [] // any other ones you want to load integrations from
// gets enabled destinations across your source (and other sources in workspace)
const destinations = await fetchDestinations([WEBSITE_WRITE_KEY, ...OTHER_WRITE_KEYS])
// KEY LOGIC HERE
// eg. could instead use getConsentCategories and map between the cookie domains to specific Segment Ints, etc
// review this logic carefully, and edit per your business requirements
const { consentDecision } = truste.cma.callApi("getConsentDecision", YOUR_DOMAIN);
const destinationPreferences = destinations.map(function (dest) {
if (consentDecision === 3) return { [dest.name]: true };
if (consentDecision === 2) return { [dest.name]: dest.categories.includes('Advertising') ? false : true }; // non-advertising only
if (consentDecision === 1) return { [dest.name]: dest.name === 'Segment.io' ? true : false }; // segment only
if (consentDecision === 0) return { [dest.name]: true } // IMPORTANT - this is default value for "no preference set"
})
conditionallyLoadAnalytics({
WEBSITE_WRITE_KEY,
destinations,
destinationPreferences,
true // or replace with custom isConsentRequired func, eg. inEU() from above!
})
// registers a listener for consent changes, will reload too
window.top.postMessage(JSON.stringify({
PrivacyManagerAPI: {
action: "getConsent",
timestamp: new Date().getTime(),
self: YOUR_DOMAIN
}
}), "*");
window.addEventListener("message", function reload(e) {
const response = JSON.parse(e.data)
if (response.PrivacyManagerAPI.consent === "denied") {
return window.location.reload();
}
// otherwise approved... carry on!
}, false);
function conditionallyLoadAnalytics({
writeKey,
destinations,
destinationPreferences,
isConsentRequired,
shouldReload = true // change if you dont want to reload on consent changes
}) {
const integrations = {All: false, 'Segment.io': true}
let isAnythingEnabled = false
if (!destinationPreferences) {
if (isConsentRequired) {
return
}
// Load a.js normally when consent isn't required and there's no preferences
if (!window.analytics.initialized) {
window.analytics.load(writeKey)
}
return
}
for (const destination of destinations) {
const isEnabled = Boolean(destinationPreferences[destination.id])
if (isEnabled) {
isAnythingEnabled = true
}
integrations[destination.id] = isEnabled
}
// Reload the page if the trackers have already been initialised so that
// the user's new preferences can take affect
if (window.analytics.initialized) {
if (shouldReload) {
window.location.reload()
}
return
}
// Don't load a.js at all if nothing has been enabled
if (isAnythingEnabled) {
window.analytics.load(writeKey, {integrations})
}
}
async function fetchDestinationForWriteKey(writeKey) {
const res = await fetch(
`https://cdn.segment.com/v1/projects/${writeKey}/integrations`
)
if (!res.ok) {
throw new Error(
`Failed to fetch integrations for write key ${writeKey}: HTTP ${
res.status
} ${res.statusText}`
)
}
const destinations = await res.json()
// Rename creationName to id to abstract the weird data model
for (const destination of destinations) {
destination.id = destination.creationName
delete destination.creationName
}
return destinations
}
async function fetchDestinations(writeKeys) {
const destinationsRequests = []
for (const writeKey of writeKeys) {
destinationsRequests.push(fetchDestinationForWriteKey(writeKey))
}
let destinations = flatten(await Promise.all(destinationsRequests))
// Remove the dummy Repeater destination
destinations = destinations.filter(d => d.id !== 'Repeater')
destinations = sortBy(destinations, ['id'])
destinations = sortedUniqBy(destinations, 'id')
return destinations
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment