@c15t/scripts 2.2.0 → 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 (202) hide show
  1. package/AGENTS.md +77 -48
  2. package/README.md +4 -3
  3. package/dist/e2e-test-utils.js +60 -24
  4. package/dist/engine/compile.js +45 -45
  5. package/dist/engine/runtime.js +130 -119
  6. package/dist/registry.js +196 -176
  7. package/dist/resolve.js +12 -12
  8. package/dist/vendors/_shared/attributes.js +5 -5
  9. package/dist/vendors/_shared/google-consent.js +10 -10
  10. package/dist/vendors/_shared/install-builders.js +9 -9
  11. package/dist/vendors/_shared/script-url.js +12 -12
  12. package/dist/vendors/ads-and-pixels/linkedin-insights.js +16 -16
  13. package/dist/vendors/ads-and-pixels/meta-pixel.js +82 -82
  14. package/dist/vendors/ads-and-pixels/microsoft-uet.js +57 -57
  15. package/dist/vendors/ads-and-pixels/openai-pixel.js +88 -0
  16. package/dist/vendors/ads-and-pixels/reddit-pixel.js +39 -39
  17. package/dist/vendors/ads-and-pixels/snapchat-pixel.js +25 -25
  18. package/dist/vendors/ads-and-pixels/tiktok-pixel.js +31 -31
  19. package/dist/vendors/ads-and-pixels/x-pixel.js +17 -17
  20. package/dist/vendors/analytics/adobe-analytics.js +17 -17
  21. package/dist/vendors/analytics/ahrefs-analytics.js +8 -8
  22. package/dist/vendors/analytics/amplitude.js +39 -39
  23. package/dist/vendors/analytics/clearbit.js +11 -11
  24. package/dist/vendors/analytics/cloudflare-web-analytics.js +13 -13
  25. package/dist/vendors/analytics/databuddy.js +45 -45
  26. package/dist/vendors/analytics/fathom-analytics.js +15 -15
  27. package/dist/vendors/analytics/google-tag.js +23 -23
  28. package/dist/vendors/analytics/heap.js +37 -37
  29. package/dist/vendors/analytics/hightouch.js +30 -30
  30. package/dist/vendors/analytics/hotjar.js +14 -14
  31. package/dist/vendors/analytics/logrocket.js +24 -24
  32. package/dist/vendors/analytics/matomo-analytics.js +51 -51
  33. package/dist/vendors/analytics/microsoft-clarity.js +34 -31
  34. package/dist/vendors/analytics/mixpanel-analytics.js +31 -31
  35. package/dist/vendors/analytics/pirsch.js +27 -27
  36. package/dist/vendors/analytics/plausible-analytics.js +24 -24
  37. package/dist/vendors/analytics/posthog.js +84 -79
  38. package/dist/vendors/analytics/promptwatch.js +8 -8
  39. package/dist/vendors/analytics/rudderstack.js +50 -50
  40. package/dist/vendors/analytics/rybbit-analytics.js +30 -30
  41. package/dist/vendors/analytics/segment.js +16 -16
  42. package/dist/vendors/analytics/umami-analytics.js +16 -16
  43. package/dist/vendors/analytics/vercel-analytics.js +22 -22
  44. package/dist/vendors/functional/crisp.js +49 -51
  45. package/dist/vendors/functional/intercom.js +18 -18
  46. package/dist/vendors/tag-managers/cloudflare-zaraz.js +98 -0
  47. package/dist/vendors/tag-managers/google-tag-manager.js +20 -20
  48. package/dist-types/__tests__/helpers.d.ts +11 -11
  49. package/dist-types/engine/compile.d.ts +3 -3
  50. package/dist-types/engine/runtime.d.ts +3 -3
  51. package/dist-types/registry.d.ts +191 -173
  52. package/dist-types/resolve.d.ts +3 -3
  53. package/dist-types/types.d.ts +2 -2
  54. package/dist-types/vendors/_shared/attributes.d.ts +2 -2
  55. package/dist-types/vendors/_shared/google-consent.d.ts +2 -2
  56. package/dist-types/vendors/_shared/install-builders.d.ts +2 -2
  57. package/dist-types/vendors/_shared/script-url.d.ts +6 -6
  58. package/dist-types/vendors/ads-and-pixels/linkedin-insights.d.ts +14 -14
  59. package/dist-types/vendors/ads-and-pixels/meta-pixel.d.ts +27 -27
  60. package/dist-types/vendors/ads-and-pixels/microsoft-uet.d.ts +40 -40
  61. package/dist-types/vendors/ads-and-pixels/openai-pixel.d.ts +211 -0
  62. package/dist-types/vendors/ads-and-pixels/reddit-pixel.d.ts +28 -29
  63. package/dist-types/vendors/ads-and-pixels/snapchat-pixel.d.ts +23 -23
  64. package/dist-types/vendors/ads-and-pixels/tiktok-pixel.d.ts +22 -22
  65. package/dist-types/vendors/ads-and-pixels/x-pixel.d.ts +15 -15
  66. package/dist-types/vendors/analytics/adobe-analytics.d.ts +3 -3
  67. package/dist-types/vendors/analytics/ahrefs-analytics.d.ts +5 -5
  68. package/dist-types/vendors/analytics/amplitude.d.ts +24 -24
  69. package/dist-types/vendors/analytics/clearbit.d.ts +5 -5
  70. package/dist-types/vendors/analytics/cloudflare-web-analytics.d.ts +6 -6
  71. package/dist-types/vendors/analytics/databuddy.d.ts +34 -31
  72. package/dist-types/vendors/analytics/fathom-analytics.d.ts +8 -8
  73. package/dist-types/vendors/analytics/google-tag.d.ts +17 -17
  74. package/dist-types/vendors/analytics/heap.d.ts +17 -17
  75. package/dist-types/vendors/analytics/hightouch.d.ts +15 -15
  76. package/dist-types/vendors/analytics/hotjar.d.ts +9 -9
  77. package/dist-types/vendors/analytics/logrocket.d.ts +11 -11
  78. package/dist-types/vendors/analytics/matomo-analytics.d.ts +3 -3
  79. package/dist-types/vendors/analytics/microsoft-clarity.d.ts +12 -13
  80. package/dist-types/vendors/analytics/mixpanel-analytics.d.ts +20 -20
  81. package/dist-types/vendors/analytics/pirsch.d.ts +10 -10
  82. package/dist-types/vendors/analytics/plausible-analytics.d.ts +13 -13
  83. package/dist-types/vendors/analytics/posthog.d.ts +35 -32
  84. package/dist-types/vendors/analytics/promptwatch.d.ts +5 -5
  85. package/dist-types/vendors/analytics/rudderstack.d.ts +16 -16
  86. package/dist-types/vendors/analytics/rybbit-analytics.d.ts +15 -15
  87. package/dist-types/vendors/analytics/segment.d.ts +11 -11
  88. package/dist-types/vendors/analytics/umami-analytics.d.ts +9 -9
  89. package/dist-types/vendors/analytics/vercel-analytics.d.ts +13 -13
  90. package/dist-types/vendors/functional/crisp.d.ts +9 -9
  91. package/dist-types/vendors/functional/intercom.d.ts +12 -12
  92. package/dist-types/vendors/tag-managers/cloudflare-zaraz.d.ts +39 -0
  93. package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +16 -16
  94. package/docs/README.md +77 -48
  95. package/docs/assets/v3/brand-bar.png +0 -0
  96. package/docs/assets/v3/brand-card.png +0 -0
  97. package/docs/assets/v3/choice-wall.png +0 -0
  98. package/docs/assets/v3/mobile-card.png +0 -0
  99. package/docs/assets/v3/preferences.png +0 -0
  100. package/docs/customization/overview.md +45 -0
  101. package/docs/customization/recipes.md +79 -0
  102. package/docs/customization/slots.md +55 -0
  103. package/docs/customization/tokens.md +76 -0
  104. package/docs/customization/translations.md +49 -0
  105. package/docs/frameworks/javascript/script-loader.md +81 -343
  106. package/docs/frameworks/next/script-loader.md +164 -455
  107. package/docs/frameworks/react/script-loader.md +41 -533
  108. package/docs/guides/consent-state.md +60 -0
  109. package/docs/guides/data-fetching.md +163 -0
  110. package/docs/guides/deployment-modes.md +75 -0
  111. package/docs/guides/troubleshooting.md +68 -0
  112. package/docs/guides/verify-consent.md +62 -0
  113. package/docs/integrations/adobe-analytics.md +239 -105
  114. package/docs/integrations/ahrefs-analytics.md +238 -104
  115. package/docs/integrations/amplitude.md +219 -157
  116. package/docs/integrations/building-integrations.md +36 -223
  117. package/docs/integrations/clear-on-revocation.md +167 -0
  118. package/docs/integrations/clearbit.md +247 -86
  119. package/docs/integrations/cloudflare-web-analytics.md +250 -84
  120. package/docs/integrations/cloudflare-zaraz.md +399 -0
  121. package/docs/integrations/crisp.md +251 -97
  122. package/docs/integrations/databuddy.md +259 -153
  123. package/docs/integrations/fathom-analytics.md +239 -96
  124. package/docs/integrations/google-maps.md +328 -207
  125. package/docs/integrations/google-tag-manager.md +248 -96
  126. package/docs/integrations/google-tag.md +261 -90
  127. package/docs/integrations/granular-consent.md +208 -0
  128. package/docs/integrations/heap.md +222 -149
  129. package/docs/integrations/hightouch.md +225 -131
  130. package/docs/integrations/hotjar.md +239 -90
  131. package/docs/integrations/intercom.md +239 -98
  132. package/docs/integrations/linkedin-insights.md +243 -113
  133. package/docs/integrations/logrocket.md +241 -123
  134. package/docs/integrations/matomo-analytics.md +256 -111
  135. package/docs/integrations/meta-pixel.md +197 -324
  136. package/docs/integrations/microsoft-clarity.md +233 -114
  137. package/docs/integrations/microsoft-uet.md +245 -110
  138. package/docs/integrations/mixpanel-analytics.md +252 -87
  139. package/docs/integrations/openai-pixel.md +441 -0
  140. package/docs/integrations/overview.md +96 -133
  141. package/docs/integrations/pirsch.md +249 -96
  142. package/docs/integrations/plausible-analytics.md +241 -100
  143. package/docs/integrations/posthog.md +353 -214
  144. package/docs/integrations/promptwatch.md +251 -81
  145. package/docs/integrations/reddit-pixel.md +226 -173
  146. package/docs/integrations/rudderstack.md +244 -187
  147. package/docs/integrations/rybbit-analytics.md +244 -91
  148. package/docs/integrations/segment.md +238 -92
  149. package/docs/integrations/snapchat-pixel.md +240 -110
  150. package/docs/integrations/tiktok-pixel.md +249 -81
  151. package/docs/integrations/umami-analytics.md +242 -95
  152. package/docs/integrations/vercel-analytics.md +242 -90
  153. package/docs/integrations/x-pixel.md +238 -104
  154. package/docs/integrations/youtube.md +359 -142
  155. package/docs/upgrade-v3.md +381 -0
  156. package/package.json +90 -78
  157. package/dist/e2e-test-utils.cjs +0 -166
  158. package/dist/engine/compile.cjs +0 -130
  159. package/dist/engine/runtime.cjs +0 -475
  160. package/dist/registry.cjs +0 -423
  161. package/dist/resolve.cjs +0 -71
  162. package/dist/types.cjs +0 -69
  163. package/dist/vendors/_shared/attributes.cjs +0 -55
  164. package/dist/vendors/_shared/google-consent.cjs +0 -69
  165. package/dist/vendors/_shared/install-builders.cjs +0 -59
  166. package/dist/vendors/_shared/script-url.cjs +0 -78
  167. package/dist/vendors/ads-and-pixels/linkedin-insights.cjs +0 -89
  168. package/dist/vendors/ads-and-pixels/meta-pixel.cjs +0 -206
  169. package/dist/vendors/ads-and-pixels/microsoft-uet.cjs +0 -151
  170. package/dist/vendors/ads-and-pixels/reddit-pixel.cjs +0 -151
  171. package/dist/vendors/ads-and-pixels/snapchat-pixel.cjs +0 -131
  172. package/dist/vendors/ads-and-pixels/tiktok-pixel.cjs +0 -130
  173. package/dist/vendors/ads-and-pixels/x-pixel.cjs +0 -92
  174. package/dist/vendors/analytics/adobe-analytics.cjs +0 -90
  175. package/dist/vendors/analytics/ahrefs-analytics.cjs +0 -68
  176. package/dist/vendors/analytics/amplitude.cjs +0 -193
  177. package/dist/vendors/analytics/clearbit.cjs +0 -69
  178. package/dist/vendors/analytics/cloudflare-web-analytics.cjs +0 -73
  179. package/dist/vendors/analytics/databuddy.cjs +0 -144
  180. package/dist/vendors/analytics/fathom-analytics.cjs +0 -76
  181. package/dist/vendors/analytics/google-tag.cjs +0 -107
  182. package/dist/vendors/analytics/heap.cjs +0 -181
  183. package/dist/vendors/analytics/hightouch.cjs +0 -153
  184. package/dist/vendors/analytics/hotjar.cjs +0 -85
  185. package/dist/vendors/analytics/logrocket.cjs +0 -99
  186. package/dist/vendors/analytics/matomo-analytics.cjs +0 -232
  187. package/dist/vendors/analytics/microsoft-clarity.cjs +0 -138
  188. package/dist/vendors/analytics/mixpanel-analytics.cjs +0 -134
  189. package/dist/vendors/analytics/pirsch.cjs +0 -108
  190. package/dist/vendors/analytics/plausible-analytics.cjs +0 -122
  191. package/dist/vendors/analytics/posthog.cjs +0 -236
  192. package/dist/vendors/analytics/promptwatch.cjs +0 -70
  193. package/dist/vendors/analytics/rudderstack.cjs +0 -227
  194. package/dist/vendors/analytics/rybbit-analytics.cjs +0 -104
  195. package/dist/vendors/analytics/segment.cjs +0 -97
  196. package/dist/vendors/analytics/umami-analytics.cjs +0 -80
  197. package/dist/vendors/analytics/vercel-analytics.cjs +0 -94
  198. package/dist/vendors/functional/crisp.cjs +0 -143
  199. package/dist/vendors/functional/intercom.cjs +0 -89
  200. package/dist/vendors/tag-managers/google-tag-manager.cjs +0 -100
  201. package/docs/shared/react/guides/script-loader.md +0 -311
  202. package/readme.json +0 -19
