@c15t/react 3.0.0-alpha.1 → 3.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -2
- package/dist/aggregate-components.js +1 -1
- package/dist/chunk-warming.js +1 -1
- package/dist/component-hooks/use-headless-iab-consent-ui.js +1 -1
- package/dist/component-hooks/use-panel-trigger.js +1 -1
- package/dist/components/consent-gate/atoms.js +1 -0
- package/dist/components/consent-gate/consent-gate.js +2 -0
- package/dist/components/consent-gate/index.js +2 -0
- package/dist/components/consent-preferences-link/consent-preferences-link.js +1 -1
- package/dist/components/iab-panel/atoms/purpose-item.js +1 -1
- package/dist/components/iab-panel/atoms/stack-item.js +1 -1
- package/dist/components/iab-panel/iab-panel.js +1 -1
- package/dist/components/iab-panel/index.js +1 -1
- package/dist/components/panel/atoms/overlay.js +1 -1
- package/dist/components/panel/atoms/root.js +1 -1
- package/dist/components/panel/index.js +1 -1
- package/dist/components/panel/panel.js +1 -1
- package/dist/components/panel-trigger/atoms/button.js +1 -1
- package/dist/components/panel-trigger/atoms/icon.js +1 -1
- package/dist/components/panel-trigger/atoms/root.js +1 -1
- package/dist/components/panel-trigger/atoms/trigger-icons.js +1 -0
- package/dist/components/panel-trigger/panel-trigger-toolbar.js +1 -1
- package/dist/components/preferences/atoms/accordion.js +1 -1
- package/dist/components/preferences/atoms/root.js +1 -1
- package/dist/components/preferences/atoms/vendor-list.js +1 -0
- package/dist/components/preferences/index.js +1 -1
- package/dist/components/prompt/policy-actions.js +1 -1
- package/dist/components/shared/primitives/button.js +1 -1
- package/dist/components/shared/ui/accordion/accordion.js +1 -1
- package/dist/components/shared/ui/collapsible/collapsible.js +1 -1
- package/dist/components/shared/ui/logo.js +1 -1
- package/dist/components/shared/ui/preference-item/preference-item.js +1 -1
- package/dist/components/shared/ui/switch/switch.js +1 -1
- package/dist/components/shared/ui/tabs/tabs.js +1 -1
- package/dist/consent-gate.js +2 -0
- package/dist/consent-theme.js +1 -0
- package/dist/draft.js +1 -1
- package/dist/external-iab-context.js +1 -1
- package/dist/headless.js +1 -1
- package/dist/hooks/use-committed-ref.js +2 -0
- package/dist/hooks.js +1 -1
- package/dist/iab/styles.tw3.css +1 -41
- package/dist/iab-context.js +1 -1
- package/dist/index.js +1 -1
- package/dist/kernel-selector.js +1 -0
- package/dist/module-hooks/iframe-blocker.js +1 -1
- package/dist/module-hooks/network-blocker.js +1 -1
- package/dist/module-hooks/network-hold.js +2 -0
- package/dist/module-hooks/persistence.js +1 -1
- package/dist/panel.js +1 -1
- package/dist/preferences.js +1 -2
- package/dist/provider.js +1 -1
- package/dist/styles.tw3.css +1 -43
- package/dist/ui-save.js +1 -1
- package/dist/utils/deferred-module.js +2 -0
- package/dist/version.js +1 -1
- package/dist-types/aggregate-components.d.ts +2 -2
- package/dist-types/chunk-warming.d.ts +41 -8
- package/dist-types/component-hooks/use-headless-iab-consent-ui.d.ts +2 -2
- package/dist-types/components/consent-gate/atoms.d.ts +11 -0
- package/dist-types/components/consent-gate/consent-gate.d.ts +2 -0
- package/dist-types/components/consent-gate/index.d.ts +41 -0
- package/dist-types/components/{frame → consent-gate}/types.d.ts +7 -7
- package/dist-types/components/consent-preferences-link/consent-preferences-link.d.ts +1 -1
- package/dist-types/components/consent-preferences-link/index.d.ts +1 -1
- package/dist-types/components/iab-panel/atoms/purpose-item.d.ts +5 -2
- package/dist-types/components/iab-panel/atoms/stack-item.d.ts +7 -2
- package/dist-types/components/iab-panel/atoms/vendor-list.d.ts +1 -1
- package/dist-types/components/iab-panel/iab-panel.d.ts +1 -1
- package/dist-types/components/iab-panel/index.d.ts +25 -24
- package/dist-types/components/iab-prompt/index.d.ts +17 -17
- package/dist-types/components/panel/atoms/card.d.ts +4 -4
- package/dist-types/components/panel/atoms/overlay.d.ts +1 -1
- package/dist-types/components/panel/index.d.ts +8 -7
- package/dist-types/components/panel/panel.d.ts +3 -3
- package/dist-types/components/panel-link/index.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/button.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/icon.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/root.d.ts +2 -2
- package/dist-types/components/panel-trigger/atoms/toolbar.d.ts +2 -2
- package/dist-types/components/panel-trigger/atoms/trigger-icons.d.ts +20 -0
- package/dist-types/components/panel-trigger/index.d.ts +4 -4
- package/dist-types/components/panel-trigger/panel-trigger-toolbar.d.ts +1 -1
- package/dist-types/components/panel-trigger/panel-trigger.d.ts +9 -9
- package/dist-types/components/panel-trigger/types.d.ts +1 -1
- package/dist-types/components/preferences/atoms/accordion.d.ts +6 -4
- package/dist-types/components/preferences/atoms/button.d.ts +1 -1
- package/dist-types/components/preferences/atoms/footer.d.ts +1 -1
- package/dist-types/components/preferences/atoms/root.d.ts +1 -1
- package/dist-types/components/preferences/atoms/vendor-list.d.ts +23 -0
- package/dist-types/components/preferences/index.d.ts +14 -11
- package/dist-types/components/preferences/policy-actions.d.ts +2 -2
- package/dist-types/components/preferences/preferences.d.ts +1 -1
- package/dist-types/components/preferences/types.d.ts +1 -1
- package/dist-types/components/prompt/components.d.ts +3 -3
- package/dist-types/components/prompt/index.d.ts +11 -11
- package/dist-types/components/prompt/policy-actions.d.ts +2 -2
- package/dist-types/components/prompt/prompt.d.ts +1 -1
- package/dist-types/components/shared/policy-actions.d.ts +2 -2
- package/dist-types/components/shared/primitives/box.d.ts +1 -1
- package/dist-types/components/shared/primitives/button.d.ts +2 -2
- package/dist-types/components/shared/primitives/button.types.d.ts +1 -1
- package/dist-types/components/shared/ui/accordion/accordion.d.ts +3 -2
- package/dist-types/components/shared/ui/accordion/index.d.ts +2 -2
- package/dist-types/components/shared/ui/animated-collapse/index.d.ts +2 -2
- package/dist-types/components/shared/ui/branding.d.ts +1 -1
- package/dist-types/components/shared/ui/button/button.d.ts +1 -1
- package/dist-types/components/shared/ui/button/index.d.ts +2 -2
- package/dist-types/components/shared/ui/collapsible/collapsible.d.ts +1 -0
- package/dist-types/components/shared/ui/collapsible/index.d.ts +1 -1
- package/dist-types/components/shared/ui/dialog/index.d.ts +1 -1
- package/dist-types/components/shared/ui/logo.d.ts +0 -10
- package/dist-types/components/shared/ui/preference-item/index.d.ts +1 -1
- package/dist-types/components/shared/ui/preference-item/preference-item.d.ts +14 -0
- package/dist-types/components/shared/ui/switch/index.d.ts +2 -2
- package/dist-types/components/shared/ui/switch/switch.d.ts +2 -1
- package/dist-types/components/shared/ui/tabs/index.d.ts +1 -1
- package/dist-types/components/shared/ui/tabs/tabs.d.ts +1 -0
- package/dist-types/consent-gate.d.ts +1 -0
- package/dist-types/consent-theme.d.ts +38 -0
- package/dist-types/context/index.d.ts +3 -3
- package/dist-types/context/theme-context.d.ts +1 -1
- package/dist-types/draft.d.ts +96 -7
- package/dist-types/headless.d.ts +6 -7
- package/dist-types/hooks/use-committed-ref.d.ts +24 -0
- package/dist-types/hooks/use-headless-iab-consent-ui.d.ts +1 -1
- package/dist-types/hooks/use-iab-manager.d.ts +1 -1
- package/dist-types/hooks/use-theme.d.ts +1 -1
- package/dist-types/hooks.d.ts +30 -1
- package/dist-types/iab.d.ts +5 -5
- package/dist-types/index.d.ts +26 -25
- package/dist-types/kernel-selector.d.ts +66 -0
- package/dist-types/module-hooks/iframe-blocker.d.ts +27 -0
- package/dist-types/module-hooks/network-blocker.d.ts +23 -0
- package/dist-types/module-hooks/network-hold.d.ts +47 -0
- package/dist-types/module-hooks.d.ts +4 -4
- package/dist-types/panel-link.d.ts +1 -1
- package/dist-types/panel-trigger.d.ts +1 -1
- package/dist-types/panel.d.ts +13 -1
- package/dist-types/preferences.d.ts +12 -1
- package/dist-types/primitives/accordion.d.ts +1 -1
- package/dist-types/primitives/button.d.ts +1 -1
- package/dist-types/primitives/collapsible.d.ts +1 -1
- package/dist-types/primitives/dialog.d.ts +1 -1
- package/dist-types/primitives/preference-item.d.ts +1 -1
- package/dist-types/primitives/switch.d.ts +1 -1
- package/dist-types/primitives/tabs.d.ts +1 -1
- package/dist-types/primitives.d.ts +7 -7
- package/dist-types/prompt.d.ts +1 -1
- package/dist-types/provider.d.ts +62 -12
- package/dist-types/server/fetch-ssr-data.d.ts +1 -1
- package/dist-types/server/index.d.ts +5 -5
- package/dist-types/theme-provider.d.ts +2 -2
- package/dist-types/types/index.d.ts +3 -3
- package/dist-types/types/manager.d.ts +1 -1
- package/dist-types/types/theme/index.d.ts +1 -1
- package/dist-types/ui-config-context.d.ts +3 -1
- package/dist-types/ui-save.d.ts +21 -1
- package/dist-types/utils/deferred-module.d.ts +13 -0
- package/dist-types/utils/index.d.ts +4 -4
- package/dist-types/utils/merge-slot-props.d.ts +2 -2
- package/dist-types/utils/merge-styles.d.ts +1 -1
- package/dist-types/utils/theme-utils.d.ts +1 -1
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +9 -2
- package/docs/customization/overview.md +4 -3
- package/docs/customization/recipes.md +4 -2
- package/docs/customization/tokens.md +66 -3
- package/docs/frameworks/react/components/consent-dialog.md +46 -7
- package/docs/frameworks/react/components/{frame.md → consent-gate.md} +35 -31
- package/docs/frameworks/react/components/consent-manager-provider.md +35 -11
- package/docs/frameworks/react/components/consent-widget.md +48 -6
- package/docs/frameworks/react/concepts/consent-categories.md +38 -2
- package/docs/frameworks/react/hooks/{use-consent-manager/overview.md → overview.md} +7 -5
- package/docs/frameworks/react/iab/overview.md +121 -1
- package/docs/frameworks/react/network-blocker.md +146 -0
- package/docs/frameworks/react/script-loader.md +6 -0
- package/docs/frameworks/react/styling/overview.md +71 -22
- package/docs/guides/consent-state.md +327 -0
- package/docs/guides/deployment-modes.md +12 -0
- package/docs/guides/shared-consent-controls.md +158 -0
- package/docs/integrations/adobe-analytics.md +1 -1
- package/docs/integrations/ahrefs-analytics.md +1 -1
- package/docs/integrations/amplitude.md +1 -1
- package/docs/integrations/building-integrations.md +5 -0
- package/docs/integrations/clearbit.md +1 -1
- package/docs/integrations/cloudflare-web-analytics.md +1 -1
- package/docs/integrations/cloudflare-zaraz.md +399 -0
- package/docs/integrations/crisp.md +1 -1
- package/docs/integrations/databuddy.md +1 -1
- package/docs/integrations/fathom-analytics.md +1 -1
- package/docs/integrations/front-chat.md +322 -0
- package/docs/integrations/google-maps.md +21 -21
- package/docs/integrations/google-tag-manager.md +1 -1
- package/docs/integrations/google-tag.md +1 -1
- package/docs/integrations/granular-consent.md +210 -0
- package/docs/integrations/heap.md +1 -1
- package/docs/integrations/hightouch.md +1 -1
- package/docs/integrations/hotjar.md +1 -1
- package/docs/integrations/intercom.md +1 -1
- package/docs/integrations/linkedin-insights.md +1 -1
- package/docs/integrations/logrocket.md +1 -1
- package/docs/integrations/matomo-analytics.md +1 -1
- package/docs/integrations/meta-pixel.md +1 -1
- package/docs/integrations/microsoft-clarity.md +1 -1
- package/docs/integrations/microsoft-uet.md +1 -1
- package/docs/integrations/mixpanel-analytics.md +1 -1
- package/docs/integrations/one-dollar-stats.md +305 -0
- package/docs/integrations/openai-pixel.md +1 -1
- package/docs/integrations/overview.md +22 -18
- package/docs/integrations/pinterest-tag.md +321 -0
- package/docs/integrations/pirsch.md +1 -1
- package/docs/integrations/plausible-analytics.md +1 -1
- package/docs/integrations/posthog.md +1 -1
- package/docs/integrations/promptwatch.md +1 -1
- package/docs/integrations/reddit-pixel.md +1 -1
- package/docs/integrations/rudderstack.md +1 -1
- package/docs/integrations/rybbit-analytics.md +1 -1
- package/docs/integrations/segment.md +1 -1
- package/docs/integrations/snapchat-pixel.md +1 -1
- package/docs/integrations/tiktok-pixel.md +1 -1
- package/docs/integrations/umami-analytics.md +1 -1
- package/docs/integrations/vercel-analytics.md +1 -1
- package/docs/integrations/x-pixel.md +1 -1
- package/docs/integrations/youtube.md +27 -22
- package/docs/upgrade-v3.md +176 -1
- package/package.json +26 -16
- package/dist/component-hooks/use-manager.js +0 -2
- package/dist/components/frame/atoms.js +0 -1
- package/dist/components/frame/frame.js +0 -2
- package/dist/components/frame/index.js +0 -2
- package/dist/frame.js +0 -2
- package/dist-types/component-hooks/use-manager.d.ts +0 -40
- package/dist-types/components/frame/atoms.d.ts +0 -11
- package/dist-types/components/frame/frame.d.ts +0 -2
- package/dist-types/components/frame/index.d.ts +0 -24
- package/dist-types/frame.d.ts +0 -1
- package/readme.json +0 -48
- package/src/iab/styles.css +0 -11
- package/src/styles.css +0 -10
- /package/dist/components/{frame → consent-gate}/types.js +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Share consent controls across frameworks
|
|
3
|
+
description: Use the same c15t script lifecycle, external consent source, and
|
|
4
|
+
event controls in every framework.
|
|
5
|
+
group: guides
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Choose one consent authority
|
|
9
|
+
|
|
10
|
+
c15t owns script loading, consent gates, lifecycle callbacks, and optional cleanup
|
|
11
|
+
through its framework-independent core. React, Vue, Svelte, Astro, and the browser
|
|
12
|
+
client connect to that core. Next.js and TanStack Start use the React provider;
|
|
13
|
+
Nuxt uses Vue; SvelteKit uses Svelte. None requires Astro for these controls.
|
|
14
|
+
|
|
15
|
+
With c15t as the consent authority, keep your framework's hosted, self-hosted, or
|
|
16
|
+
offline setup. Offline mode keeps choices in the browser; a hosted backend can
|
|
17
|
+
store records. The script SDK and event dispatcher work with either mode.
|
|
18
|
+
|
|
19
|
+
To keep another CMP, provide a `consentSource`. It owns the banner, preferences,
|
|
20
|
+
records, expiration, privacy signals, and category mapping. c15t follows its
|
|
21
|
+
current permissions without creating a second choice record. Optional categories
|
|
22
|
+
start denied, including during SSR. An unavailable source or a failed read denies
|
|
23
|
+
them again. Initialize the CMP independently, or register its loader as an
|
|
24
|
+
explicitly early-loading script so it does not wait for its own consent.
|
|
25
|
+
|
|
26
|
+
The source contract is exported from `@c15t/core/runtime`:
|
|
27
|
+
|
|
28
|
+
```ts title="src/consent-source.ts — adapter skeleton"
|
|
29
|
+
import type { ExternalConsentSource } from 'c15t/runtime';
|
|
30
|
+
import { provider } from './existing-cmp';
|
|
31
|
+
|
|
32
|
+
export const consentSource: ExternalConsentSource = {
|
|
33
|
+
getPermissions: () => provider.getCategoryPermissions(),
|
|
34
|
+
subscribe: (notify) => provider.subscribe(notify),
|
|
35
|
+
openPreferences: () => provider.openPreferences(),
|
|
36
|
+
};
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`provider` is your application's adapter for the existing CMP, not a c15t export.
|
|
40
|
+
Map its categories to c15t's `measurement`, `marketing`, `functionality`, and
|
|
41
|
+
`experience` booleans. Missing categories are denied; `necessary` stays true.
|
|
42
|
+
Return `null` until the CMP is ready. `subscribe` must notify on initialization,
|
|
43
|
+
changes, withdrawal, and expiration, and return a function that removes listeners.
|
|
44
|
+
Keep browser access inside these functions so importing the adapter during SSR is safe.
|
|
45
|
+
|
|
46
|
+
If `subscribe` throws, c15t reports the failure through `callbacks.onError` and
|
|
47
|
+
continues startup with optional categories denied. The failed connection ignores
|
|
48
|
+
later notifications and does not forward preference requests. Recreate the owner
|
|
49
|
+
after the CMP is available to connect again.
|
|
50
|
+
|
|
51
|
+
## Pass the controls to your framework
|
|
52
|
+
|
|
53
|
+
The `consentSource` option is available at these registration points. Register your SDK configurations through the same owner's
|
|
54
|
+
`scripts` option. Do not create an additional runtime beside an existing provider.
|
|
55
|
+
|
|
56
|
+
| Framework | Registration point |
|
|
57
|
+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
58
|
+
| React | `ConsentProvider options={{ mode, consentSource, scripts }}` |
|
|
59
|
+
| Next.js / TanStack Start | `ConsentRoot options={{ consentSource }}` with `scripts` as a top-level prop; `ConsentProvider` also accepts the React options |
|
|
60
|
+
| Vue | `app.use(c15tVue, { consentSource, scripts })` |
|
|
61
|
+
| Nuxt | `app.config.ts` → `c15t: { consentSource, scripts }` |
|
|
62
|
+
| Svelte / SvelteKit | `ConsentManagerProvider` options or corresponding top-level props |
|
|
63
|
+
| Astro | `clientOptions.consentSource` |
|
|
64
|
+
| Browser client | `createConsentClient({ consentSource, scripts })` |
|
|
65
|
+
| Headless JavaScript / Solid | `createConsentRuntime({ mode, consentSource, scripts })` |
|
|
66
|
+
|
|
67
|
+
For example, a React client boundary can use the source directly:
|
|
68
|
+
|
|
69
|
+
```tsx title="src/Consent.tsx"
|
|
70
|
+
'use client';
|
|
71
|
+
|
|
72
|
+
import type { ReactNode } from 'react';
|
|
73
|
+
import { ConsentProvider, offline, useSetActiveUI } from 'c15t/react';
|
|
74
|
+
import { googleTagManager } from '@c15t/scripts/google-tag-manager';
|
|
75
|
+
import { consentSource } from './consent-source';
|
|
76
|
+
|
|
77
|
+
const mode = offline();
|
|
78
|
+
const scripts = [googleTagManager({ id: 'GTM-EXAMPLE' })];
|
|
79
|
+
|
|
80
|
+
function Preferences() {
|
|
81
|
+
const setActiveUI = useSetActiveUI();
|
|
82
|
+
return <button type="button" onClick={() => setActiveUI('dialog')}>Privacy settings</button>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function Consent({ children }: { children: ReactNode }) {
|
|
86
|
+
return (
|
|
87
|
+
<ConsentProvider options={{ mode, consentSource, scripts }}>
|
|
88
|
+
{children}
|
|
89
|
+
<Preferences />
|
|
90
|
+
</ConsentProvider>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Replace the container ID. `mode` remains required by the provider API, but an
|
|
96
|
+
external source bypasses c15t backend initialization and persistence. Omit c15t's
|
|
97
|
+
banner and dialog. Preference links, hooks, and `kernel.set.activeUI('dialog')`
|
|
98
|
+
delegate to the source. Preference-opening failures reach `callbacks.onError`;
|
|
99
|
+
`kernel.commands.save()` rejects instead of recording a second choice.
|
|
100
|
+
|
|
101
|
+
In Next.js, construct the source in the client boundary; do not pass functions
|
|
102
|
+
from a Server Component. Existing `ConsentRoot` state can stay serializable, but
|
|
103
|
+
c15t records do not establish external permissions. A client-owned
|
|
104
|
+
`ConsentProvider` avoids a redundant server consent fetch for external-only setups.
|
|
105
|
+
For Nuxt, use `app.config.ts` for the functions, not serialized public runtime
|
|
106
|
+
configuration; the module skips its consent fetch and record hydration when a
|
|
107
|
+
source is configured. Browser access remains deferred until mount.
|
|
108
|
+
|
|
109
|
+
Solid currently ships UI primitives, not a lifecycle provider. Create the core
|
|
110
|
+
runtime once, call `start()` from `onMount`, and `dispose()` from `onCleanup`.
|
|
111
|
+
Other frameworks' providers perform that lifecycle automatically. A provider given
|
|
112
|
+
an existing `runtime` borrows it: configure controls on the runtime owner, which
|
|
113
|
+
also owns starting and disposing it.
|
|
114
|
+
|
|
115
|
+
## Handle withdrawal and application events
|
|
116
|
+
|
|
117
|
+
When the source withdraws an optional category that was granted, c15t reloads
|
|
118
|
+
the page, as it does when a visitor revokes consent in c15t's own UI. Removing a
|
|
119
|
+
script element cannot stop JavaScript that already ran, so the reload starts a
|
|
120
|
+
page with only permitted code. The reload runs in the next task, after
|
|
121
|
+
synchronous consent callbacks and `onBeforeConsentRevocationReload`. Disposing
|
|
122
|
+
the owner cancels a pending reload.
|
|
123
|
+
|
|
124
|
+
c15t cannot tell a visitor's withdrawal from expiry or a reset in the CMP, so
|
|
125
|
+
any notification that turns off a granted category reloads. The CMP owns
|
|
126
|
+
persistence: store the new decision before notifying c15t, or the reloaded page
|
|
127
|
+
reads the old one. Set `reloadOnConsentRevoked: false` to handle withdrawal
|
|
128
|
+
yourself. c15t still updates gates and calls script consent callbacks.
|
|
129
|
+
|
|
130
|
+
`createEventDispatcher` from `@c15t/scripts/events` also has no framework dependency:
|
|
131
|
+
|
|
132
|
+
```ts title="src/events.ts — attach to an existing runtime"
|
|
133
|
+
import { createEventDispatcher } from '@c15t/scripts/events';
|
|
134
|
+
|
|
135
|
+
const events = createEventDispatcher({
|
|
136
|
+
scripts,
|
|
137
|
+
getSnapshot: () => runtime.kernel.getSnapshot(),
|
|
138
|
+
});
|
|
139
|
+
events.track('docs_search', { resultCount: 4 });
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Here `scripts` is the same configuration registered with the existing `runtime`.
|
|
143
|
+
For a provider-owned kernel, use that kernel's live `getSnapshot` instead. The
|
|
144
|
+
dispatcher sends only to configured integrations with supported event APIs when
|
|
145
|
+
measurement and the script's own consent condition allow it. It discards denied
|
|
146
|
+
events, isolates vendor failures, and deduplicates explicitly configured SPA
|
|
147
|
+
pageviews. It does not subscribe to a framework router: notify it from your
|
|
148
|
+
router's navigation hook. Use vendor-specific helpers for APIs outside the shared
|
|
149
|
+
event contract.
|
|
150
|
+
|
|
151
|
+
## Verify the integration
|
|
152
|
+
|
|
153
|
+
Test an undecided visitor, an existing grant, withdrawal, expiry, and a source
|
|
154
|
+
that cannot be read. Check that only permitted scripts execute, the preference
|
|
155
|
+
control opens the existing CMP, c15t does not render another banner or persist
|
|
156
|
+
another receipt, and unmounting removes the source listeners. Test your actual
|
|
157
|
+
CMP category mapping and tag-manager container; shared gates do not validate
|
|
158
|
+
those configurations or establish compliance by themselves.
|
|
@@ -196,7 +196,7 @@ clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)
|
|
|
196
196
|
Export the scripts from that module:
|
|
197
197
|
|
|
198
198
|
```ts title="src/c15t.client.ts"
|
|
199
|
-
import type { C15tClientOptionsExtension } from '
|
|
199
|
+
import type { C15tClientOptionsExtension } from 'c15t/astro';
|
|
200
200
|
import { scripts } from './consent-scripts';
|
|
201
201
|
|
|
202
202
|
export default { scripts } satisfies C15tClientOptionsExtension;
|
|
@@ -194,7 +194,7 @@ clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)
|
|
|
194
194
|
Export the scripts from that module:
|
|
195
195
|
|
|
196
196
|
```ts title="src/c15t.client.ts"
|
|
197
|
-
import type { C15tClientOptionsExtension } from '
|
|
197
|
+
import type { C15tClientOptionsExtension } from 'c15t/astro';
|
|
198
198
|
import { scripts } from './consent-scripts';
|
|
199
199
|
|
|
200
200
|
export default { scripts } satisfies C15tClientOptionsExtension;
|
|
@@ -194,7 +194,7 @@ clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)
|
|
|
194
194
|
Export the scripts from that module:
|
|
195
195
|
|
|
196
196
|
```ts title="src/c15t.client.ts"
|
|
197
|
-
import type { C15tClientOptionsExtension } from '
|
|
197
|
+
import type { C15tClientOptionsExtension } from 'c15t/astro';
|
|
198
198
|
import { scripts } from './consent-scripts';
|
|
199
199
|
|
|
200
200
|
export default { scripts } satisfies C15tClientOptionsExtension;
|
|
@@ -31,6 +31,11 @@ Replace the example URL and implement the vendor's initialization. This is a
|
|
|
31
31
|
loader template, not a functioning analytics SDK. The script stays blocked
|
|
32
32
|
while measurement permission is denied.
|
|
33
33
|
|
|
34
|
+
Add `vendor: 'example-analytics'` and declare the vendor in the runtime's
|
|
35
|
+
`vendors` option or in the backend manifest when visitors should be able to
|
|
36
|
+
turn this vendor off inside a granted category. See
|
|
37
|
+
[granular consent](./granular-consent.md).
|
|
38
|
+
|
|
34
39
|
## Define revocation deliberately
|
|
35
40
|
|
|
36
41
|
`onConsentChange` receives current permission information. Use it to update the
|
|
@@ -194,7 +194,7 @@ clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)
|
|
|
194
194
|
Export the scripts from that module:
|
|
195
195
|
|
|
196
196
|
```ts title="src/c15t.client.ts"
|
|
197
|
-
import type { C15tClientOptionsExtension } from '
|
|
197
|
+
import type { C15tClientOptionsExtension } from 'c15t/astro';
|
|
198
198
|
import { scripts } from './consent-scripts';
|
|
199
199
|
|
|
200
200
|
export default { scripts } satisfies C15tClientOptionsExtension;
|
|
@@ -194,7 +194,7 @@ clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)
|
|
|
194
194
|
Export the scripts from that module:
|
|
195
195
|
|
|
196
196
|
```ts title="src/c15t.client.ts"
|
|
197
|
-
import type { C15tClientOptionsExtension } from '
|
|
197
|
+
import type { C15tClientOptionsExtension } from 'c15t/astro';
|
|
198
198
|
import { scripts } from './consent-scripts';
|
|
199
199
|
|
|
200
200
|
export default { scripts } satisfies C15tClientOptionsExtension;
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Cloudflare Zaraz
|
|
3
|
+
description: Synchronize c15t permissions with Zaraz purposes while Cloudflare
|
|
4
|
+
manages your tools.
|
|
5
|
+
group: integrations
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Configure Zaraz before registering the bridge
|
|
9
|
+
|
|
10
|
+
This helper connects c15t to an existing Zaraz installation. It does not insert a
|
|
11
|
+
script, configure Cloudflare tools, or turn a standalone SDK into a server-side
|
|
12
|
+
integration. Configure each tool in Zaraz and remove its previous standalone
|
|
13
|
+
loader, including any duplicate `@c15t/scripts` helper.
|
|
14
|
+
|
|
15
|
+
In the Zaraz dashboard:
|
|
16
|
+
|
|
17
|
+
1. Enable Consent Management and create purposes for the categories you use.
|
|
18
|
+
2. Assign a purpose to every tool requiring permission. Zaraz tools without a
|
|
19
|
+
purpose bypass consent checks.
|
|
20
|
+
3. Disable automatic display of the Zaraz consent modal. c15t owns the UI.
|
|
21
|
+
4. Disable **Automatic Pageview Tracking**. Disable automatic SPA pageviews too
|
|
22
|
+
if your application will emit them itself.
|
|
23
|
+
5. Copy the purpose IDs into the mapping below. Every active purpose returned by `zaraz.consent.getAll()` and omitted
|
|
24
|
+
from the mapping is denied by this bridge. Register one bridge per application.
|
|
25
|
+
|
|
26
|
+
Zaraz keeps a separate consent cookie. Its automatic pageview can run before
|
|
27
|
+
c15t resolves the current permissions, using a grant from a previous visit.
|
|
28
|
+
Disabling that pageview and emitting it from `onReady` prevents this particular
|
|
29
|
+
startup race. Do not send other events before synchronization, and audit any
|
|
30
|
+
custom triggers that run independently. DOM-ready, timer or click triggers can
|
|
31
|
+
run with stale permissions before the bridge mounts. The bridge cannot undo
|
|
32
|
+
requests sent before it starts.
|
|
33
|
+
|
|
34
|
+
Cloudflare documents [purpose assignment](https://developers.cloudflare.com/zaraz/consent-management/)
|
|
35
|
+
and [automatic pageview settings](https://developers.cloudflare.com/zaraz/reference/settings/).
|
|
36
|
+
|
|
37
|
+
## Register the consent bridge
|
|
38
|
+
|
|
39
|
+
| Package manager | Command |
|
|
40
|
+
| :-------------- | :-------------------------- |
|
|
41
|
+
| npm | `npm install @c15t/scripts` |
|
|
42
|
+
| pnpm | `pnpm add @c15t/scripts` |
|
|
43
|
+
| yarn | `yarn add @c15t/scripts` |
|
|
44
|
+
| bun | `bun add @c15t/scripts` |
|
|
45
|
+
|
|
46
|
+
```ts title="src/consent-scripts.ts"
|
|
47
|
+
import { cloudflareZaraz } from '@c15t/scripts/cloudflare-zaraz';
|
|
48
|
+
|
|
49
|
+
// Zaraz provides this global after its loader runs.
|
|
50
|
+
declare const zaraz: { track: (event: string) => void };
|
|
51
|
+
|
|
52
|
+
export const scripts = [
|
|
53
|
+
cloudflareZaraz({
|
|
54
|
+
purposes: {
|
|
55
|
+
measurement: ['your-measurement-purpose-id'],
|
|
56
|
+
marketing: ['your-marketing-purpose-id'],
|
|
57
|
+
},
|
|
58
|
+
onReady: () => {
|
|
59
|
+
zaraz.track('Pageview');
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
];
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Use actual IDs from your dashboard, not the purpose names. A category may map to
|
|
66
|
+
several purposes, but a purpose cannot appear more than once. Empty mappings,
|
|
67
|
+
blank IDs and duplicate IDs throw during construction. Zaraz only returns purposes attached to enabled tools from `getAll()`. IDs absent
|
|
68
|
+
from that result cannot receive a grant; compare the mapping with
|
|
69
|
+
`zaraz.consent.getAll()` when troubleshooting.
|
|
70
|
+
|
|
71
|
+
Include the mapped categories in your c15t policy. The bridge reads effective
|
|
72
|
+
permissions, including policy restrictions, rather than treating every allowed
|
|
73
|
+
category as a recorded visitor choice.
|
|
74
|
+
|
|
75
|
+
For the shared registration examples below, keep Zaraz's own loader and its
|
|
76
|
+
configured dashboard tools. Remove duplicate standalone vendor loaders only.
|
|
77
|
+
For this integration, c15t owns permission synchronization and Zaraz owns tool
|
|
78
|
+
loading.
|
|
79
|
+
|
|
80
|
+
## Register the scripts
|
|
81
|
+
|
|
82
|
+
Complete your [framework quickstart](https://c15t.com/docs/frameworks) first. Keep its Inth
|
|
83
|
+
endpoint, policy, styles and consent UI. Remove the vendor's original script,
|
|
84
|
+
SDK initializer or tag-manager entry so c15t owns loading once.
|
|
85
|
+
|
|
86
|
+
The `scripts` export in `src/consent-scripts.ts` is a configuration, not an
|
|
87
|
+
initializer. Add it to your existing consent owner using the registration point
|
|
88
|
+
below. These are partial edits to that owner, not additional providers.
|
|
89
|
+
|
|
90
|
+
**Next.js**
|
|
91
|
+
|
|
92
|
+
Import the configuration into the client boundary from your router guide:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { ConsentRoot } from 'c15t/next';
|
|
96
|
+
import { scripts } from './consent-scripts';
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Keep the server-resolved `state` and shared `consentConfig` from your
|
|
100
|
+
router guide. Its manifest, init and save URLs stay in effect. Add
|
|
101
|
+
`scripts` as a top-level prop on the existing root:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
<ConsentRoot state={state} config={consentConfig} scripts={scripts}>
|
|
105
|
+
{children}
|
|
106
|
+
</ConsentRoot>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
For a Pages Router or static-export setup using `ConsentProvider`, add
|
|
110
|
+
`scripts` to its existing `options` instead. Keep the router-specific setup
|
|
111
|
+
from [Next.js script loading](https://c15t.com/docs/frameworks/next/script-loader).
|
|
112
|
+
|
|
113
|
+
**TanStack Start**
|
|
114
|
+
|
|
115
|
+
In your existing root route component, import the scripts alongside
|
|
116
|
+
`ConsentRoot`. Keep the server loader from the [TanStack Start quickstart](https://c15t.com/docs/frameworks/tanstack-start/quickstart).
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import { Outlet } from '@tanstack/react-router';
|
|
120
|
+
import { ConsentRoot } from 'c15t/tanstack-start';
|
|
121
|
+
import { scripts } from '../consent-scripts';
|
|
122
|
+
|
|
123
|
+
function Root() {
|
|
124
|
+
const state = Route.useLoaderData();
|
|
125
|
+
return (
|
|
126
|
+
<ConsentRoot state={state} backendURL={backendURL} initRoute={false} scripts={scripts}>
|
|
127
|
+
<Outlet />
|
|
128
|
+
{/* Keep your consent banner, dialog and preferences link here. */}
|
|
129
|
+
</ConsentRoot>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
This edits the existing route. `Route` and `backendURL` come from its setup;
|
|
135
|
+
keep the document shell and head components if they are part of your root.
|
|
136
|
+
`initRoute={false}` keeps the quickstart's direct-backend initialization.
|
|
137
|
+
If your app mounts a consent server route, retain its existing `initRoute`
|
|
138
|
+
instead. Do not return script callbacks from a server function or route loader.
|
|
139
|
+
|
|
140
|
+
**React**
|
|
141
|
+
|
|
142
|
+
Import the scripts into your existing provider component:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { ConsentProvider } from 'c15t/react';
|
|
146
|
+
import { scripts } from './consent-scripts';
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Keep the existing options and add `scripts`:
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
<ConsentProvider options={{ ...consentOptions, scripts }}>
|
|
153
|
+
{children}
|
|
154
|
+
</ConsentProvider>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Here `consentOptions` is your existing configuration, including
|
|
158
|
+
`mode: hosted({ url: backendURL })`. Keep the banner, dialog and preferences
|
|
159
|
+
link inside the provider. See [React script loading](../frameworks/react/script-loader.md).
|
|
160
|
+
|
|
161
|
+
**Nuxt**
|
|
162
|
+
|
|
163
|
+
Attach one loader from the root `app.vue`, after the Nuxt module has
|
|
164
|
+
started its browser runtime. This keeps vendor callbacks in application code rather
|
|
165
|
+
than serialized `nuxt.config.ts` runtime configuration.
|
|
166
|
+
|
|
167
|
+
```vue title="app/app.vue"
|
|
168
|
+
<script setup lang="ts">
|
|
169
|
+
import { onUnmounted } from 'vue';
|
|
170
|
+
import { createScriptLoader } from 'c15t/modules/script-loader';
|
|
171
|
+
import { scripts } from '../src/consent-scripts';
|
|
172
|
+
|
|
173
|
+
const nuxtApp = useNuxtApp();
|
|
174
|
+
const kernel = useConsentKernel();
|
|
175
|
+
let loader: ReturnType<typeof createScriptLoader> | undefined;
|
|
176
|
+
|
|
177
|
+
const removeMountedHook = nuxtApp.hook('app:mounted', () => {
|
|
178
|
+
loader = createScriptLoader({ kernel, scripts });
|
|
179
|
+
});
|
|
180
|
+
onUnmounted(() => {
|
|
181
|
+
removeMountedHook();
|
|
182
|
+
loader?.dispose();
|
|
183
|
+
});
|
|
184
|
+
</script>
|
|
185
|
+
|
|
186
|
+
<template>
|
|
187
|
+
<ConsentRoot />
|
|
188
|
+
<NuxtPage />
|
|
189
|
+
</template>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Merge the setup code into your root and retain its footer and preferences
|
|
193
|
+
link. `useConsentKernel` is auto-imported by the c15t Nuxt module. Adjust the
|
|
194
|
+
relative script import if your `app.vue` is at the project root. This loader
|
|
195
|
+
waits until the module has applied browser persistence and privacy signals,
|
|
196
|
+
then reads the current snapshot and observes future changes. Do not also register these scripts
|
|
197
|
+
in another loader. See the [Nuxt quickstart](https://c15t.com/docs/frameworks/nuxt/quickstart).
|
|
198
|
+
|
|
199
|
+
**Vue**
|
|
200
|
+
|
|
201
|
+
Use the kernel already provided by the Vue plugin. Merge this setup into
|
|
202
|
+
`App.vue`, whose lifetime covers the application:
|
|
203
|
+
|
|
204
|
+
```vue title="src/App.vue"
|
|
205
|
+
<script setup lang="ts">
|
|
206
|
+
import { onMounted, onUnmounted } from 'vue';
|
|
207
|
+
import { createScriptLoader } from 'c15t/modules/script-loader';
|
|
208
|
+
import { useConsentKernel } from 'c15t/vue/vue-plugin';
|
|
209
|
+
import ConsentRoot from 'c15t/vue/consent-root';
|
|
210
|
+
import { scripts } from './consent-scripts';
|
|
211
|
+
|
|
212
|
+
const kernel = useConsentKernel();
|
|
213
|
+
let loader: ReturnType<typeof createScriptLoader> | undefined;
|
|
214
|
+
|
|
215
|
+
onMounted(() => {
|
|
216
|
+
loader = createScriptLoader({ kernel, scripts });
|
|
217
|
+
});
|
|
218
|
+
onUnmounted(() => loader?.dispose());
|
|
219
|
+
</script>
|
|
220
|
+
|
|
221
|
+
<template>
|
|
222
|
+
<ConsentRoot />
|
|
223
|
+
<main>Your application</main>
|
|
224
|
+
</template>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Keep your existing page content and preferences link. The plugin still owns
|
|
228
|
+
the kernel and persistence; this component owns only the vendor loader.
|
|
229
|
+
Do not register the same scripts in plugin configuration as well. See the
|
|
230
|
+
[Vue quickstart](https://c15t.com/docs/frameworks/vue/quickstart).
|
|
231
|
+
|
|
232
|
+
**Astro**
|
|
233
|
+
|
|
234
|
+
Point the existing Astro integration at a client module. Keep its `mode`,
|
|
235
|
+
`ui` and framework integration from the [Astro quickstart](https://c15t.com/docs/frameworks/astro/quickstart).
|
|
236
|
+
Import `fileURLToPath` in your Astro configuration:
|
|
237
|
+
|
|
238
|
+
```js title="astro.config.mjs"
|
|
239
|
+
import { fileURLToPath } from 'node:url';
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Add this option to the existing `c15t({ ... })` call. Resolve the path from
|
|
243
|
+
the configuration file because Astro injects the import into a virtual module:
|
|
244
|
+
|
|
245
|
+
```js
|
|
246
|
+
clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)),
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Export the scripts from that module:
|
|
250
|
+
|
|
251
|
+
```ts title="src/c15t.client.ts"
|
|
252
|
+
import type { C15tClientOptionsExtension } from 'c15t/astro';
|
|
253
|
+
import { scripts } from './consent-scripts';
|
|
254
|
+
|
|
255
|
+
export default { scripts } satisfies C15tClientOptionsExtension;
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
The integration passes this extension to its shared browser runtime. Vendor
|
|
259
|
+
helpers contain callbacks, so do not put them in the serialized `scripts`
|
|
260
|
+
option in `astro.config.mjs`. Keep one runtime across consent islands and
|
|
261
|
+
`ClientRouter` navigation.
|
|
262
|
+
|
|
263
|
+
**Svelte**
|
|
264
|
+
|
|
265
|
+
Import the scripts in the component that owns your existing provider and
|
|
266
|
+
pass them as a top-level prop:
|
|
267
|
+
|
|
268
|
+
```svelte title="src/App.svelte"
|
|
269
|
+
<script lang="ts">
|
|
270
|
+
import { ConsentManagerProvider, hosted } from '@c15t/svelte';
|
|
271
|
+
import { scripts } from './consent-scripts';
|
|
272
|
+
|
|
273
|
+
const backendURL = import.meta.env.VITE_C15T_BACKEND_URL;
|
|
274
|
+
if (!backendURL) throw new Error('Set VITE_C15T_BACKEND_URL');
|
|
275
|
+
const mode = hosted({ url: backendURL });
|
|
276
|
+
</script>
|
|
277
|
+
|
|
278
|
+
<ConsentManagerProvider {mode} {scripts}>
|
|
279
|
+
<!-- Keep your application, consent UI and preferences link here. -->
|
|
280
|
+
</ConsentManagerProvider>
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Retain the styles and consent UI from the [Svelte quickstart](https://c15t.com/docs/frameworks/svelte/quickstart).
|
|
284
|
+
The provider owns the loader and disposes it on unmount.
|
|
285
|
+
|
|
286
|
+
**SvelteKit**
|
|
287
|
+
|
|
288
|
+
Add the scripts to the existing root layout provider. Keep the server load
|
|
289
|
+
and its serializable prefetch data from the [SvelteKit quickstart](https://c15t.com/docs/frameworks/sveltekit/quickstart).
|
|
290
|
+
|
|
291
|
+
```svelte title="src/routes/+layout.svelte"
|
|
292
|
+
<script lang="ts">
|
|
293
|
+
import { ConsentManagerProvider, hosted } from '@c15t/svelte';
|
|
294
|
+
import { scripts } from '../consent-scripts';
|
|
295
|
+
|
|
296
|
+
let { children, data } = $props();
|
|
297
|
+
const mode = hosted({ url: data.backendURL });
|
|
298
|
+
</script>
|
|
299
|
+
|
|
300
|
+
<ConsentManagerProvider {mode} {scripts} prefetch={data.prefetch}>
|
|
301
|
+
{@render children()}
|
|
302
|
+
<!-- Keep your consent UI and preferences link here. -->
|
|
303
|
+
</ConsentManagerProvider>
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Import vendor helpers in the layout component, not in `+layout.server.ts`.
|
|
307
|
+
For static hosting, keep your browser-only `mode` setup and omit request
|
|
308
|
+
prefetch; the `scripts` prop stays the same. If you pass an externally owned
|
|
309
|
+
`runtime` to the provider, register scripts when creating that runtime instead.
|
|
310
|
+
|
|
311
|
+
**JavaScript**
|
|
312
|
+
|
|
313
|
+
Attach the loader to your existing kernel before calling
|
|
314
|
+
`kernel.commands.init()`:
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
import { createScriptLoader } from 'c15t/modules/script-loader';
|
|
318
|
+
import { scripts } from './consent-scripts';
|
|
319
|
+
|
|
320
|
+
const loader = createScriptLoader({ kernel, scripts });
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Call `loader.dispose()` when that application instance is destroyed.
|
|
324
|
+
`kernel` is the hosted kernel from your quickstart. A provider-owned kernel
|
|
325
|
+
already has a loader; do not attach a second one. See
|
|
326
|
+
[JavaScript script loading](https://c15t.com/docs/frameworks/javascript/script-loader).
|
|
327
|
+
|
|
328
|
+
## Loading and updates
|
|
329
|
+
|
|
330
|
+
The helper returns an `alwaysLoad`, `callbackOnly` configuration with category
|
|
331
|
+
`necessary`. This lets consent synchronization run for every visitor. It does
|
|
332
|
+
not make the downstream analytics or advertising tools necessary.
|
|
333
|
+
|
|
334
|
+
Zaraz normally injects its own loader. If auto-injection is disabled, install
|
|
335
|
+
[Zaraz manually](https://developers.cloudflare.com/zaraz/advanced/load-zaraz-manually/)
|
|
336
|
+
once. The bridge supports either loading order: an already-ready API is updated
|
|
337
|
+
immediately; otherwise it waits for `zarazConsentAPIReady` and applies the latest
|
|
338
|
+
c15t permissions. No polling is used.
|
|
339
|
+
|
|
340
|
+
On a change, the bridge calls `zaraz.consent.set()` before
|
|
341
|
+
`zaraz.consent.sendQueuedEvents()`. It flushes Zaraz's queued pageviews only when
|
|
342
|
+
a purpose changes from denied to allowed. Revocation updates purposes to false
|
|
343
|
+
and does not flush events. Repeated identical permissions do not rewrite the
|
|
344
|
+
Zaraz cookie. `onReady` runs once after the first successful synchronization,
|
|
345
|
+
including when all optional purposes are denied. A pageview sent there remains
|
|
346
|
+
subject to Zaraz's purpose checks.
|
|
347
|
+
|
|
348
|
+
| Option | Default | Behavior |
|
|
349
|
+
| ------------------ | -------- | ---------------------------------------------------------------------------- |
|
|
350
|
+
| `purposes` | Required | Maps categories to Zaraz purpose IDs; unmapped purposes are denied |
|
|
351
|
+
| `hideBuiltInModal` | `true` | Hides the currently visible modal; also disable auto-display in Cloudflare |
|
|
352
|
+
| `sendQueuedEvents` | `true` | Replays Zaraz's queued pageviews after new grants |
|
|
353
|
+
| `onReady` | Unset | Runs after initial permission synchronization |
|
|
354
|
+
| `onError` | Unset | Receives synchronization errors so the application can report or handle them |
|
|
355
|
+
|
|
356
|
+
If a Zaraz API call throws, `onReady` does not run until synchronization
|
|
357
|
+
succeeds. Use `onError(error)` to report the failure and prevent application
|
|
358
|
+
events from relying on permissions that were not applied. The bridge retries
|
|
359
|
+
with the latest permissions on the next consent update or readiness event;
|
|
360
|
+
it does not poll or schedule automatic retries. Readiness retries remain
|
|
361
|
+
registered when `onError` is omitted and an error reaches the loader debug hook. A failed queued-event replay
|
|
362
|
+
remains pending until synchronization succeeds while that purpose is still
|
|
363
|
+
allowed. Revoking the purpose cancels its pending replay. Zaraz can partially
|
|
364
|
+
process a queue before throwing, so retries cannot guarantee exactly-once delivery. Without `onError`, synchronous
|
|
365
|
+
failures reach the script loader's debug events and readiness-event failures
|
|
366
|
+
reach the browser's error handler. A failed revocation can leave the previous
|
|
367
|
+
Zaraz grant in place.
|
|
368
|
+
|
|
369
|
+
If the bridge starts before saved consent or policy resolution is available,
|
|
370
|
+
it applies the kernel's current effective permissions and updates them when
|
|
371
|
+
initialization completes. Pass restored state during setup when available.
|
|
372
|
+
The bridge does not force a denial when the kernel already permits a purpose.
|
|
373
|
+
|
|
374
|
+
Set `sendQueuedEvents: false` if your application deliberately discards
|
|
375
|
+
pre-consent pageviews. Send subsequent route events only after readiness and
|
|
376
|
+
avoid combining manual route events with Zaraz's automatic SPA pageviews.
|
|
377
|
+
|
|
378
|
+
Removing or replacing the configuration, or disposing its loader, detaches the
|
|
379
|
+
readiness listener. Disposal does not revoke consent, clear vendor storage, or
|
|
380
|
+
stop a tool that has already initialized. Save the denied permissions before
|
|
381
|
+
teardown when revocation is required. Zaraz controls subsequent tool execution;
|
|
382
|
+
test vendor-specific behavior for scripts with their own ongoing activity.
|
|
383
|
+
|
|
384
|
+
## Verify the configured tools
|
|
385
|
+
|
|
386
|
+
Use a test environment with isolated destinations. Check a first visit, a return
|
|
387
|
+
visit with stale Zaraz grants, measurement-only acceptance, marketing-only
|
|
388
|
+
acceptance, rejection, and revocation. Inspect both `zaraz.consent.getAll()` and
|
|
389
|
+
actual tool activity. An updated consent object alone does not prove that a
|
|
390
|
+
misconfigured tool stopped sending data.
|
|
391
|
+
|
|
392
|
+
This integration maps c15t categories to Zaraz purposes. It does not translate
|
|
393
|
+
IAB TCF vendor and purpose choices or replace Zaraz's separate TCF configuration.
|
|
394
|
+
|
|
395
|
+
[Cloudflare Web Analytics](./cloudflare-web-analytics.md) is a
|
|
396
|
+
separate analytics product with its own loader. Zaraz manages multiple tools,
|
|
397
|
+
which can have different consent requirements and execution costs. Moving a
|
|
398
|
+
tool to Zaraz can reduce browser work, but this bridge alone does not establish
|
|
399
|
+
a performance improvement for that tool.
|
|
@@ -194,7 +194,7 @@ clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)
|
|
|
194
194
|
Export the scripts from that module:
|
|
195
195
|
|
|
196
196
|
```ts title="src/c15t.client.ts"
|
|
197
|
-
import type { C15tClientOptionsExtension } from '
|
|
197
|
+
import type { C15tClientOptionsExtension } from 'c15t/astro';
|
|
198
198
|
import { scripts } from './consent-scripts';
|
|
199
199
|
|
|
200
200
|
export default { scripts } satisfies C15tClientOptionsExtension;
|
|
@@ -200,7 +200,7 @@ clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)
|
|
|
200
200
|
Export the scripts from that module:
|
|
201
201
|
|
|
202
202
|
```ts title="src/c15t.client.ts"
|
|
203
|
-
import type { C15tClientOptionsExtension } from '
|
|
203
|
+
import type { C15tClientOptionsExtension } from 'c15t/astro';
|
|
204
204
|
import { scripts } from './consent-scripts';
|
|
205
205
|
|
|
206
206
|
export default { scripts } satisfies C15tClientOptionsExtension;
|
|
@@ -194,7 +194,7 @@ clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)
|
|
|
194
194
|
Export the scripts from that module:
|
|
195
195
|
|
|
196
196
|
```ts title="src/c15t.client.ts"
|
|
197
|
-
import type { C15tClientOptionsExtension } from '
|
|
197
|
+
import type { C15tClientOptionsExtension } from 'c15t/astro';
|
|
198
198
|
import { scripts } from './consent-scripts';
|
|
199
199
|
|
|
200
200
|
export default { scripts } satisfies C15tClientOptionsExtension;
|