@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.
Files changed (221) hide show
  1. package/AGENTS.md +103 -142
  2. package/README.md +4 -4
  3. package/dist/api.js +1 -0
  4. package/dist/config.js +1 -0
  5. package/dist/devtools.js +2 -0
  6. package/dist/headers.js +1 -0
  7. package/dist/iab/styles.css +1 -1
  8. package/dist/iab/styles.tw3.css +27 -19
  9. package/dist/index.js +1 -1
  10. package/dist/middleware.js +1 -0
  11. package/dist/node-bridge.js +1 -0
  12. package/dist/pages.js +1 -0
  13. package/dist/proxy.js +1 -0
  14. package/dist/root.js +2 -0
  15. package/dist/server.js +1 -0
  16. package/dist/static.js +1 -0
  17. package/dist/styles.css +1 -1
  18. package/dist/styles.tw3.css +67 -29
  19. package/dist/version.js +1 -1
  20. package/dist-types/api.d.ts +88 -0
  21. package/dist-types/config.d.ts +110 -0
  22. package/dist-types/devtools.d.ts +1 -0
  23. package/dist-types/headers.d.ts +4 -0
  24. package/dist-types/index.d.ts +28 -10
  25. package/dist-types/middleware.d.ts +15 -0
  26. package/dist-types/node-bridge.d.ts +57 -0
  27. package/dist-types/pages.d.ts +88 -0
  28. package/dist-types/proxy.d.ts +34 -0
  29. package/dist-types/root.d.ts +92 -0
  30. package/dist-types/server.d.ts +164 -0
  31. package/dist-types/static.d.ts +42 -0
  32. package/dist-types/types.d.ts +5 -36
  33. package/dist-types/version.d.ts +1 -1
  34. package/docs/README.md +103 -142
  35. package/docs/assets/v3/brand-bar.png +0 -0
  36. package/docs/assets/v3/brand-card.png +0 -0
  37. package/docs/assets/v3/choice-wall.png +0 -0
  38. package/docs/assets/v3/mobile-card.png +0 -0
  39. package/docs/assets/v3/preferences.png +0 -0
  40. package/docs/customization/overview.md +45 -0
  41. package/docs/customization/recipes.md +79 -0
  42. package/docs/customization/slots.md +55 -0
  43. package/docs/customization/tokens.md +76 -0
  44. package/docs/customization/translations.md +49 -0
  45. package/docs/frameworks/next/api-reference/data-fetching.md +416 -0
  46. package/docs/frameworks/next/app-router.md +403 -0
  47. package/docs/frameworks/next/client-side.md +118 -0
  48. package/docs/frameworks/next/components/consent-banner.md +251 -211
  49. package/docs/frameworks/next/components/consent-dialog-link.md +96 -35
  50. package/docs/frameworks/next/components/consent-dialog-trigger.md +74 -149
  51. package/docs/frameworks/next/components/consent-dialog.md +189 -134
  52. package/docs/frameworks/next/components/consent-manager-provider.md +68 -318
  53. package/docs/frameworks/next/components/consent-widget.md +172 -114
  54. package/docs/frameworks/next/components/dev-tools.md +199 -40
  55. package/docs/frameworks/next/components/frame.md +137 -42
  56. package/docs/frameworks/next/concepts/consent-categories.md +24 -89
  57. package/docs/frameworks/next/concepts/policy-presets.md +142 -0
  58. package/docs/frameworks/next/content-security-policy.md +189 -0
  59. package/docs/frameworks/next/data-fetching.md +74 -0
  60. package/docs/frameworks/next/geography-headers.md +251 -0
  61. package/docs/frameworks/next/headless.md +95 -185
  62. package/docs/frameworks/next/hooks/use-consent-manager/overview.md +42 -163
  63. package/docs/frameworks/next/iab/overview.md +37 -107
  64. package/docs/frameworks/next/optimization.md +158 -194
  65. package/docs/frameworks/next/pages-router.md +296 -0
  66. package/docs/frameworks/next/quickstart.md +31 -132
  67. package/docs/frameworks/next/script-loader.md +140 -465
  68. package/docs/frameworks/next/server-side.md +97 -130
  69. package/docs/frameworks/next/static-export.md +164 -0
  70. package/docs/frameworks/next/styling/overview.md +174 -248
  71. package/docs/frameworks/next/troubleshooting.md +134 -144
  72. package/docs/guides/consent-state.md +60 -0
  73. package/docs/guides/data-fetching.md +163 -0
  74. package/docs/guides/deployment-modes.md +63 -0
  75. package/docs/guides/troubleshooting.md +68 -0
  76. package/docs/guides/verify-consent.md +62 -0
  77. package/docs/integrations/adobe-analytics.md +239 -105
  78. package/docs/integrations/ahrefs-analytics.md +238 -104
  79. package/docs/integrations/amplitude.md +219 -157
  80. package/docs/integrations/building-integrations.md +32 -224
  81. package/docs/integrations/clear-on-revocation.md +167 -0
  82. package/docs/integrations/clearbit.md +247 -86
  83. package/docs/integrations/cloudflare-web-analytics.md +250 -84
  84. package/docs/integrations/crisp.md +251 -97
  85. package/docs/integrations/databuddy.md +259 -153
  86. package/docs/integrations/fathom-analytics.md +239 -96
  87. package/docs/integrations/google-maps.md +328 -207
  88. package/docs/integrations/google-tag-manager.md +248 -96
  89. package/docs/integrations/google-tag.md +261 -90
  90. package/docs/integrations/heap.md +222 -149
  91. package/docs/integrations/hightouch.md +225 -131
  92. package/docs/integrations/hotjar.md +239 -90
  93. package/docs/integrations/intercom.md +239 -98
  94. package/docs/integrations/linkedin-insights.md +243 -113
  95. package/docs/integrations/logrocket.md +241 -123
  96. package/docs/integrations/matomo-analytics.md +256 -111
  97. package/docs/integrations/meta-pixel.md +197 -324
  98. package/docs/integrations/microsoft-clarity.md +233 -114
  99. package/docs/integrations/microsoft-uet.md +245 -110
  100. package/docs/integrations/mixpanel-analytics.md +252 -87
  101. package/docs/integrations/openai-pixel.md +441 -0
  102. package/docs/integrations/overview.md +95 -133
  103. package/docs/integrations/pirsch.md +249 -96
  104. package/docs/integrations/plausible-analytics.md +241 -100
  105. package/docs/integrations/posthog.md +353 -214
  106. package/docs/integrations/promptwatch.md +251 -81
  107. package/docs/integrations/reddit-pixel.md +226 -173
  108. package/docs/integrations/rudderstack.md +244 -187
  109. package/docs/integrations/rybbit-analytics.md +244 -91
  110. package/docs/integrations/segment.md +238 -92
  111. package/docs/integrations/snapchat-pixel.md +240 -110
  112. package/docs/integrations/tiktok-pixel.md +249 -81
  113. package/docs/integrations/umami-analytics.md +242 -95
  114. package/docs/integrations/vercel-analytics.md +242 -90
  115. package/docs/integrations/x-pixel.md +238 -104
  116. package/docs/integrations/youtube.md +354 -142
  117. package/docs/upgrade-v3.md +334 -0
  118. package/iab/styles.css +1 -1
  119. package/iab/styles.tw3.css +1 -1
  120. package/package.json +106 -65
  121. package/readme.json +3 -3
  122. package/src/iab/styles.css +1 -1
  123. package/src/iab/styles.tw3.css +1 -1
  124. package/src/styles.css +1 -1
  125. package/src/styles.tw3.css +1 -1
  126. package/styles.css +1 -1
  127. package/styles.tw3.css +1 -1
  128. package/client/components/consent-dialog-link.js +0 -3
  129. package/client/components/integrations.js +0 -3
  130. package/dist/components/integrations/index.cjs +0 -1
  131. package/dist/components/integrations/index.js +0 -1
  132. package/dist/headless.cjs +0 -1
  133. package/dist/index.cjs +0 -1
  134. package/dist/libs/browser-initial-data.cjs +0 -1
  135. package/dist/libs/browser-initial-data.js +0 -1
  136. package/dist/libs/initial-data.cjs +0 -1
  137. package/dist/libs/initial-data.js +0 -1
  138. package/dist/types.cjs +0 -1
  139. package/dist/version.cjs +0 -1
  140. package/dist-types/components/integrations/index.d.ts +0 -1
  141. package/dist-types/libs/browser-initial-data.d.ts +0 -9
  142. package/dist-types/libs/initial-data.d.ts +0 -33
  143. package/docs/frameworks/next/building-headless-components.md +0 -379
  144. package/docs/frameworks/next/callbacks.md +0 -186
  145. package/docs/frameworks/next/concepts/client-modes.md +0 -177
  146. package/docs/frameworks/next/concepts/consent-models.md +0 -117
  147. package/docs/frameworks/next/concepts/cookie-management.md +0 -122
  148. package/docs/frameworks/next/concepts/glossary.md +0 -24
  149. package/docs/frameworks/next/concepts/initialization-flow.md +0 -149
  150. package/docs/frameworks/next/concepts/policy-packs.md +0 -230
  151. package/docs/frameworks/next/hooks/use-color-scheme.md +0 -41
  152. package/docs/frameworks/next/hooks/use-consent-manager/checking-consent.md +0 -96
  153. package/docs/frameworks/next/hooks/use-consent-manager/location-info.md +0 -97
  154. package/docs/frameworks/next/hooks/use-consent-manager/setting-consent.md +0 -94
  155. package/docs/frameworks/next/hooks/use-draggable.md +0 -59
  156. package/docs/frameworks/next/hooks/use-focus-trap.md +0 -42
  157. package/docs/frameworks/next/hooks/use-reduced-motion.md +0 -37
  158. package/docs/frameworks/next/hooks/use-ssr-status.md +0 -32
  159. package/docs/frameworks/next/hooks/use-text-direction.md +0 -50
  160. package/docs/frameworks/next/hooks/use-translations.md +0 -55
  161. package/docs/frameworks/next/iab/consent-banner.md +0 -91
  162. package/docs/frameworks/next/iab/consent-dialog.md +0 -129
  163. package/docs/frameworks/next/iab/use-gvl-data.md +0 -21
  164. package/docs/frameworks/next/iframe-blocking.md +0 -106
  165. package/docs/frameworks/next/internationalization.md +0 -207
  166. package/docs/frameworks/next/network-blocker.md +0 -140
  167. package/docs/frameworks/next/policy-packs.md +0 -248
  168. package/docs/frameworks/next/styling/classnames.md +0 -94
  169. package/docs/frameworks/next/styling/color-scheme.md +0 -84
  170. package/docs/frameworks/next/styling/css-variables.md +0 -53
  171. package/docs/frameworks/next/styling/slots.md +0 -94
  172. package/docs/frameworks/next/styling/tailwind.md +0 -137
  173. package/docs/frameworks/next/styling/tokens.md +0 -156
  174. package/docs/shared/concepts/client-modes.md +0 -103
  175. package/docs/shared/concepts/consent-categories.md +0 -41
  176. package/docs/shared/concepts/consent-models.md +0 -72
  177. package/docs/shared/concepts/cookie-management.md +0 -88
  178. package/docs/shared/concepts/glossary.md +0 -24
  179. package/docs/shared/concepts/initialization-flow.md +0 -105
  180. package/docs/shared/concepts/policy-packs.md +0 -225
  181. package/docs/shared/react/components/consent-banner.md +0 -242
  182. package/docs/shared/react/components/consent-dialog-link.md +0 -45
  183. package/docs/shared/react/components/consent-dialog-trigger.md +0 -185
  184. package/docs/shared/react/components/consent-dialog.md +0 -119
  185. package/docs/shared/react/components/consent-manager-provider.md +0 -225
  186. package/docs/shared/react/components/consent-widget.md +0 -121
  187. package/docs/shared/react/components/dev-tools.md +0 -81
  188. package/docs/shared/react/components/frame.md +0 -52
  189. package/docs/shared/react/guides/building-headless-components.md +0 -110
  190. package/docs/shared/react/guides/callbacks.md +0 -89
  191. package/docs/shared/react/guides/headless.md +0 -31
  192. package/docs/shared/react/guides/iframe-blocking.md +0 -65
  193. package/docs/shared/react/guides/internationalization.md +0 -123
  194. package/docs/shared/react/guides/network-blocker.md +0 -72
  195. package/docs/shared/react/guides/optimization.md +0 -44
  196. package/docs/shared/react/guides/policy-packs.md +0 -173
  197. package/docs/shared/react/guides/script-loader.md +0 -311
  198. package/docs/shared/react/hooks/use-color-scheme.md +0 -31
  199. package/docs/shared/react/hooks/use-consent-manager/checking-consent.md +0 -95
  200. package/docs/shared/react/hooks/use-consent-manager/location-info.md +0 -96
  201. package/docs/shared/react/hooks/use-consent-manager/overview.md +0 -74
  202. package/docs/shared/react/hooks/use-consent-manager/setting-consent.md +0 -93
  203. package/docs/shared/react/hooks/use-draggable.md +0 -30
  204. package/docs/shared/react/hooks/use-focus-trap.md +0 -20
  205. package/docs/shared/react/hooks/use-reduced-motion.md +0 -33
  206. package/docs/shared/react/hooks/use-ssr-status.md +0 -16
  207. package/docs/shared/react/hooks/use-text-direction.md +0 -38
  208. package/docs/shared/react/hooks/use-translations.md +0 -15
  209. package/docs/shared/react/iab/consent-banner.md +0 -60
  210. package/docs/shared/react/iab/consent-dialog.md +0 -76
  211. package/docs/shared/react/iab/overview.md +0 -80
  212. package/docs/shared/react/iab/use-gvl-data.md +0 -21
  213. package/docs/shared/react/styling/classnames.md +0 -93
  214. package/docs/shared/react/styling/color-scheme.md +0 -35
  215. package/docs/shared/react/styling/css-variables.md +0 -53
  216. package/docs/shared/react/styling/overview.md +0 -261
  217. package/docs/shared/react/styling/slots.md +0 -93
  218. package/docs/shared/react/styling/stylesheet-entrypoint.md +0 -8
  219. package/docs/shared/react/styling/tailwind.md +0 -88
  220. package/docs/shared/react/styling/tokens.md +0 -155
  221. package/docs/shared/troubleshooting.md +0 -82
