@c15t/nextjs 2.2.1 → 3.0.0-alpha.1
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 +103 -142
- package/README.md +4 -4
- package/dist/api.js +1 -0
- package/dist/config.js +1 -0
- package/dist/devtools.js +2 -0
- package/dist/headers.js +1 -0
- package/dist/iab/styles.css +1 -1
- package/dist/iab/styles.tw3.css +27 -19
- package/dist/index.js +1 -1
- package/dist/middleware.js +1 -0
- package/dist/node-bridge.js +1 -0
- package/dist/pages.js +1 -0
- package/dist/proxy.js +1 -0
- package/dist/root.js +2 -0
- package/dist/server.js +1 -0
- package/dist/static.js +1 -0
- package/dist/styles.css +1 -1
- package/dist/styles.tw3.css +67 -29
- package/dist/version.js +1 -1
- package/dist-types/api.d.ts +88 -0
- package/dist-types/config.d.ts +110 -0
- package/dist-types/devtools.d.ts +1 -0
- package/dist-types/headers.d.ts +4 -0
- package/dist-types/index.d.ts +28 -10
- package/dist-types/middleware.d.ts +15 -0
- package/dist-types/node-bridge.d.ts +57 -0
- package/dist-types/pages.d.ts +88 -0
- package/dist-types/proxy.d.ts +34 -0
- package/dist-types/root.d.ts +92 -0
- package/dist-types/server.d.ts +164 -0
- package/dist-types/static.d.ts +42 -0
- package/dist-types/types.d.ts +5 -36
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +103 -142
- package/docs/assets/v3/brand-bar.png +0 -0
- package/docs/assets/v3/brand-card.png +0 -0
- package/docs/assets/v3/choice-wall.png +0 -0
- package/docs/assets/v3/mobile-card.png +0 -0
- package/docs/assets/v3/preferences.png +0 -0
- package/docs/customization/overview.md +45 -0
- package/docs/customization/recipes.md +79 -0
- package/docs/customization/slots.md +55 -0
- package/docs/customization/tokens.md +76 -0
- package/docs/customization/translations.md +49 -0
- package/docs/frameworks/next/api-reference/data-fetching.md +416 -0
- package/docs/frameworks/next/app-router.md +403 -0
- package/docs/frameworks/next/client-side.md +118 -0
- package/docs/frameworks/next/components/consent-banner.md +251 -211
- package/docs/frameworks/next/components/consent-dialog-link.md +96 -35
- package/docs/frameworks/next/components/consent-dialog-trigger.md +74 -149
- package/docs/frameworks/next/components/consent-dialog.md +189 -134
- package/docs/frameworks/next/components/consent-manager-provider.md +68 -318
- package/docs/frameworks/next/components/consent-widget.md +172 -114
- package/docs/frameworks/next/components/dev-tools.md +199 -40
- package/docs/frameworks/next/components/frame.md +137 -42
- package/docs/frameworks/next/concepts/consent-categories.md +24 -89
- package/docs/frameworks/next/concepts/policy-presets.md +142 -0
- package/docs/frameworks/next/content-security-policy.md +189 -0
- package/docs/frameworks/next/data-fetching.md +74 -0
- package/docs/frameworks/next/geography-headers.md +251 -0
- package/docs/frameworks/next/headless.md +95 -185
- package/docs/frameworks/next/hooks/use-consent-manager/overview.md +42 -163
- package/docs/frameworks/next/iab/overview.md +37 -107
- package/docs/frameworks/next/optimization.md +158 -194
- package/docs/frameworks/next/pages-router.md +296 -0
- package/docs/frameworks/next/quickstart.md +31 -132
- package/docs/frameworks/next/script-loader.md +140 -465
- package/docs/frameworks/next/server-side.md +97 -130
- package/docs/frameworks/next/static-export.md +164 -0
- package/docs/frameworks/next/styling/overview.md +174 -248
- package/docs/frameworks/next/troubleshooting.md +134 -144
- package/docs/guides/consent-state.md +60 -0
- package/docs/guides/data-fetching.md +163 -0
- package/docs/guides/deployment-modes.md +63 -0
- package/docs/guides/troubleshooting.md +68 -0
- package/docs/guides/verify-consent.md +62 -0
- package/docs/integrations/adobe-analytics.md +239 -105
- package/docs/integrations/ahrefs-analytics.md +238 -104
- package/docs/integrations/amplitude.md +219 -157
- package/docs/integrations/building-integrations.md +32 -224
- package/docs/integrations/clear-on-revocation.md +167 -0
- package/docs/integrations/clearbit.md +247 -86
- package/docs/integrations/cloudflare-web-analytics.md +250 -84
- package/docs/integrations/crisp.md +251 -97
- package/docs/integrations/databuddy.md +259 -153
- package/docs/integrations/fathom-analytics.md +239 -96
- package/docs/integrations/google-maps.md +328 -207
- package/docs/integrations/google-tag-manager.md +248 -96
- package/docs/integrations/google-tag.md +261 -90
- package/docs/integrations/heap.md +222 -149
- package/docs/integrations/hightouch.md +225 -131
- package/docs/integrations/hotjar.md +239 -90
- package/docs/integrations/intercom.md +239 -98
- package/docs/integrations/linkedin-insights.md +243 -113
- package/docs/integrations/logrocket.md +241 -123
- package/docs/integrations/matomo-analytics.md +256 -111
- package/docs/integrations/meta-pixel.md +197 -324
- package/docs/integrations/microsoft-clarity.md +233 -114
- package/docs/integrations/microsoft-uet.md +245 -110
- package/docs/integrations/mixpanel-analytics.md +252 -87
- package/docs/integrations/openai-pixel.md +441 -0
- package/docs/integrations/overview.md +95 -133
- package/docs/integrations/pirsch.md +249 -96
- package/docs/integrations/plausible-analytics.md +241 -100
- package/docs/integrations/posthog.md +353 -214
- package/docs/integrations/promptwatch.md +251 -81
- package/docs/integrations/reddit-pixel.md +226 -173
- package/docs/integrations/rudderstack.md +244 -187
- package/docs/integrations/rybbit-analytics.md +244 -91
- package/docs/integrations/segment.md +238 -92
- package/docs/integrations/snapchat-pixel.md +240 -110
- package/docs/integrations/tiktok-pixel.md +249 -81
- package/docs/integrations/umami-analytics.md +242 -95
- package/docs/integrations/vercel-analytics.md +242 -90
- package/docs/integrations/x-pixel.md +238 -104
- package/docs/integrations/youtube.md +354 -142
- package/docs/upgrade-v3.md +334 -0
- package/iab/styles.css +1 -1
- package/iab/styles.tw3.css +1 -1
- package/package.json +106 -65
- package/readme.json +3 -3
- package/src/iab/styles.css +1 -1
- package/src/iab/styles.tw3.css +1 -1
- package/src/styles.css +1 -1
- package/src/styles.tw3.css +1 -1
- package/styles.css +1 -1
- package/styles.tw3.css +1 -1
- package/client/components/consent-dialog-link.js +0 -3
- package/client/components/integrations.js +0 -3
- package/dist/components/integrations/index.cjs +0 -1
- package/dist/components/integrations/index.js +0 -1
- package/dist/headless.cjs +0 -1
- package/dist/index.cjs +0 -1
- package/dist/libs/browser-initial-data.cjs +0 -1
- package/dist/libs/browser-initial-data.js +0 -1
- package/dist/libs/initial-data.cjs +0 -1
- package/dist/libs/initial-data.js +0 -1
- package/dist/types.cjs +0 -1
- package/dist/version.cjs +0 -1
- package/dist-types/components/integrations/index.d.ts +0 -1
- package/dist-types/libs/browser-initial-data.d.ts +0 -9
- package/dist-types/libs/initial-data.d.ts +0 -33
- package/docs/frameworks/next/building-headless-components.md +0 -379
- package/docs/frameworks/next/callbacks.md +0 -186
- package/docs/frameworks/next/concepts/client-modes.md +0 -177
- package/docs/frameworks/next/concepts/consent-models.md +0 -117
- package/docs/frameworks/next/concepts/cookie-management.md +0 -122
- package/docs/frameworks/next/concepts/glossary.md +0 -24
- package/docs/frameworks/next/concepts/initialization-flow.md +0 -149
- package/docs/frameworks/next/concepts/policy-packs.md +0 -230
- package/docs/frameworks/next/hooks/use-color-scheme.md +0 -41
- package/docs/frameworks/next/hooks/use-consent-manager/checking-consent.md +0 -96
- package/docs/frameworks/next/hooks/use-consent-manager/location-info.md +0 -97
- package/docs/frameworks/next/hooks/use-consent-manager/setting-consent.md +0 -94
- package/docs/frameworks/next/hooks/use-draggable.md +0 -59
- package/docs/frameworks/next/hooks/use-focus-trap.md +0 -42
- package/docs/frameworks/next/hooks/use-reduced-motion.md +0 -37
- package/docs/frameworks/next/hooks/use-ssr-status.md +0 -32
- package/docs/frameworks/next/hooks/use-text-direction.md +0 -50
- package/docs/frameworks/next/hooks/use-translations.md +0 -55
- package/docs/frameworks/next/iab/consent-banner.md +0 -91
- package/docs/frameworks/next/iab/consent-dialog.md +0 -129
- package/docs/frameworks/next/iab/use-gvl-data.md +0 -21
- package/docs/frameworks/next/iframe-blocking.md +0 -106
- package/docs/frameworks/next/internationalization.md +0 -207
- package/docs/frameworks/next/network-blocker.md +0 -140
- package/docs/frameworks/next/policy-packs.md +0 -248
- package/docs/frameworks/next/styling/classnames.md +0 -94
- package/docs/frameworks/next/styling/color-scheme.md +0 -84
- package/docs/frameworks/next/styling/css-variables.md +0 -53
- package/docs/frameworks/next/styling/slots.md +0 -94
- package/docs/frameworks/next/styling/tailwind.md +0 -137
- package/docs/frameworks/next/styling/tokens.md +0 -156
- package/docs/shared/concepts/client-modes.md +0 -103
- package/docs/shared/concepts/consent-categories.md +0 -41
- package/docs/shared/concepts/consent-models.md +0 -72
- package/docs/shared/concepts/cookie-management.md +0 -88
- package/docs/shared/concepts/glossary.md +0 -24
- package/docs/shared/concepts/initialization-flow.md +0 -105
- package/docs/shared/concepts/policy-packs.md +0 -225
- package/docs/shared/react/components/consent-banner.md +0 -242
- package/docs/shared/react/components/consent-dialog-link.md +0 -45
- package/docs/shared/react/components/consent-dialog-trigger.md +0 -185
- package/docs/shared/react/components/consent-dialog.md +0 -119
- package/docs/shared/react/components/consent-manager-provider.md +0 -225
- package/docs/shared/react/components/consent-widget.md +0 -121
- package/docs/shared/react/components/dev-tools.md +0 -81
- package/docs/shared/react/components/frame.md +0 -52
- package/docs/shared/react/guides/building-headless-components.md +0 -110
- package/docs/shared/react/guides/callbacks.md +0 -89
- package/docs/shared/react/guides/headless.md +0 -31
- package/docs/shared/react/guides/iframe-blocking.md +0 -65
- package/docs/shared/react/guides/internationalization.md +0 -123
- package/docs/shared/react/guides/network-blocker.md +0 -72
- package/docs/shared/react/guides/optimization.md +0 -44
- package/docs/shared/react/guides/policy-packs.md +0 -173
- package/docs/shared/react/guides/script-loader.md +0 -311
- package/docs/shared/react/hooks/use-color-scheme.md +0 -31
- package/docs/shared/react/hooks/use-consent-manager/checking-consent.md +0 -95
- package/docs/shared/react/hooks/use-consent-manager/location-info.md +0 -96
- package/docs/shared/react/hooks/use-consent-manager/overview.md +0 -74
- package/docs/shared/react/hooks/use-consent-manager/setting-consent.md +0 -93
- package/docs/shared/react/hooks/use-draggable.md +0 -30
- package/docs/shared/react/hooks/use-focus-trap.md +0 -20
- package/docs/shared/react/hooks/use-reduced-motion.md +0 -33
- package/docs/shared/react/hooks/use-ssr-status.md +0 -16
- package/docs/shared/react/hooks/use-text-direction.md +0 -38
- package/docs/shared/react/hooks/use-translations.md +0 -15
- package/docs/shared/react/iab/consent-banner.md +0 -60
- package/docs/shared/react/iab/consent-dialog.md +0 -76
- package/docs/shared/react/iab/overview.md +0 -80
- package/docs/shared/react/iab/use-gvl-data.md +0 -21
- package/docs/shared/react/styling/classnames.md +0 -93
- package/docs/shared/react/styling/color-scheme.md +0 -35
- package/docs/shared/react/styling/css-variables.md +0 -53
- package/docs/shared/react/styling/overview.md +0 -261
- package/docs/shared/react/styling/slots.md +0 -93
- package/docs/shared/react/styling/stylesheet-entrypoint.md +0 -8
- package/docs/shared/react/styling/tailwind.md +0 -88
- package/docs/shared/react/styling/tokens.md +0 -155
- package/docs/shared/troubleshooting.md +0 -82
|
@@ -1,239 +1,47 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
3
|
-
description:
|
|
4
|
-
|
|
5
|
-
scripts in c15t.
|
|
2
|
+
title: Custom integrations
|
|
3
|
+
description: Define loading, initialization and consent-change behavior for a
|
|
4
|
+
vendor without a helper.
|
|
6
5
|
group: integrations
|
|
7
6
|
---
|
|
8
|
-
If you cannot find a prebuilt integration in [`@c15t/scripts`](/docs/integrations), you have two good options:
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
2. Build a reusable manifest-backed integration helper.
|
|
8
|
+
## Start with a script configuration
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
### One-off app script
|
|
18
|
-
|
|
19
|
-
Use a raw `Script` when:
|
|
20
|
-
|
|
21
|
-
* the integration is only used in one app
|
|
22
|
-
* the vendor setup is small
|
|
23
|
-
* you do not need to publish or share the helper
|
|
24
|
-
|
|
25
|
-
```ts
|
|
26
|
-
import type { Script } from 'c15t';
|
|
27
|
-
|
|
28
|
-
export function acmeAnalytics(siteId: string): Script {
|
|
29
|
-
return {
|
|
30
|
-
id: 'acme-analytics',
|
|
31
|
-
src: `https://cdn.acme.com/analytics.js?site=${siteId}`,
|
|
32
|
-
category: 'measurement',
|
|
33
|
-
onBeforeLoad: () => {
|
|
34
|
-
window.acmeQueue = window.acmeQueue || [];
|
|
35
|
-
},
|
|
36
|
-
onConsentChange: ({ hasConsent }) => {
|
|
37
|
-
window.acme?.setConsent(hasConsent);
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### Reusable manifest-backed integration
|
|
44
|
-
|
|
45
|
-
Use a manifest-backed helper when:
|
|
46
|
-
|
|
47
|
-
* you want to contribute to `@c15t/scripts`
|
|
48
|
-
* you want the integration to be reusable across apps
|
|
49
|
-
* you need structured startup/setup phases
|
|
50
|
-
* you want compatibility with c15t's server-side support for script loading
|
|
51
|
-
|
|
52
|
-
Manifest integrations should be declarative, serializable, and built from structured steps rather than raw inline JavaScript strings.
|
|
53
|
-
|
|
54
|
-
## Manifest Contract
|
|
55
|
-
|
|
56
|
-
Every reusable manifest carries two contract fields:
|
|
57
|
-
|
|
58
|
-
* `kind`: identifies the payload as a c15t vendor manifest
|
|
59
|
-
* `schemaVersion`: identifies which manifest schema the runtime should compile
|
|
60
|
-
|
|
61
|
-
Use `vendorManifestContract` so helpers stay aligned with the runtime's current contract:
|
|
62
|
-
|
|
63
|
-
```ts
|
|
64
|
-
const acmeManifest = {
|
|
65
|
-
...vendorManifestContract,
|
|
66
|
-
vendor: 'acme-analytics',
|
|
67
|
-
// ...
|
|
68
|
-
} as const satisfies VendorManifest;
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
If manifests are sent from a server later, these fields are how the client can validate that it knows how to interpret the payload before executing anything.
|
|
72
|
-
|
|
73
|
-
## Manifest Mental Model
|
|
74
|
-
|
|
75
|
-
The manifest runtime executes a script in ordered phases:
|
|
76
|
-
|
|
77
|
-
* `bootstrap`: globals or stubs that must exist before anything else
|
|
78
|
-
* `install`: startup steps plus a single `loadScript`
|
|
79
|
-
* `afterLoad`: work that should run after the external script loads
|
|
80
|
-
* `onBeforeLoadGranted` / `onBeforeLoadDenied`: initial consent-specific setup
|
|
81
|
-
* `onLoadGranted` / `onLoadDenied`: post-load consent-specific setup
|
|
82
|
-
* `onConsentChange`: runs on every consent update
|
|
83
|
-
* `onConsentGranted` / `onConsentDenied`: branch-specific consent updates
|
|
84
|
-
|
|
85
|
-
For vendors with explicit consent APIs, you can also use:
|
|
86
|
-
|
|
87
|
-
* `consentMapping`
|
|
88
|
-
* `consentSignal`
|
|
89
|
-
* `consentSignalTarget`
|
|
90
|
-
|
|
91
|
-
That is how the Google integrations map c15t consent categories to Consent Mode v2 and inject `default` and `update` signals in the correct phase order.
|
|
92
|
-
|
|
93
|
-
`category` supports the same consent condition model as a plain `Script`, so manifests can represent simple or nested rules such as:
|
|
10
|
+
Check the installed `@c15t/scripts` exports first. For an unlisted SDK, define a
|
|
11
|
+
stable ID, category and source URL, then pass the configuration to the existing
|
|
12
|
+
provider or loader:
|
|
94
13
|
|
|
95
14
|
```ts
|
|
96
|
-
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Structured Steps
|
|
100
|
-
|
|
101
|
-
Prefer structured steps over raw script text. The current manifest DSL supports patterns like:
|
|
102
|
-
|
|
103
|
-
* `setGlobal`
|
|
104
|
-
* `setGlobalPath`
|
|
105
|
-
* `defineQueueFunction`
|
|
106
|
-
* `defineStubFunction`
|
|
107
|
-
* `pushToQueue`
|
|
108
|
-
* `callGlobal`
|
|
109
|
-
* `defineQueueMethods`
|
|
110
|
-
* `defineGlobalMethods`
|
|
111
|
-
* `constructGlobal`
|
|
112
|
-
* `loadScript`
|
|
113
|
-
|
|
114
|
-
These steps are easier to validate, test, debug, and eventually transport from the server.
|
|
115
|
-
|
|
116
|
-
## Example Manifest Integration
|
|
117
|
-
|
|
118
|
-
If you are building a reusable helper, the pattern looks like this:
|
|
15
|
+
import type { Script } from 'c15t/modules/script-loader';
|
|
119
16
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
import { resolveManifest } from '@c15t/scripts/resolve';
|
|
123
|
-
import {
|
|
124
|
-
vendorManifestContract,
|
|
125
|
-
type VendorManifest,
|
|
126
|
-
} from '@c15t/scripts/types';
|
|
127
|
-
|
|
128
|
-
const acmeManifest = {
|
|
129
|
-
...vendorManifestContract,
|
|
130
|
-
vendor: 'acme-analytics',
|
|
17
|
+
export const analyticsScript = {
|
|
18
|
+
id: 'example-analytics',
|
|
131
19
|
category: 'measurement',
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
type: 'defineQueueFunction',
|
|
141
|
-
name: 'acme',
|
|
142
|
-
queue: 'acmeQueue',
|
|
143
|
-
ifUndefined: true,
|
|
144
|
-
},
|
|
145
|
-
],
|
|
146
|
-
install: [
|
|
147
|
-
{
|
|
148
|
-
type: 'callGlobal',
|
|
149
|
-
global: 'acme',
|
|
150
|
-
args: ['init', '{{siteId}}'],
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
type: 'loadScript',
|
|
154
|
-
src: 'https://cdn.acme.com/analytics.js?site={{siteId}}',
|
|
155
|
-
async: true,
|
|
156
|
-
},
|
|
157
|
-
],
|
|
158
|
-
onConsentGranted: [
|
|
159
|
-
{
|
|
160
|
-
type: 'callGlobal',
|
|
161
|
-
global: 'acme',
|
|
162
|
-
args: ['consent', true],
|
|
163
|
-
},
|
|
164
|
-
],
|
|
165
|
-
onConsentDenied: [
|
|
166
|
-
{
|
|
167
|
-
type: 'callGlobal',
|
|
168
|
-
global: 'acme',
|
|
169
|
-
args: ['consent', false],
|
|
170
|
-
},
|
|
171
|
-
],
|
|
172
|
-
} as const satisfies VendorManifest;
|
|
173
|
-
|
|
174
|
-
export function acmeAnalytics(siteId: string): Script {
|
|
175
|
-
return resolveManifest(acmeManifest, { siteId });
|
|
176
|
-
}
|
|
20
|
+
src: 'https://analytics.example.com/sdk.js',
|
|
21
|
+
onLoad() {
|
|
22
|
+
// Initialize the vendor here using its documented API.
|
|
23
|
+
},
|
|
24
|
+
onError({ error }) {
|
|
25
|
+
console.error('Analytics SDK failed to load', error);
|
|
26
|
+
},
|
|
27
|
+
} satisfies Script;
|
|
177
28
|
```
|
|
178
29
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
* Keep helper logic thin. Put behavior in the manifest, not in post-resolution callback mutation.
|
|
184
|
-
* Keep manifests serializable. Avoid helper-only runtime branches where possible.
|
|
185
|
-
* Use explicit config inputs. Avoid generic override bags when a named option is clearer.
|
|
186
|
-
* Use `alwaysLoad` only when the vendor truly manages its own consent correctly.
|
|
187
|
-
* Use `persistAfterConsentRevoked` only when the vendor exposes a real consent toggle and does not need a full reload.
|
|
188
|
-
* Keep vendor-specific naming out of the core DSL when a generic step can express it.
|
|
189
|
-
|
|
190
|
-
## Testing Checklist
|
|
191
|
-
|
|
192
|
-
At minimum, test these flows:
|
|
193
|
-
|
|
194
|
-
1. Initial page load with consent denied.
|
|
195
|
-
2. Initial page load with consent granted.
|
|
196
|
-
3. Consent granted after the script was previously denied.
|
|
197
|
-
4. Consent revoked after the script was previously active.
|
|
198
|
-
5. Existing script element reuse if the script persists after revocation.
|
|
199
|
-
6. Error handling if the vendor global or loader is missing.
|
|
200
|
-
|
|
201
|
-
If you are contributing to `@c15t/scripts`, add focused engine/helper tests similar to the existing tests in `packages/scripts/src/engine.test.ts` and `packages/scripts/src/helpers.test.ts`.
|
|
202
|
-
|
|
203
|
-
## Debugging
|
|
204
|
-
|
|
205
|
-
Use `@c15t/dev-tools` while implementing and testing integrations.
|
|
206
|
-
|
|
207
|
-
The scripts panel now shows:
|
|
208
|
-
|
|
209
|
-
* whether a script is loaded, pending, or blocked
|
|
210
|
-
* grouped activity for `onBeforeLoad`, `onLoad`, and `onConsentChange`
|
|
211
|
-
* manifest phase activity such as `bootstrap`, `consent-default`, `setup`, and `afterLoad`
|
|
212
|
-
|
|
213
|
-
The events panel also records script lifecycle and manifest step events, which is useful when a vendor reads consent too early or a startup step runs in the wrong order.
|
|
214
|
-
|
|
215
|
-
## When to Stop and Use a Plain Script
|
|
216
|
-
|
|
217
|
-
Not every integration needs a reusable manifest helper.
|
|
218
|
-
|
|
219
|
-
If the vendor snippet is tiny, unique to one app, or mostly static, a plain `Script` object in your runtime options is usually the simpler choice. Reach for the manifest system when you need reuse, consistency, structured startup behavior, or a path to server-driven manifests.
|
|
220
|
-
|
|
221
|
-
## Reference Types
|
|
222
|
-
|
|
223
|
-
### Script
|
|
224
|
-
|
|
225
|
-
|Property|Value|
|
|
226
|
-
|:--|:--|
|
|
227
|
-
|Type Name|\`Script\`|
|
|
228
|
-
|Source Path|\`./packages/core/src/libs/script-loader/types.ts\`|
|
|
30
|
+
Replace the example URL and implement the vendor's initialization. This is a
|
|
31
|
+
loader template, not a functioning analytics SDK. The script stays blocked
|
|
32
|
+
while measurement permission is denied.
|
|
229
33
|
|
|
230
|
-
|
|
34
|
+
## Define revocation deliberately
|
|
231
35
|
|
|
232
|
-
|
|
36
|
+
`onConsentChange` receives current permission information. Use it to update the
|
|
37
|
+
vendor's consent API or disable future work. `persistAfterConsentRevoked` retains
|
|
38
|
+
a loaded script when set; `alwaysLoad` bypasses initial category gating. Enable
|
|
39
|
+
those only when the vendor's own consent behavior matches the intended design.
|
|
233
40
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|Source Path|\`./packages/scripts/src/types.ts\`|
|
|
41
|
+
For a library imported elsewhere, `callbackOnly` allows lifecycle callbacks
|
|
42
|
+
without inserting a script element. It does not prevent that earlier import
|
|
43
|
+
from running. For SDKs with side effects at import time, defer the import too.
|
|
238
44
|
|
|
239
|
-
|
|
45
|
+
A browser cannot undo executed JavaScript merely by removing its script tag.
|
|
46
|
+
Test cleanup, queued events, re-grant and navigation. Use the provider's nonce
|
|
47
|
+
option or a per-script nonce for a nonce-based Content Security Policy.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Clear on revocation
|
|
3
|
+
description: Remove configured first-party cookies and Web Storage keys when
|
|
4
|
+
their consent category is denied.
|
|
5
|
+
group: integrations
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Configure cleanup
|
|
9
|
+
|
|
10
|
+
Add `clearOnRevocation` to your provider or runtime options. Declare only the
|
|
11
|
+
data owned by each optional category:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { hosted, type ClearOnRevocationConfig } from 'c15t';
|
|
15
|
+
import { createConsentRuntime } from 'c15t/runtime';
|
|
16
|
+
|
|
17
|
+
const clearOnRevocation = {
|
|
18
|
+
measurement: {
|
|
19
|
+
cookies: ['_ga', '_ga_*'],
|
|
20
|
+
localStorage: ['analytics:*'],
|
|
21
|
+
},
|
|
22
|
+
marketing: {
|
|
23
|
+
cookies: ['_fbp'],
|
|
24
|
+
sessionStorage: ['campaign-id'],
|
|
25
|
+
},
|
|
26
|
+
} satisfies ClearOnRevocationConfig;
|
|
27
|
+
|
|
28
|
+
const runtime = createConsentRuntime({
|
|
29
|
+
mode: hosted({ url: '/api/c15t' }),
|
|
30
|
+
clearOnRevocation,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Start in the browser after mount. The endpoint must serve your c15t backend.
|
|
34
|
+
runtime.start();
|
|
35
|
+
|
|
36
|
+
// Call runtime.dispose() when the app no longer needs consent management.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For React, pass the same configuration through `ConsentProvider.options`:
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import type { ReactNode } from 'react';
|
|
43
|
+
import { ConsentProvider, hosted } from 'c15t/react';
|
|
44
|
+
|
|
45
|
+
const mode = hosted({ url: '/api/c15t' });
|
|
46
|
+
|
|
47
|
+
export function Consent({ children }: { children: ReactNode }) {
|
|
48
|
+
return (
|
|
49
|
+
<ConsentProvider
|
|
50
|
+
options={{
|
|
51
|
+
mode,
|
|
52
|
+
clearOnRevocation: {
|
|
53
|
+
measurement: { cookies: ['_ga', '_ga_*'] },
|
|
54
|
+
},
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
57
|
+
{children}
|
|
58
|
+
</ConsentProvider>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The same option is available in Next.js and TanStack Start `ConsentRoot` props, Vue and
|
|
64
|
+
Nuxt configuration, Svelte providers, and Astro integration options. Solid and
|
|
65
|
+
other headless integrations can use `createConsentRuntime` as shown above.
|
|
66
|
+
Every adapter uses the same cleanup module.
|
|
67
|
+
|
|
68
|
+
Omitting `clearOnRevocation` leaves cleanup disabled. The provider option is
|
|
69
|
+
initial-only. Remount the provider to replace its cleanup configuration. For
|
|
70
|
+
a shared runtime, configure the runtime owner rather than a borrowing provider.
|
|
71
|
+
|
|
72
|
+
## Matching names and cookie scopes
|
|
73
|
+
|
|
74
|
+
Use an exact string or a nonempty prefix followed by `*`. `_ga_*` matches
|
|
75
|
+
`_ga_ABC123`; it does not match `_ga`. Regular expressions, wildcards in other
|
|
76
|
+
positions, and a bare `*` are unsupported. Web Storage keys may contain spaces,
|
|
77
|
+
Unicode, and punctuation. Cookie names use their raw spelling, without URL
|
|
78
|
+
decoding.
|
|
79
|
+
|
|
80
|
+
Cookies can share a name while having different domains or paths. Cleanup
|
|
81
|
+
tries the current host and its parent domains, and the current path and its
|
|
82
|
+
ancestors. To target a specific scope, use an object:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const clearOnRevocation = {
|
|
86
|
+
measurement: {
|
|
87
|
+
cookies: [
|
|
88
|
+
{ name: 'analytics-id', domain: 'example.com', path: '/' },
|
|
89
|
+
{ name: 'checkout-metrics', domain: '', path: '/checkout' },
|
|
90
|
+
{ name: 'partitioned-metrics', partitioned: true },
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
An empty `domain` means host-only. Explicit domains and paths replace the
|
|
97
|
+
automatic attempts for that field. Exact names can be deleted at a configured
|
|
98
|
+
path even when the current page cannot read that cookie. Prefix matching can
|
|
99
|
+
only discover cookie names visible to the current page, so use an exact name
|
|
100
|
+
for a cookie on another path.
|
|
101
|
+
|
|
102
|
+
Partitioned cookies require `partitioned: true`; ordinary targets remove
|
|
103
|
+
unpartitioned cookies. Cookie deletion preserves the browser's `__Secure-`
|
|
104
|
+
and `__Host-` prefix requirements. c15t protects its own consent, notice,
|
|
105
|
+
privacy, pending-save, and IAB consent records in cookies and localStorage,
|
|
106
|
+
including configured custom storage keys, even if your patterns match them.
|
|
107
|
+
c15t does not store consent in sessionStorage, so targeted entries there are
|
|
108
|
+
removed even when their names match consent storage keys.
|
|
109
|
+
|
|
110
|
+
## When cleanup runs
|
|
111
|
+
|
|
112
|
+
The runtime attaches cleanup after persistence and the script loader. Cleanup
|
|
113
|
+
waits while the policy is pending. On the first settled snapshot, it removes
|
|
114
|
+
configured data for every denied category. This includes a new opt-in visitor
|
|
115
|
+
who has not made a choice and a returning visitor whose permission expired.
|
|
116
|
+
|
|
117
|
+
After that first pass, cleanup runs when a category changes from allowed to
|
|
118
|
+
denied. Saving a refusal, expiry, a policy change, Global Privacy Control,
|
|
119
|
+
or synchronized records can cause that transition. Under an opt-out policy,
|
|
120
|
+
an expired grant that remains effectively allowed does not trigger deletion.
|
|
121
|
+
The `necessary` category cannot be configured for cleanup.
|
|
122
|
+
|
|
123
|
+
Cleanup keeps waiting if a failed initial request leaves the policy pending.
|
|
124
|
+
If a previously settled policy falls back to denial after an initialization
|
|
125
|
+
failure, cleanup removes its configured data. A later successful retry cannot
|
|
126
|
+
restore deleted data.
|
|
127
|
+
|
|
128
|
+
Runtime construction, server rendering, draft checkbox edits, opening the
|
|
129
|
+
dialog, and disposal do not clear data. Cleanup does not poll storage or repeat
|
|
130
|
+
on unrelated UI updates.
|
|
131
|
+
|
|
132
|
+
## Use an existing kernel
|
|
133
|
+
|
|
134
|
+
For a manually assembled integration, attach the module in the browser after
|
|
135
|
+
persistence hydration and script-loader setup:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { createClearOnRevocation } from 'c15t/modules/clear-on-revocation';
|
|
139
|
+
|
|
140
|
+
const cleanup = createClearOnRevocation({
|
|
141
|
+
kernel,
|
|
142
|
+
config: { measurement: { cookies: ['_ga', '_ga_*'] } },
|
|
143
|
+
storageConfig,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Stop observing consent when this integration is torn down.
|
|
147
|
+
cleanup.dispose();
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Here `kernel` is your existing consent kernel. Pass the same `storageConfig`
|
|
151
|
+
used by persistence so cleanup protects custom record keys. Attaching the
|
|
152
|
+
module can immediately clear denied categories if the policy is already
|
|
153
|
+
settled. Do not also attach it when your provider or runtime owns cleanup.
|
|
154
|
+
|
|
155
|
+
## Browser limits
|
|
156
|
+
|
|
157
|
+
Cleanup can remove JavaScript-accessible first-party cookies and keys in the
|
|
158
|
+
current origin's `localStorage` and `sessionStorage`. It cannot remove
|
|
159
|
+
`HttpOnly` cookies or another origin's data. Keep `HttpOnly` protections and
|
|
160
|
+
use your server to expire cookies that require server access. Cookie deletion
|
|
161
|
+
must match the cookie's scope. See the
|
|
162
|
+
[browser cookie documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies).
|
|
163
|
+
|
|
164
|
+
Browser restrictions can prevent reads or deletions. Cleanup failures do not
|
|
165
|
+
block consent updates. A running SDK may write data again after a sweep, so
|
|
166
|
+
keep script gating and the integration's consent-change or teardown behavior
|
|
167
|
+
configured. Deleting a script element cannot undo JavaScript it already ran.
|