@@ -1,239 +1,52 @@
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
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:
24
13
 
25
14
  ```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:
15
+ import type { Script } from 'c15t/modules/script-loader';
62
16
 
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:
94
-
95
- ```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:
119
-
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
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.
224
33
 
225
- |Property|Value|
226
- |:--|:--|
227
- |Type Name|\`Script\`|
228
- |Source Path|\`./packages/core/src/libs/script-loader/types.ts\`|
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).
229
38
 
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.\*
39
+ ## Define revocation deliberately
231
40
 
232
- ### VendorManifest
41
+ `onConsentChange` receives current permission information. Use it to update the
42
+ vendor's consent API or disable future work. `persistAfterConsentRevoked` retains
43
+ a loaded script when set; `alwaysLoad` bypasses initial category gating. Enable
44
+ those only when the vendor's own consent behavior matches the intended design.
233
45
 
234
- |Property|Value|
235
- |:--|:--|
236
- |Type Name|\`VendorManifest\`|
237
- |Source Path|\`./packages/scripts/src/types.ts\`|
46
+ For a library imported elsewhere, `callbackOnly` allows lifecycle callbacks
47
+ without inserting a script element. It does not prevent that earlier import
48
+ from running. For SDKs with side effects at import time, defer the import too.
238
49
 
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.\*
50
+ A browser cannot undo executed JavaScript merely by removing its script tag.
51
+ Test cleanup, queued events, re-grant and navigation. Use the provider's nonce
52
+ 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.