Skip to main content

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, no localStorage writes, no cookies, no DOM mutations. When consent is granted mid-session, the snippet wakes up and runs normally.
Pick 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 effectPre-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
The only thing the inline snippet does pre-consent is run a tiny polling check (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.
Save the site, then re-copy the snippet from the Install panel and replace the one in your <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

<script>
  // When your CMP / banner grants consent:
  window.abtestly_consent = 'granted';
</script>
That’s it. The snippet’s poller (running at 200ms intervals) observes the value, clears itself, fetches the runtime, and runs the experiment flow exactly once.

OneTrust example

<script>
  window.OptanonWrapper = function () {
    // Categorize ABTestly under "Performance" or whichever cookie category fits
    // your DPO's classification — example uses "C0003" for Performance.
    if (window.OnetrustActiveGroups && window.OnetrustActiveGroups.indexOf('C0003') >= 0) {
      window.abtestly_consent = 'granted';
    }
  };
</script>

Osano example

<script>
  if (window.Osano) {
    Osano.cm.addEventListener('osano-cm-consent-saved', function (consent) {
      if (consent.ANALYTICS === 'ACCEPT') {
        window.abtestly_consent = 'granted';
      }
    });
  }
</script>

CookieYes example

<script>
  document.addEventListener('cookieyes_consent_update', function (e) {
    if (e.detail && e.detail.accepted && e.detail.accepted.indexOf('analytics') >= 0) {
      window.abtestly_consent = 'granted';
    }
  });
</script>
<script>
  document.querySelector('#accept-cookies').addEventListener('click', function () {
    window.abtestly_consent = 'granted';
    // ...your own consent persistence
  });
</script>

The anti-flicker trade-off

In always_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 sets window[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 clear localStorage.__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:
  1. Configure deferred mode + your consent key.
  2. Open a fresh incognito window. Open DevTools → Network + Application tabs.
  3. Load a page on your site. Confirm in the Network tab that no request to cdn.abtestly.com or api.abtestly.com is made. Confirm in Application → Local Storage that no __abtestly_* keys exist.
  4. Trigger your CMP to grant consent. Within ~200ms you should see:
    • Network request to cdn.abtestly.com/s/<your-site-id>.js
    • __abtestly_uid in Local Storage
    • One exposure beacon to api.abtestly.com/e per running experiment that targets the page
  5. Refresh the page (consent now persisted). Observe that the snippet runs immediately on pageload — no 200ms polling delay.
If any of steps 3 fail (network or storage activity appears before grant), file a ticket at 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 recommend abtestly_consent — vendor-specific so it doesn’t collide with another tool’s consent property, and obvious in what it’s signalling.
<!-- Once granted: -->
<script>window.abtestly_consent = 'granted';</script>

Need help?

Email support@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.