-
Notifications
You must be signed in to change notification settings - Fork 12
feat: support consent management #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ The AEM Experimentation plugin supports: | |
| - :busts_in_silhouette: serving different content variations to different audiences, including custom audience definitions for your project that can be either resolved directly in-browser or against a trusted backend API. | ||
| - :money_with_wings: serving different content variations based on marketing campaigns you are running, so that you can easily track email and/or social campaigns | ||
| - :chart_with_upwards_trend: running A/B test experiments on a set of variants to measure and improve the conversion on your site. This works particularly with our :chart: [RUM conversion tracking plugin](https://github.com/adobe/franklin-rum-conversion). | ||
| - :shield: privacy-compliant experimentation with built-in consent management support for GDPR, CCPA, and other privacy regulations | ||
| - :rocket: easy simulation of each experience and basic reporting leveraging in-page overlays | ||
|
|
||
| ## Installation | ||
|
|
@@ -200,6 +201,175 @@ The plugin exposes experiment data through two mechanisms: | |
|
|
||
| ### Available APIs | ||
|
|
||
| #### Consent Management | ||
|
|
||
| The plugin provides consent management APIs for privacy compliance. Experiments can be configured to require user consent before running. | ||
|
|
||
| **APIs:** | ||
|
|
||
| ```javascript | ||
| import { | ||
| isUserConsentGiven, | ||
| updateUserConsent | ||
| } from './plugins/experimentation/src/index.js'; | ||
|
|
||
| // Check if user has consented to experimentation | ||
| const hasConsent = isUserConsentGiven(); | ||
|
|
||
| // Integrate this with your consent management platform events to track the user's choice | ||
| updateUserConsent(true); // or false to revoke consent | ||
| ``` | ||
|
|
||
| **Requiring consent for an experiment:** | ||
|
|
||
| Add the `Experiment Requires Consent` metadata property: | ||
|
|
||
| | Metadata | | | ||
| |-----------------------|--------------------------------------------------------------| | ||
| | Experiment | Hero Test | | ||
| | Experiment Variants | /variant-1, /variant-2 | | ||
| | Experiment Requires Consent | true | | ||
|
|
||
| **Implementation:** | ||
|
|
||
| You can integrate consent management in two ways: | ||
|
|
||
| 1. **In your `experiment-loader.js`** (recommended) - keeps all experimentation code together | ||
| 2. **In your `scripts.js`** - if you need consent for other purposes beyond experimentation | ||
|
|
||
| <details> | ||
| <summary>Recommended: Integrate in experiment-loader.js</summary> | ||
|
|
||
| ```javascript | ||
| // experiment-loader.js | ||
| import { | ||
| updateUserConsent, | ||
| isUserConsentGiven, | ||
| } from '../plugins/experimentation/src/index.js'; | ||
|
|
||
| /** | ||
| * Initialize consent management | ||
| * Choose ONE of the setup functions based on your CMP (Consent Management Platform) | ||
| * | ||
| * IMPORTANT: These are example implementations. Please: | ||
| * 1. Verify the consent categories match your OneTrust/Cookiebot configuration | ||
| * 2. Test thoroughly in your environment | ||
| * 3. Consult with your legal/privacy team about consent requirements | ||
| */ | ||
| function initConsent() { | ||
| // OPTION 1: OneTrust | ||
| function setupOneTrustConsent() { | ||
| // Step 1: Bridge OneTrust's callback to dispatch a custom event | ||
| window.OptanonWrapper = function() { | ||
| const activeGroups = window.OnetrustActiveGroups || ''; | ||
| const groups = activeGroups.split(',').filter(g => g); | ||
| window.dispatchEvent(new CustomEvent('consent.onetrust', { | ||
| detail: groups | ||
| })); | ||
| }; | ||
|
|
||
| // Step 2: Listen for the custom event | ||
| function consentEventHandler(ev) { | ||
| const groups = ev.detail; | ||
| const hasConsent = groups.includes('C0003') // Functional Cookies | ||
| || groups.includes('C0004'); // Targeting Cookies | ||
| updateUserConsent(hasConsent); | ||
| } | ||
| window.addEventListener('consent.onetrust', consentEventHandler); | ||
| } | ||
|
|
||
| // OPTION 2: Cookiebot | ||
| function setupCookiebotConsent() { | ||
| function handleCookiebotConsent() { | ||
| const preferences = window.Cookiebot?.consent?.preferences || false; | ||
| const marketing = window.Cookiebot?.consent?.marketing || false; | ||
| updateUserConsent(preferences || marketing); | ||
| } | ||
| window.addEventListener('CookiebotOnConsentReady', handleCookiebotConsent); | ||
| window.addEventListener('CookiebotOnAccept', handleCookiebotConsent); | ||
| } | ||
|
Comment on lines
+281
to
+290
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice one! We could add this to the martech plugin as well so it's consistent!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| // OPTION 3: Custom Consent Banner | ||
| function setupCustomConsent() { | ||
| document.addEventListener('consent-updated', (event) => { | ||
| updateUserConsent(event.detail.experimentation); | ||
| }); | ||
| } | ||
|
|
||
| // Choose ONE: | ||
| setupOneTrustConsent(); // or setupCookiebotConsent() or setupCustomConsent() | ||
| } | ||
|
|
||
| export async function runExperimentation(document, config) { | ||
| if (!isExperimentationEnabled()) { | ||
| return null; | ||
| } | ||
|
|
||
| // Initialize consent BEFORE loading experimentation | ||
| initConsent(); | ||
|
|
||
| const { loadEager } = await import('../plugins/experimentation/src/index.js'); | ||
| return loadEager(document, config); | ||
| } | ||
|
|
||
| // Export consent functions for use elsewhere if needed | ||
| export { updateUserConsent, isUserConsentGiven }; | ||
| ``` | ||
|
|
||
| Your `scripts.js` stays clean - no consent code needed there! | ||
|
|
||
| </details> | ||
|
|
||
| <details> | ||
| <summary>Integrate in scripts.js</summary> | ||
|
|
||
| ```javascript | ||
| // scripts.js | ||
| import { | ||
| updateUserConsent, | ||
| isUserConsentGiven, | ||
| } from '../plugins/experimentation/src/index.js'; | ||
|
|
||
| import { runExperimentation } from './experiment-loader.js'; | ||
|
|
||
| // Setup consent (choose ONE based on your CMP) | ||
| function setupOneTrustConsent() { | ||
| // Step 1: Bridge OneTrust's callback to dispatch a custom event | ||
| window.OptanonWrapper = function() { | ||
| const activeGroups = window.OnetrustActiveGroups || ''; | ||
| const groups = activeGroups.split(',').filter(g => g); | ||
| window.dispatchEvent(new CustomEvent('consent.onetrust', { | ||
| detail: groups | ||
| })); | ||
| }; | ||
|
|
||
| // Step 2: Listen for the custom event | ||
| function consentEventHandler(ev) { | ||
| const groups = ev.detail; | ||
| const hasConsent = groups.includes('C0003') // Functional Cookies | ||
| || groups.includes('C0004'); // Targeting Cookies | ||
| updateUserConsent(hasConsent); | ||
| } | ||
| window.addEventListener('consent.onetrust', consentEventHandler); | ||
| } | ||
|
FentPams marked this conversation as resolved.
|
||
|
|
||
| async function loadEager(doc) { | ||
| document.documentElement.lang = 'en'; | ||
| decorateTemplateAndTheme(); | ||
|
|
||
| // Initialize consent BEFORE running experiments | ||
| setupOneTrustConsent(); | ||
|
|
||
| await runExperimentation(doc, experimentationConfig); | ||
|
|
||
| // ... rest of your code | ||
| } | ||
| ``` | ||
|
|
||
| </details> | ||
|
|
||
| For detailed usage instructions and more examples, see the [Experiments documentation](/documentation/experiments.md#consent-based-experiments). | ||
|
|
||
| #### Events | ||
|
|
||
| Listen for the `aem:experimentation` event to react when experiments, campaigns, or audiences are applied: | ||
|
|
@@ -508,6 +678,7 @@ Here's the complete experiment config structure available in `window.hlx.experim | |
| variantNames: ["control", "challenger-1"], | ||
| audiences: ["mobile", "desktop"], | ||
| resolvedAudiences: ["mobile"], | ||
| requiresConsent: false, // whether this experiment requires user consent | ||
| run: true, | ||
| variants: { | ||
| control: { percentageSplit: "0.5", pages: ["/current"], label: "Control" }, | ||
|
|
||
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
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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.