Consent & deferred mode
ABTestly supports two consent modes, configurable per site:-
always_on(default) — the snippet runs on every pageload regardless of consent state. Right for sites where ABTestly’s purpose qualifies as strictly necessary, or sites without an EU/UK audience that need ePrivacy compliance. -
deferred— the snippet does nothing observable until your consent management platform (CMP) signals consent has been granted. No network requests, nolocalStoragewrites, no cookies, no DOM mutations. When consent is granted mid-session, the snippet wakes up and runs normally.
deferred if you’re under EU/UK ePrivacy, GDPR, or any regime that requires prior consent before non-essential device storage or third-party requests.
The guarantee, in writing
In deferred mode with consent not granted, the ABTestly inline snippet — the one you paste in your<head> — performs zero of the following:
| Side effect | Pre-consent (deferred) |
|---|---|
Network request to cdn.abtestly.com (fetching the runtime) | ❌ Not made |
Network request to api.abtestly.com (analytics, error reporting) | ❌ Not made |
localStorage write (uid, variant cache, version stamps) | ❌ Not made |
Cookie set (__abtestly_uid) | ❌ Not made |
| DOM mutation (anti-flicker hide class, variant CSS, variant JS) | ❌ Not made |
window.dataLayer.push (GA4 export) | ❌ Not made |
window.__abtestly API exposure (onApply, onCleanup, trackGoal) | ❌ Not made |
SPA pushState/popstate/hashchange listener wrapping | ❌ Not made |
window.error / unhandledrejection listener attached | ❌ Not made |
setInterval) on the consent property you configured. That’s a local JS timer — not observable to anything outside the page.
When window[consentKey] === 'granted' is observed, the snippet then performs the same full flow an always_on site would have performed at pageload — fetch the runtime, bucket the visitor, apply the variant, record the exposure. Exactly once, even if consent flips on and off again.
Configure your site
In Settings → SPA & consent for your site:- Mode:
deferred - Consent key: the
window.<name>property your CMP writes when consent for analytics/A-B testing is granted. Example:abtestly_consent,analytics_storage,cmp_consent_status.
<head>. The snippet is parameterized at copy time — switching modes requires a fresh copy.
Wire your CMP
After ABTestly is configured for deferred mode and the snippet is installed, point your CMP’s grant callback at the configured key:Generic example
OneTrust example
Osano example
CookieYes example
Custom in-house consent
The anti-flicker trade-off
Inalways_on mode the snippet briefly hides the page (opacity: 0) while it decides which variant to apply — this is the anti-flicker mechanism, and it runs immediately on pageload.
In deferred mode we don’t hide the page until consent is granted. The legally cleanest posture is to do nothing pre-consent, which means visitors who eventually grant consent may see a brief flash of original content (FOOC) when the variant applies. This is the intentional trade-off: zero pre-consent action in exchange for a momentary flicker after grant. If your CMP grants consent very quickly (i.e. you have a “consent already given” cookie from a prior visit), the flicker is imperceptible.
What about “granted at load”?
If your CMP has persisted consent from a previous visit and setswindow[consentKey] = 'granted' synchronously BEFORE the ABTestly inline snippet runs, ABTestly detects this on first execution and behaves exactly like always_on — no polling delay, no flicker beyond what always_on visitors already see.
This is the common case for returning visitors with a consent cookie. Make sure your CMP runs before the ABTestly snippet in your <head>, OR write the consent property from a synchronous inline script before ABTestly’s snippet.
What about revocation?
If a visitor grants consent, ABTestly runs, then they later revoke consent in the same session: ABTestly does not undo what it already did (uid in localStorage, variant rendered, impression recorded — those are already there). It also does not start any new side effects after revocation; the next pageload in the revoked state will treat the visitor as not-granted from the start. Cleaning up data already written is out of scope for the snippet. Customers who need full data deletion on revocation should clearlocalStorage.__abtestly_uid, the __abtestly_uid cookie, and any __abtestly_v_* keys themselves — or contact us about a right-to-erasure endpoint at support@abtestly.com.
Verifying the guarantee yourself
Before relying on deferred mode for compliance, verify the contract holds on your site:- Configure deferred mode + your consent key.
- Open a fresh incognito window. Open DevTools → Network + Application tabs.
- Load a page on your site. Confirm in the Network tab that no request to
cdn.abtestly.comorapi.abtestly.comis made. Confirm in Application → Local Storage that no__abtestly_*keys exist. - Trigger your CMP to grant consent. Within ~200ms you should see:
- Network request to
cdn.abtestly.com/s/<your-site-id>.js __abtestly_uidin Local Storage- One exposure beacon to
api.abtestly.com/eper running experiment that targets the page
- Network request to
- Refresh the page (consent now persisted). Observe that the snippet runs immediately on pageload — no 200ms polling delay.
support@abtestly.com — that’s a contract violation and we treat it as a P0.
What happens if you select deferred but forget the key?
The snippet fails closed. It does nothing — no fetch, no hide class, no storage. Your DevTools console will show a clear error:
[abtestly] deferred consent mode is configured but consentKey is empty — the snippet will NOT run until a key is set in your site settings.
We deliberately chose fail-closed over fail-open here. You selected deferred because you wanted consent gating; honoring that intent (by tracking nothing) is safer than silently reverting to always_on (tracking everything pre-consent), which would be the exact opposite of what you asked for.
To fix: Settings → SPA & consent → set a non-empty Consent key → save → re-copy the snippet from the Install panel → replace it in your <head>.
Default key choice
If you’re unsure what key to use, we recommendabtestly_consent — vendor-specific so it doesn’t collide with another tool’s consent property, and obvious in what it’s signalling.
Need help?
Emailsupport@abtestly.com with your CMP name and we’ll help wire it up. If your CMP supports the IAB TCF v2.2 framework, there’s a standard way to map a TCF consent signal to window[consentKey] = 'granted' — we can provide a snippet.