Consent

Make aff.js and referalli/browser follow your consent tool: nothing is stored or sent until the visitor allows it.

Embed
Preview of the card
<a href="https://referalli.com/docs/tracking-consent"><img src="https://referalli.com/docs/_api/public/orgs/07f432f4-34b9-46a7-aaad-c0e395d2e4f9/spaces/2bf4f614-3630-4fbf-85f9-5ecafa6b7d97/pages/47bf5f5a-3cc4-43b0-aa93-0570d31974af/social-card.svg?v=3e7ae33eec8b" alt="Consent" width="600" height="315"></a>

A referral cookie credits an affiliate, so in the EU and UK it needs the visitor's opt-in (CNIL, ICO, EDPB guidelines 2/2023). The tracking script can read your consent tool (CMP) and wait for it.

Visitor's choice

Storage

Visit beacon

Referral

No decision yet

Nothing written

None

Kept in memory: aff.getReferral() and aff.signupMetadata() still return it, so a sign-up on the same page is still attributed

Granted

referalli_ctx (and its twin referally_ctx) written

Sent, with consent evidence

Stored for the cookie window

Denied or withdrawn

Deleted at once

None

Dropped

The evidence (which tool, its record id, the TCF or GPP string, the time) is stored with the click. GET /v1/clicks/{id} returns it, and GET /v1/clicks/consent-coverage gives the share of attributed sign-ups that carry it.

Choose a mode

Set it once in Settings → Tracking, or with PUT /v1/org/tracking-consent; the script picks it up within five minutes, with no change to your tag. A tag attribute overrides it for one site.

Mode

Behaviour

auto (new orgs)

Uses the first consent tool it finds on the page, in the order below. With none, noCmp: "persist" stores as before and "memory" never stores. It waits up to 3 seconds for a tool that loads late; if the visitor leaves sooner, it decides then.

a tool id

Only that tool. Add ?consent=<id> to the script URL to download just its adapter.

pending

Waits for your own code: aff.consent(true) or aff.consent(false).

none

Persist always. Stores before any choice, as the script did before consent support. Use it only where no consent is required. Orgs created before consent support start here, so their tags behave exactly as before until they choose.

<!-- Follow OneTrust's "Targeting" group, and download only its adapter -->
<script src="https://referalli.com/t/tk_.../aff.js?consent=onetrust" data-consent-category="C0004" async></script>

auto checks them in this order.

Custom

Define window.referalliConsent() returning true, false or null (no decision), and dispatch window.dispatchEvent(new Event('referalli:consent')) when it changes. Or skip it and push the decision: aff.consent(true | false) (it is idempotent; the latest signal wins). Calls made before the script loads are queued:

<script>window.aff = window.aff || { q: [] }; aff.q.push(['consent', true]);</script>

Reads CookieMunch.consent after hasResponse, category referrals, falling back to marketing when your site has no referrals category. Evidence: the consent id. Tag: data-consent="cookiemunch".

OneTrust

Reads OnetrustActiveGroups, group C0004 (targeting) by default. An inactive group counts as a denial only once the banner was closed. Evidence: the data-subject id. Tag: data-consent="onetrust".

Cookiebot

Reads Cookiebot.consent.marketing. Evidence: consentID. Tag: data-consent="cookiebot".

Usercentrics

Beta. v2 UC_UI.getServicesBaseInfo() or v3 __ucCmp.getConsentDetails(). Set the category to a service name (add a "Referalli" service) or a category slug; default marketing. Tag: data-consent="usercentrics".

Didomi

Beta. Reads Didomi.getUserStatus(): purpose cookies by default, or a vendor id (c:referalli-…). Tag: data-consent="didomi".

Osano

Beta. Reads Osano.cm.getConsent().MARKETING. Tag: data-consent="osano".

Termly

Beta. Reads Termly.getConsentState().advertising. A returning visitor who declined is kept in memory only (never stored). Tag: data-consent="termly".

TCF

IAB TCF v2.2. Through __tcfapi: purpose 1 (store) plus purpose 7 or 9, or, with data-consent-tcf-vendor="<id>", purpose 1 plus that vendor. Evidence: the TC string. Tag: data-consent="tcf".

GPP

IAB GPP, beta. Through __gpp: the EU section follows the TCF rule; US state sections deny on a sale, sharing or targeted-advertising opt-out. Evidence: the GPP string. Tag: data-consent="gpp".

Version 2. Follows ad_storage (or analytics_storage) from gtag('consent', 'update', …). A denied default with no update yet counts as no decision. Tag: data-consent="gcm".

In your own code

import { createTracker } from 'referalli/browser';
const tracker = await createTracker({ publishableKey: 'tk_...', consent: { mode: 'auto', noCmp: 'memory' } });
tracker.consentMode;        // 'onetrust', 'auto' while looking, 'no-cmp', …
tracker.consentEvidence();  // pass to POST /v1/referrals/associate as `consent`

Server-side kits take a function that reads your CMP's cookie; on unknown they set no cookie, on denied they delete it:

export const middleware = referalliMiddleware({ consent: (req) => (req.cookies.get('my_cmp')?.value === 'yes' ? 'granted' : 'unknown') });

/.well-known/forgedeck-embed.json lists the script's storage (referalli_ctx and referally_ctx, cookie and localStorage, category referrals) and origins; GET /v1/embed?token=tk_... gives your org's cookie window and setting.

Updated