Tag managers
Cloudflare Zaraz
Configure Cloudflare Zaraz
cloudflareZaraz connects c15t to an existing Zaraz installation. It inserts
no script and configures no tools. Zaraz loads the tools; c15t decides which
purposes they may use. In the Zaraz dashboard:
- Enable Consent Management and create purposes for the c15t categories you use.
- Assign a purpose to every tool that needs permission. Zaraz runs a tool without a purpose regardless of consent.
- Turn off automatic display of the Zaraz consent modal. c15t owns the UI.
- Turn off Automatic Pageview Tracking, and automatic SPA pageviews too if your app sends them itself.
- Copy the purpose IDs, not the purpose names, into the mapping below.
Zaraz keeps its own consent cookie. An automatic pageview can run with a grant
from a previous visit before c15t applies the current permissions. With
automatic pageviews off, send the first pageview from onReady, which runs
after the first synchronization. DOM-ready, timer and click triggers you add in
Zaraz can still run before the bridge starts; audit them. Cloudflare documents
purpose assignment
and pageview settings.
Register one bridge per app. Keep Zaraz's own loader and its dashboard tools
when you follow the registration steps below; remove only standalone loaders
for tools that Zaraz already runs, including a separate @c15t/integrations helper
for the same tool. If Zaraz auto-injection is off, load
Zaraz manually
once.
Register the scripts
Complete your framework quickstart first. Keep its Inth endpoint, policy, styles and consent UI. Remove the vendor's original script, SDK initializer or tag-manager entry, so the vendor loads only through c15t.
The vendor pages put the helper in src/consent-scripts.ts. If your framework
quickstart already has a scripts array, such as the one in c15t.config.ts
in the Next.js guide, add the helper to that array instead of creating a
second file.
The scripts export is a configuration, not an initializer. Add it to the c15t provider you already have, at the registration
point for your framework below. These are edits to that provider, not a second
provider.
Add the configuration to scripts in c15t.config.ts, next to
next.config.ts:
Keep the rest of your config, such as mode and routePrefix, in the
same call. ConsentRoot reads the config in the browser, so the layout
keeps passing only state. App Router, Pages Router and static export all
read the same file. See
Next.js scripts and embeds.
Options
| Option | Default | Behavior |
|---|---|---|
purposes | Required | Maps c15t categories to Zaraz purpose IDs. A category can list several IDs. An empty mapping, a blank ID, an ID with surrounding whitespace or an ID mapped twice throws. |
hideBuiltInModal | true | Hides the Zaraz modal if it is visible. Also turn off auto-display in Zaraz. |
sendQueuedEvents | true | Calls zaraz.consent.sendQueuedEvents() after a purpose changes from denied to allowed. Set false to discard pageviews Zaraz queued before consent. |
onReady | None | Runs once after the first successful synchronization, even when every purpose is denied. |
onError | None | Receives synchronization errors. |
Loading and revocation
cloudflareZaraz returns a callback-only script with the necessary category
and alwaysLoad, so the bridge runs for every visitor. That does not make the
tools behind it necessary. Control each tool through its Zaraz purpose.
The bridge's vendor slug is cloudflare-zaraz. Declare a vendor with that
id to give visitors a switch for Zaraz in the preference dialog. While a
visitor has it switched off, the bridge denies every purpose mapped to an
optional category, whatever the categories allow. See
vendor consent for your framework.
When the Zaraz consent API is ready, the bridge reads zaraz.consent.getAll()
and sets each returned purpose to true only if its mapped category is
allowed in c15t's effective permissions, which include policy restrictions.
Purposes you did not map are set to false. If the API is not ready,
the bridge waits for the zarazConsentAPIReady event and applies the latest
permissions; it does not poll. On each consent change it calls
zaraz.consent.set() only when a value differs, then replays queued events
for newly allowed purposes. Revocation sets purposes to false and replays
nothing. Zaraz returns only purposes attached to enabled tools, so a mapped ID
missing from getAll() gets no grant.
If a Zaraz call throws, onReady waits and the bridge retries on the next
consent change or readiness event. Without onError, the error reaches the
script loader's debug events, or the browser's error handler for readiness
events. A failed revocation can leave the previous Zaraz grant in place, and a
retried replay can send a queued event twice. Disposing the loader detaches the
bridge but does not revoke purposes or stop tools that already ran. The bridge
maps categories to purposes only; it does not translate IAB TCF choices.
Verify Cloudflare Zaraz
Test with isolated destinations. getAll() shows what the bridge set, but only
a tool's own requests show whether it respected that.
- In a private window with an opt-in policy, load the page. The bridge adds
no script element.
zaraz.consent.getAll()returnsfalsefor every purpose, the Zaraz modal stays hidden, and no purpose-gated tool sends a request. - Click Reject, then reload. Every purpose is still
false. - Open Privacy settings and allow measurement. Without a reload, the
measurement purposes become
true, the queued pageview replays and measurement tools send requests. Marketing tools stay silent. - Turn measurement off again and save. c15t reloads the page, and the new
page starts with every purpose
false. - In the console, call
zaraz.consent.set()to grant a purpose that c15t denies, then reload. The bridge sets it back tofalsebeforeonReadyruns.
Cloudflare Web Analytics is a separate product with its own helper. See the consent verification guide for navigation and hosting checks.