Skip to main content

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:

  1. Enable Consent Management and create purposes for the c15t categories you use.
  2. Assign a purpose to every tool that needs permission. Zaraz runs a tool without a purpose regardless of consent.
  3. Turn off automatic display of the Zaraz consent modal. c15t owns the UI.
  4. Turn off Automatic Pageview Tracking, and automatic SPA pageviews too if your app sends them itself.
  5. 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.

npm install @c15t/integrations@alpha
src/consent-scripts.ts
import { cloudflareZaraz } from '@c15t/integrations/cloudflare-zaraz';

// Zaraz provides this global after its loader runs.
declare const zaraz: { track: (event: string) => void };

export const scripts = [
	cloudflareZaraz({
		purposes: {
			measurement: ['your-measurement-purpose-id'],
			marketing: ['your-marketing-purpose-id'],
		},
		onReady: () => {
			zaraz.track('Pageview');
		},
	}),
];

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:

import { defineConsentConfig } from 'c15t/next';
import { scripts } from './src/consent-scripts';

export default defineConsentConfig({ scripts });

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

OptionDefaultBehavior
purposesRequiredMaps 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.
hideBuiltInModaltrueHides the Zaraz modal if it is visible. Also turn off auto-display in Zaraz.
sendQueuedEventstrueCalls zaraz.consent.sendQueuedEvents() after a purpose changes from denied to allowed. Set false to discard pageviews Zaraz queued before consent.
onReadyNoneRuns once after the first successful synchronization, even when every purpose is denied.
onErrorNoneReceives 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.

  1. In a private window with an opt-in policy, load the page. The bridge adds no script element. zaraz.consent.getAll() returns false for every purpose, the Zaraz modal stays hidden, and no purpose-gated tool sends a request.
  2. Click Reject, then reload. Every purpose is still false.
  3. 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.
  4. Turn measurement off again and save. c15t reloads the page, and the new page starts with every purpose false.
  5. In the console, call zaraz.consent.set() to grant a purpose that c15t denies, then reload. The bridge sets it back to false before onReady runs.

Cloudflare Web Analytics is a separate product with its own helper. See the consent verification guide for navigation and hosting checks.