@@ -1,239 +1,47 @@
1
1
  ---
2
- title: Build a Custom Script Integration
3
- description: Learn when to use a raw Script, when to build a reusable
4
- manifest-backed integration, and how to debug and test custom consent-aware
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
- 1. Build a one-off `Script` object directly in your app.
11
- 2. Build a reusable manifest-backed integration helper.
8
+ ## Start with a script configuration
12
9
 
13
- Use the first option for app-specific scripts. Use the second option when you want something reusable, testable, and aligned with c15t's manifest system.
14
-
15
- ## Choose the Right Level
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
- category: { and: ['measurement', { not: 'marketing' }] }
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
- ```ts
121
- import type { Script } from 'c15t';
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
- bootstrap: [
133
- {
134
- type: 'setGlobal',
135
- name: 'acmeQueue',
136
- value: [],
137
- ifUndefined: true,
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
- ## Design Guidelines
180
-
181
- When building an integration, prefer these rules:
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
- \*ExtractedTypeTable: Could not extract "Script" from "./packages/core/src/libs/script-loader/types.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
34
+ ## Define revocation deliberately
231
35
 
232
- ### VendorManifest
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
- |Property|Value|
235
- |:--|:--|
236
- |Type Name|\`VendorManifest\`|
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
- \*ExtractedTypeTable: Could not extract "VendorManifest" from "./packages/scripts/src/types.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
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.