Last active
October 31, 2023 10:05
-
-
Save sperand-io/4725e248a35d5005d68d810d8a8f7b29 to your computer and use it in GitHub Desktop.
Example of using analytics.js conditional loading with TrustArc Consent Manager
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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