Managed & regulations
The source-available core is self-sufficient and offline by default — zero network calls. When you need per-country behavior, audit-grade consent receipts or a certified CMP, plug in a backend through the adapter interface: your own, or the upcoming ConsentLoop Cloud.
Regulation presets (local, no backend)
| Preset | Model | Behavior |
|---|---|---|
gdpr (default) | Opt-in | Nothing optional runs before consent. Equal Accept/Reject. Not dismissable. New categories re-prompt. |
us-optout | Opt-out | Category default: true applies immediately (method: "implied"); banner offers opting out; Esc/dismiss persists the implied choice. CCPA/CPRA-style. |
none | Opt-in UI | Like gdpr but dismissable without a choice. |
ConsentLoop.run({
regulation: "us-optout",
categories: {
analytics: { default: true },
marketing: { default: true }, // visitors opt *out* of these
},
content: { translations: { en: { banner: {
title: "Your privacy choices",
description: 'We share some data with advertising partners. Opt out anytime — see "Do Not Sell or Share".',
links: [{ label: "Do Not Sell or Share My Personal Information", href: "/do-not-sell" }],
} } } },
});
The adapter contract
Two optional functions. Everything is fail-open: a slow or broken backend never blocks the banner or the page.
ConsentLoop.run({
adapter: {
// Called once before the banner would show (skipped for returning visitors).
// Decide per-jurisdiction behavior server-side.
async init({ config, stored }) {
const res = await fetch("https://api.your.app/consent/decision");
const { show, regulation, lang } = await res.json();
return { show, regulation, lang };
// show: false -> no banner needed here; defaults applied as implied consent
// regulation -> override the preset for this visitor (e.g. "us-optout" for CA)
// lang -> force a language
},
// Fire-and-forget consent receipt after every choice (uses sendBeacon when available).
persist(record) {
navigator.sendBeacon("https://api.your.app/consent/receipts", JSON.stringify(record));
},
},
});
Timeout: the banner waits at most manage.timeout (default 750 ms) for init(), then proceeds with local config. The consent record you receive is the full audit object — id, timestamps, revision, per-service choices, regulation, method.
ConsentLoop Cloud coming soon
Our managed plan is the same adapter, hosted: one line instead of a custom backend.
ConsentLoop.run({
manage: {
endpoint: "https://api.consentloop.com/v1",
siteId: "site_123",
},
});
- Geo rules — GDPR in the EEA, CCPA/CPRA in California, LGPD in Brazil, no banner where none is required. Decided at the edge via
GET /decision. - Consent receipts — tamper-evident audit trail via
POST /consent, exportable for DPAs. - Certified CMP — IAB TCF v2.2 string generation and Google CMP certification handled for you.
- Remote config & translations — tweak texts and categories without deploys.
Consent-aware rendering on your server
Consent is a first-party cookie (cl_consent), so your server can read it too:
// e.g. in middleware — short keys: a = accepted categories
const raw = cookies.get("cl_consent");
const consent = raw ? JSON.parse(raw) : null;
const analyticsAllowed = consent?.a?.includes("analytics") ?? false;