-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: check user opt-out when blocking trackers
Adds check for user manual tracking opt out to tracking module
- Loading branch information
1 parent
3f394f5
commit 64e4be8
Showing
5 changed files
with
127 additions
and
2 deletions.
There are no files selected for viewing
This file contains 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
73 changes: 73 additions & 0 deletions
73
packages/tracking/src/integrations/__tests__/getConsentDecision.test.ts
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { Consent } from '../consent'; | ||
import { | ||
getConsentDecision, | ||
OPT_OUT_DATALAYER_VAR, | ||
} from '../getConsentDecision'; | ||
import { TrackingWindow } from '../types'; | ||
|
||
const MINIMUM_CONSENT = [Consent.StrictlyNecessary]; | ||
|
||
const FULL_CONSENT = [ | ||
Consent.StrictlyNecessary, | ||
Consent.Functional, | ||
Consent.Performance, | ||
Consent.Targeting, | ||
]; | ||
|
||
const FULL_CONSENT_STRING = [',', ...FULL_CONSENT].join(','); | ||
|
||
describe('getConsentDecision', () => { | ||
it('converts a stringified consent decision into an array', () => { | ||
const result = getConsentDecision({ | ||
scope: { | ||
OnetrustActiveGroups: FULL_CONSENT_STRING, | ||
}, | ||
}); | ||
expect(result).toEqual(FULL_CONSENT); | ||
}); | ||
|
||
it('does not modify an array formatted consent decision', () => { | ||
const result = getConsentDecision({ | ||
scope: { | ||
OnetrustActiveGroups: FULL_CONSENT, | ||
}, | ||
}); | ||
expect(result).toEqual(FULL_CONSENT); | ||
}); | ||
|
||
describe('optedOutExternalTracking', () => { | ||
it('reduces the consent decision to necessary and functional for opted out users', () => { | ||
const result = getConsentDecision({ | ||
scope: { | ||
OnetrustActiveGroups: FULL_CONSENT, | ||
}, | ||
optedOutExternalTracking: true, | ||
}); | ||
expect(result).toEqual([Consent.StrictlyNecessary, Consent.Functional]); | ||
}); | ||
|
||
it('does not add Functional tracking if the user has opted out of it', () => { | ||
const result = getConsentDecision({ | ||
scope: { | ||
OnetrustActiveGroups: MINIMUM_CONSENT, | ||
}, | ||
optedOutExternalTracking: true, | ||
}); | ||
expect(result).toEqual(MINIMUM_CONSENT); | ||
}); | ||
|
||
it('triggers the opt out datalayer variable', () => { | ||
const scope: TrackingWindow = { | ||
OnetrustActiveGroups: FULL_CONSENT, | ||
}; | ||
getConsentDecision({ | ||
scope, | ||
optedOutExternalTracking: true, | ||
}); | ||
const dataLayerVars = scope.dataLayer | ||
?.map((v: Record<string, unknown>) => Object.keys(v)) | ||
.flat(); | ||
expect(dataLayerVars).toEqual([OPT_OUT_DATALAYER_VAR]); | ||
}); | ||
}); | ||
}); |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { Consent } from './consent'; | ||
import { TrackingWindow } from './types'; | ||
|
||
export interface ConsentDecisionOptions { | ||
scope: TrackingWindow; | ||
optedOutExternalTracking?: boolean; | ||
} | ||
|
||
export const OPT_OUT_DATALAYER_VAR = 'user_opted_out_external_tracking'; | ||
|
||
export const getConsentDecision = ({ | ||
scope, | ||
optedOutExternalTracking, | ||
}: ConsentDecisionOptions) => { | ||
let consentDecision: Consent[] = []; | ||
|
||
if (typeof scope.OnetrustActiveGroups === 'string') { | ||
consentDecision = scope.OnetrustActiveGroups.split(',').filter( | ||
Boolean | ||
) as Consent[]; | ||
} else if (scope.OnetrustActiveGroups) { | ||
consentDecision = scope.OnetrustActiveGroups; | ||
} | ||
|
||
if (optedOutExternalTracking) { | ||
/** | ||
* If user has already opted out of everything but the essentials | ||
* don't force them to consent to Functional trackers | ||
*/ | ||
if (consentDecision.length > 1) { | ||
consentDecision = [Consent.StrictlyNecessary, Consent.Functional]; | ||
} | ||
scope.dataLayer ??= []; | ||
scope.dataLayer.push({ [OPT_OUT_DATALAYER_VAR]: true }); | ||
} | ||
|
||
return consentDecision; | ||
}; |
This file contains 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
This file contains 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