Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
silesky committed Apr 12, 2024
1 parent bab8745 commit 67573c7
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 1 deletion.
3 changes: 3 additions & 0 deletions packages/consent/consent-tools/src/domain/load-context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CreateWrapperSettings } from '../types'
import { AnalyticsConsentError } from '../types/errors'
import { logger } from './logger'
import { ValidationError } from './validation/validation-error'

/**
Expand Down Expand Up @@ -47,13 +48,15 @@ export class LoadContext {
load(options: LoadOptions) {
this.isLoadCalled = true
this.loadOptions = { ...this.loadOptions, ...options }
logger.debug('Load segment w/ consent', this.loadOptions)
}
/**
* Abort the _consent-wrapped_ analytics.js initialization
*/
abort(options?: AbortLoadOptions): void {
this.isAbortCalled = true
this.abortLoadOptions = { ...this.abortLoadOptions, ...options }
logger.debug('Abort consent wrapper', this.loadOptions)
}

validate() {
Expand Down
20 changes: 19 additions & 1 deletion packages/consent/consent-wrapper-onetrust/src/domain/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ import {
export interface OneTrustSettings {
integrationCategoryMappings?: CreateWrapperSettings['integrationCategoryMappings']
disableConsentChangedEvent?: boolean
/**
* Override configured consent model
* - optIn = true (default) - load segment and all destinations without waiting for explicit consent.
* - optIn = false (strict/GDPR) - wait for explicit consent before loading segment
*
* By default, the value is determined by `OneTrust.GetDomainData().ConsentModel` which is set in the OneTrust UI.
*/
optIn?: boolean | (() => boolean)
}

/**
Expand All @@ -32,7 +40,16 @@ export const withOneTrust = <Analytics extends AnyAnalytics>(
await resolveWhen(() => getOneTrustGlobal() !== undefined, 500)
},
// wait for AlertBox to be closed before segment can be loaded. If no consented groups, do not load Segment.
shouldLoadSegment: async () => {
shouldLoadSegment: async (ctx) => {
const isOptIn =
typeof settings.optIn === 'function'
? settings.optIn() === false
: settings.optIn === false

if (isOptIn) {
return ctx.load({ optIn: false })
}
console.log('OneTrust: waiting for alert box to be closed')
await resolveWhen(() => {
const OneTrust = getOneTrustGlobal()!
return (
Expand All @@ -44,6 +61,7 @@ export const withOneTrust = <Analytics extends AnyAnalytics>(
OneTrust.IsAlertBoxClosed())
)
}, 500)
return ctx.load({ optIn: true })
},
getCategories: () => {
const results = getNormalizedCategoriesFromGroupData()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type OtConsentChangedEvent = CustomEvent<ConsentGroupIds>
export interface OneTrustDomainData {
ShowAlertNotice: boolean
Groups: GroupInfoDto[]
ConsentModel: {
Name: 'opt-in' | 'opt-out' | 'custom'
}
}
/**
* The data model used by the OneTrust lib
Expand Down
201 changes: 201 additions & 0 deletions playgrounds/standalone-playground/pages/index-consent-opt-out.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
<html>

<head>


<!-- Form: WriteKey -->
<form method="get">
<input type="text" name="writeKey" placeholder="Writekey" />
<button>Load</button>
</form>
<script>
const { searchParams } = new URL(document.location);
const writeKey = searchParams.get("writeKey");
document.querySelector("input").value = writeKey;
</script>

<!-- Form: Clear OneTrust Cookie -->
<button id="clear-ot-cookies">Clear OneTrust Cookies & Reload</button>
<script>
document.getElementById('clear-ot-cookies').addEventListener('click', () => {
['OptanonConsent', 'OptanonAlertBoxClosed'].forEach((name) => {
document.cookie =
name + "=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;";
});
window.location.reload();
console.log("OneTrust Cookies cleared.");
})
</script>

<!-- OneTrust Vendor Script -->
<script src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js" type="text/javascript"
data-domain-script="80ca7b5c-e72f-4bd0-972a-b74d052a0820-test"></script>

<!-- OneTrust Wrapper -->
<script
src="/node_modules/@segment/analytics-consent-wrapper-onetrust/dist/umd/analytics-onetrust.umd.development.js">
</script>
<!-- Segment Snippet (Modified)-->
<script>
if (writeKey) {
!(function () {
var analytics = (window.analytics = window.analytics || [])
if (!analytics.initialize)
if (analytics.invoked)
window.console &&
console.error &&
console.error('Segment snippet included twice.')
else {
analytics.invoked = !0
analytics.methods = [
'screen',
'register',
'deregister',
'trackSubmit',
'trackClick',
'trackLink',
'trackForm',
'pageview',
'identify',
'reset',
'group',
'track',
'ready',
'alias',
'debug',
'page',
'once',
'off',
'on',
'addSourceMiddleware',
'addIntegrationMiddleware',
'setAnonymousId',
'addDestinationMiddleware',
'emit'
]
analytics.factory = function (e) {
return function () {
if (window.analytics.initialized) {
// Sometimes users assigned analytics to a variable before analytics is done loading, resulting in a stale reference.
// If so, proxy any calls to the 'real' analytics instance.
return window.analytics[e].apply(window.analytics, arguments);
}
var t = Array.prototype.slice.call(arguments)
t.unshift(e)
analytics.push(t)
return analytics
}
}
for (var e = 0; e < analytics.methods.length; e++) {
var key = analytics.methods[e]
analytics[key] = analytics.factory(key)
}
analytics.load = function (key, e) {
var t = document.createElement('script')
t.type = 'text/javascript'
t.async = !0
t.src = '/node_modules/@segment/analytics-next/dist/umd/standalone.js'
var n = document.getElementsByTagName('script')[0]
n.parentNode.insertBefore(t, n)
analytics._loadOptions = e
}
analytics.SNIPPET_VERSION = '4.13.1'
analytics._writeKey = writeKey
window['SEGMENT_CONSENT_WRAPPER_DEBUG_MODE'] = true
withOneTrust(analytics, { optIn: false }).load()
analytics.page()
}
})()
}
</script>

</head>

<body>
<form>
<textarea name="event" id="event">
{
"name": "hi",
"properties": { },
"traits": { },
"options": { }
}
</textarea>
<div>
<button id="track">Track</button>
<button id="identify">Identify</button>
</div>
</form>
<h2>Consent Changed Event</h2>
<pre id="consent-changed"></pre>
<h2>Logs</h2>
<pre id="logs"></pre>

<script type="text/javascript">
const displayConsentLogs = (str) => document.querySelector('#consent-changed').textContent = str
analytics.on('track', (name, properties, options) => {
if (name.includes("Segment Consent")) {
displayConsentLogs("Consent Changed Event Fired")
setTimeout(() => displayConsentLogs(''), 3000)
}
})
const displayRegularLogs = (str) => document.querySelector('#logs').textContent = str
const logEvent = (promise) => {
if (Array.isArray(promise)) {
displayRegularLogs('Analytics is not initialized!')
setTimeout(() => displayRegularLogs(''), 5000)
return
}
if (promise) {
promise.then((ctx) => {
ctx.flush()
displayRegularLogs(JSON.stringify(
ctx.event,
null,
2
))
})
}
}


document.querySelector('#track').addEventListener('click', async (e) => {
e.preventDefault()
const contents = document.querySelector('#event').value
const evt = JSON.parse(contents)
const promise = window.analytics.track(
evt.name ?? '',
evt.properties ?? {},
evt.options ?? {}
)
logEvent(promise)
})

document
.querySelector('#identify')
.addEventListener('click', async (e) => {
e.preventDefault()
const contents = document.querySelector('#event').value
const evt = JSON.parse(contents)
const promise = window.analytics.identify(
evt.name ?? '',
evt.properties ?? {},
evt.options ?? {}
)
logEvent(promise)
})
</script>
<style>
body {
font-family: monospace;
}

#event {
margin: 2em 0;
min-height: 200px;
min-width: 700px;
}
</style>
</body>

</html>

0 comments on commit 67573c7

Please sign in to comment.