@c15t/scripts 2.2.0 → 3.0.0-alpha.0

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 (197) hide show
  1. package/AGENTS.md +74 -48
  2. package/README.md +3 -3
  3. package/dist/e2e-test-utils.js +60 -24
  4. package/dist/engine/compile.js +45 -45
  5. package/dist/engine/runtime.js +119 -119
  6. package/dist/registry.js +186 -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 +31 -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/google-tag-manager.js +20 -20
  47. package/dist-types/__tests__/helpers.d.ts +10 -10
  48. package/dist-types/engine/compile.d.ts +2 -2
  49. package/dist-types/engine/runtime.d.ts +3 -3
  50. package/dist-types/registry.d.ts +182 -173
  51. package/dist-types/resolve.d.ts +2 -2
  52. package/dist-types/types.d.ts +2 -2
  53. package/dist-types/vendors/_shared/attributes.d.ts +2 -2
  54. package/dist-types/vendors/_shared/google-consent.d.ts +2 -2
  55. package/dist-types/vendors/_shared/install-builders.d.ts +1 -1
  56. package/dist-types/vendors/_shared/script-url.d.ts +6 -6
  57. package/dist-types/vendors/ads-and-pixels/linkedin-insights.d.ts +14 -14
  58. package/dist-types/vendors/ads-and-pixels/meta-pixel.d.ts +27 -27
  59. package/dist-types/vendors/ads-and-pixels/microsoft-uet.d.ts +40 -40
  60. package/dist-types/vendors/ads-and-pixels/openai-pixel.d.ts +211 -0
  61. package/dist-types/vendors/ads-and-pixels/reddit-pixel.d.ts +28 -29
  62. package/dist-types/vendors/ads-and-pixels/snapchat-pixel.d.ts +23 -23
  63. package/dist-types/vendors/ads-and-pixels/tiktok-pixel.d.ts +22 -22
  64. package/dist-types/vendors/ads-and-pixels/x-pixel.d.ts +15 -15
  65. package/dist-types/vendors/analytics/adobe-analytics.d.ts +3 -3
  66. package/dist-types/vendors/analytics/ahrefs-analytics.d.ts +5 -5
  67. package/dist-types/vendors/analytics/amplitude.d.ts +24 -24
  68. package/dist-types/vendors/analytics/clearbit.d.ts +5 -5
  69. package/dist-types/vendors/analytics/cloudflare-web-analytics.d.ts +6 -6
  70. package/dist-types/vendors/analytics/databuddy.d.ts +34 -31
  71. package/dist-types/vendors/analytics/fathom-analytics.d.ts +8 -8
  72. package/dist-types/vendors/analytics/google-tag.d.ts +17 -17
  73. package/dist-types/vendors/analytics/heap.d.ts +17 -17
  74. package/dist-types/vendors/analytics/hightouch.d.ts +15 -15
  75. package/dist-types/vendors/analytics/hotjar.d.ts +9 -9
  76. package/dist-types/vendors/analytics/logrocket.d.ts +11 -11
  77. package/dist-types/vendors/analytics/matomo-analytics.d.ts +3 -3
  78. package/dist-types/vendors/analytics/microsoft-clarity.d.ts +12 -13
  79. package/dist-types/vendors/analytics/mixpanel-analytics.d.ts +20 -20
  80. package/dist-types/vendors/analytics/pirsch.d.ts +10 -10
  81. package/dist-types/vendors/analytics/plausible-analytics.d.ts +13 -13
  82. package/dist-types/vendors/analytics/posthog.d.ts +35 -32
  83. package/dist-types/vendors/analytics/promptwatch.d.ts +5 -5
  84. package/dist-types/vendors/analytics/rudderstack.d.ts +16 -16
  85. package/dist-types/vendors/analytics/rybbit-analytics.d.ts +15 -15
  86. package/dist-types/vendors/analytics/segment.d.ts +11 -11
  87. package/dist-types/vendors/analytics/umami-analytics.d.ts +9 -9
  88. package/dist-types/vendors/analytics/vercel-analytics.d.ts +13 -13
  89. package/dist-types/vendors/functional/crisp.d.ts +9 -9
  90. package/dist-types/vendors/functional/intercom.d.ts +12 -12
  91. package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +16 -16
  92. package/docs/README.md +74 -48
  93. package/docs/assets/v3/brand-bar.png +0 -0
  94. package/docs/assets/v3/brand-card.png +0 -0
  95. package/docs/assets/v3/choice-wall.png +0 -0
  96. package/docs/assets/v3/mobile-card.png +0 -0
  97. package/docs/assets/v3/preferences.png +0 -0
  98. package/docs/customization/overview.md +45 -0
  99. package/docs/customization/recipes.md +79 -0
  100. package/docs/customization/slots.md +55 -0
  101. package/docs/customization/tokens.md +76 -0
  102. package/docs/customization/translations.md +49 -0
  103. package/docs/frameworks/javascript/script-loader.md +30 -339
  104. package/docs/frameworks/next/script-loader.md +134 -467
  105. package/docs/frameworks/react/script-loader.md +35 -535
  106. package/docs/guides/consent-state.md +60 -0
  107. package/docs/guides/data-fetching.md +163 -0
  108. package/docs/guides/deployment-modes.md +63 -0
  109. package/docs/guides/troubleshooting.md +68 -0
  110. package/docs/guides/verify-consent.md +62 -0
  111. package/docs/integrations/adobe-analytics.md +239 -105
  112. package/docs/integrations/ahrefs-analytics.md +238 -104
  113. package/docs/integrations/amplitude.md +219 -157
  114. package/docs/integrations/building-integrations.md +32 -224
  115. package/docs/integrations/clearbit.md +247 -86
  116. package/docs/integrations/cloudflare-web-analytics.md +250 -84
  117. package/docs/integrations/crisp.md +251 -97
  118. package/docs/integrations/databuddy.md +259 -153
  119. package/docs/integrations/fathom-analytics.md +239 -96
  120. package/docs/integrations/google-maps.md +328 -207
  121. package/docs/integrations/google-tag-manager.md +248 -96
  122. package/docs/integrations/google-tag.md +261 -90
  123. package/docs/integrations/heap.md +222 -149
  124. package/docs/integrations/hightouch.md +225 -131
  125. package/docs/integrations/hotjar.md +239 -90
  126. package/docs/integrations/intercom.md +239 -98
  127. package/docs/integrations/linkedin-insights.md +243 -113
  128. package/docs/integrations/logrocket.md +241 -123
  129. package/docs/integrations/matomo-analytics.md +256 -111
  130. package/docs/integrations/meta-pixel.md +197 -324
  131. package/docs/integrations/microsoft-clarity.md +233 -114
  132. package/docs/integrations/microsoft-uet.md +245 -110
  133. package/docs/integrations/mixpanel-analytics.md +252 -87
  134. package/docs/integrations/openai-pixel.md +441 -0
  135. package/docs/integrations/overview.md +95 -133
  136. package/docs/integrations/pirsch.md +249 -96
  137. package/docs/integrations/plausible-analytics.md +241 -100
  138. package/docs/integrations/posthog.md +353 -214
  139. package/docs/integrations/promptwatch.md +251 -81
  140. package/docs/integrations/reddit-pixel.md +226 -173
  141. package/docs/integrations/rudderstack.md +244 -187
  142. package/docs/integrations/rybbit-analytics.md +244 -91
  143. package/docs/integrations/segment.md +238 -92
  144. package/docs/integrations/snapchat-pixel.md +240 -110
  145. package/docs/integrations/tiktok-pixel.md +249 -81
  146. package/docs/integrations/umami-analytics.md +242 -95
  147. package/docs/integrations/vercel-analytics.md +242 -90
  148. package/docs/integrations/x-pixel.md +238 -104
  149. package/docs/integrations/youtube.md +354 -142
  150. package/docs/upgrade-v3.md +334 -0
  151. package/package.json +85 -78
  152. package/readme.json +2 -2
  153. package/dist/e2e-test-utils.cjs +0 -166
  154. package/dist/engine/compile.cjs +0 -130
  155. package/dist/engine/runtime.cjs +0 -475
  156. package/dist/registry.cjs +0 -423
  157. package/dist/resolve.cjs +0 -71
  158. package/dist/types.cjs +0 -69
  159. package/dist/vendors/_shared/attributes.cjs +0 -55
  160. package/dist/vendors/_shared/google-consent.cjs +0 -69
  161. package/dist/vendors/_shared/install-builders.cjs +0 -59
  162. package/dist/vendors/_shared/script-url.cjs +0 -78
  163. package/dist/vendors/ads-and-pixels/linkedin-insights.cjs +0 -89
  164. package/dist/vendors/ads-and-pixels/meta-pixel.cjs +0 -206
  165. package/dist/vendors/ads-and-pixels/microsoft-uet.cjs +0 -151
  166. package/dist/vendors/ads-and-pixels/reddit-pixel.cjs +0 -151
  167. package/dist/vendors/ads-and-pixels/snapchat-pixel.cjs +0 -131
  168. package/dist/vendors/ads-and-pixels/tiktok-pixel.cjs +0 -130
  169. package/dist/vendors/ads-and-pixels/x-pixel.cjs +0 -92
  170. package/dist/vendors/analytics/adobe-analytics.cjs +0 -90
  171. package/dist/vendors/analytics/ahrefs-analytics.cjs +0 -68
  172. package/dist/vendors/analytics/amplitude.cjs +0 -193
  173. package/dist/vendors/analytics/clearbit.cjs +0 -69
  174. package/dist/vendors/analytics/cloudflare-web-analytics.cjs +0 -73
  175. package/dist/vendors/analytics/databuddy.cjs +0 -144
  176. package/dist/vendors/analytics/fathom-analytics.cjs +0 -76
  177. package/dist/vendors/analytics/google-tag.cjs +0 -107
  178. package/dist/vendors/analytics/heap.cjs +0 -181
  179. package/dist/vendors/analytics/hightouch.cjs +0 -153
  180. package/dist/vendors/analytics/hotjar.cjs +0 -85
  181. package/dist/vendors/analytics/logrocket.cjs +0 -99
  182. package/dist/vendors/analytics/matomo-analytics.cjs +0 -232
  183. package/dist/vendors/analytics/microsoft-clarity.cjs +0 -138
  184. package/dist/vendors/analytics/mixpanel-analytics.cjs +0 -134
  185. package/dist/vendors/analytics/pirsch.cjs +0 -108
  186. package/dist/vendors/analytics/plausible-analytics.cjs +0 -122
  187. package/dist/vendors/analytics/posthog.cjs +0 -236
  188. package/dist/vendors/analytics/promptwatch.cjs +0 -70
  189. package/dist/vendors/analytics/rudderstack.cjs +0 -227
  190. package/dist/vendors/analytics/rybbit-analytics.cjs +0 -104
  191. package/dist/vendors/analytics/segment.cjs +0 -97
  192. package/dist/vendors/analytics/umami-analytics.cjs +0 -80
  193. package/dist/vendors/analytics/vercel-analytics.cjs +0 -94
  194. package/dist/vendors/functional/crisp.cjs +0 -143
  195. package/dist/vendors/functional/intercom.cjs +0 -89
  196. package/dist/vendors/tag-managers/google-tag-manager.cjs +0 -100
  197. package/docs/shared/react/guides/script-loader.md +0 -311
@@ -1,271 +1,328 @@
1
1
  ---
2
2
  title: RudderStack
3
- description: Load RudderStack's JavaScript SDK with c15t and gate the browser
4
- SDK behind measurement consent.
3
+ description: Gate the RudderStack browser SDK or map c15t categories to
4
+ destination consent IDs.
5
5
  group: integrations
6
- icon: rudderstack
7
6
  ---
8
- [RudderStack](https://www.rudderstack.com/) collects customer data from websites and routes it through your RudderStack data plane to downstream destinations. The `rudderstack()` helper creates RudderStack's `window.rudderanalytics` v3 queue, queues the required `load()` call with your write key and data plane URL, optionally queues the initial `page()` call, and loads the browser SDK when `measurement` consent is available.
9
7
 
10
- ## Integrate with c15t
8
+ ## Configure RudderStack
11
9
 
12
- **React**
10
+ Copy the source write key and HTTPS data plane URL from your RudderStack source.
11
+ The default helper waits for measurement permission before loading the SDK.
13
12
 
14
- ```tsx
15
- import { type ReactNode } from 'react';
16
- import { ConsentManagerProvider } from '@c15t/react';
13
+ | Package manager | Command |
14
+ | :-------------- | :-------------------------- |
15
+ | npm | `npm install @c15t/scripts` |
16
+ | pnpm | `pnpm add @c15t/scripts` |
17
+ | yarn | `yarn add @c15t/scripts` |
18
+ | bun | `bun add @c15t/scripts` |
19
+
20
+ ```ts title="src/consent-scripts.ts"
17
21
  import { rudderstack } from '@c15t/scripts/rudderstack';
18
22
 
19
- const scripts = [
23
+ export const scripts = [
20
24
  rudderstack({
21
- writeKey: 'WRITE_KEY',
22
- dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
25
+ writeKey: 'YOUR_SOURCE_WRITE_KEY',
26
+ dataPlaneUrl: 'https://your-data-plane.example.com',
23
27
  }),
24
28
  ];
25
-
26
- export function ConsentProvider({ children }: { children: ReactNode }) {
27
- return (
28
- <ConsentManagerProvider
29
- options={{
30
- mode: 'hosted',
31
- backendURL: 'https://your-instance.c15t.dev',
32
- scripts,
33
- }}
34
- >
35
- {children}
36
- </ConsentManagerProvider>
37
- );
38
- }
39
29
  ```
40
30
 
41
- **Next.js**
31
+ Replace both values before running the example. Keep secret control-plane
32
+ credentials out of the browser.
42
33
 
43
- ```tsx
44
- 'use client';
34
+ ## Register the scripts
45
35
 
46
- import { type ReactNode } from 'react';
47
- import { ConsentManagerProvider } from '@c15t/nextjs';
48
- import { rudderstack } from '@c15t/scripts/rudderstack';
36
+ Complete your [framework quickstart](https://c15t.com/docs/frameworks) first. Keep its Inth
37
+ endpoint, policy, styles and consent UI. Remove the vendor's original script,
38
+ SDK initializer or tag-manager entry so c15t owns loading once.
49
39
 
50
- const scripts = [
51
- rudderstack({
52
- writeKey: 'WRITE_KEY',
53
- dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
54
- }),
55
- ];
40
+ The `scripts` export in `src/consent-scripts.ts` is a configuration, not an
41
+ initializer. Add it to your existing consent owner using the registration point
42
+ below. These are partial edits to that owner, not additional providers.
56
43
 
57
- export function ConsentProvider({ children }: { children: ReactNode }) {
58
- return (
59
- <ConsentManagerProvider
60
- options={{
61
- mode: 'hosted',
62
- backendURL: '/api/c15t',
63
- scripts,
64
- }}
65
- >
66
- {children}
67
- </ConsentManagerProvider>
68
- );
69
- }
70
- ```
44
+ **Next.js**
71
45
 
72
- **JavaScript**
46
+ Import the configuration into the client boundary from your router guide:
73
47
 
74
48
  ```ts
75
- import { getOrCreateConsentRuntime } from 'c15t';
76
- import { rudderstack } from '@c15t/scripts/rudderstack';
49
+ import { ConsentRoot } from 'c15t/next';
50
+ import { scripts } from './consent-scripts';
51
+ ```
77
52
 
78
- getOrCreateConsentRuntime({
79
- mode: 'hosted',
80
- backendURL: 'https://your-instance.c15t.dev',
81
- scripts: [
82
- rudderstack({
83
- writeKey: 'WRITE_KEY',
84
- dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
85
- }),
86
- ],
87
- });
53
+ Keep the server-resolved `state` and shared `consentConfig` from your
54
+ router guide. Its manifest, init and save URLs stay in effect. Add
55
+ `scripts` as a top-level prop on the existing root:
56
+
57
+ ```tsx
58
+ <ConsentRoot state={state} config={consentConfig} scripts={scripts}>
59
+ {children}
60
+ </ConsentRoot>
88
61
  ```
89
62
 
90
- ## How c15t loads it
63
+ For a Pages Router or static-export setup using `ConsentProvider`, add
64
+ `scripts` to its existing `options` instead. Keep the router-specific setup
65
+ from [Next.js script loading](../frameworks/next/script-loader.md).
91
66
 
92
- * **Category:** `measurement` (Analytics)
93
- * **Loads when:** measurement consent is granted
94
- * **On revocation:** unloaded - c15t removes the script element from the DOM and clears RudderStack globals until consent is granted again.
67
+ **TanStack Start**
95
68
 
96
- The helper maps RudderStack's v3 browser snippet into the manifest engine:
69
+ In your existing root route component, import the scripts alongside
70
+ `ConsentRoot`. Keep the server loader from the [TanStack Start quickstart](https://c15t.com/docs/frameworks/tanstack-start/quickstart).
97
71
 
98
- ```ts
99
- rudderstack({
100
- writeKey: 'WRITE_KEY',
101
- dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
102
- });
72
+ ```tsx
73
+ import { Outlet } from '@tanstack/react-router';
74
+ import { ConsentRoot } from 'c15t/tanstack-start';
75
+ import { scripts } from '../consent-scripts';
76
+
77
+ function Root() {
78
+ const state = Route.useLoaderData();
79
+ return (
80
+ <ConsentRoot state={state} backendURL={backendURL} initRoute={false} scripts={scripts}>
81
+ <Outlet />
82
+ {/* Keep your consent banner, dialog and preferences link here. */}
83
+ </ConsentRoot>
84
+ );
85
+ }
103
86
  ```
104
87
 
105
- It creates `window.rudderanalytics`, defines the v3 snippet queue methods, queues:
88
+ This edits the existing route. `Route` and `backendURL` come from its setup;
89
+ keep the document shell and head components if they are part of your root.
90
+ `initRoute={false}` keeps the quickstart's direct-backend initialization.
91
+ If your app mounts a consent server route, retain its existing `initRoute`
92
+ instead. Do not return script callbacks from a server function or route loader.
93
+
94
+ **React**
95
+
96
+ Import the scripts into your existing provider component:
106
97
 
107
98
  ```ts
108
- window.rudderanalytics.load(
109
- 'WRITE_KEY',
110
- 'https://example.dataplane.rudderstack.com',
111
- {}
112
- );
113
- window.rudderanalytics.page();
99
+ import { ConsentProvider } from 'c15t/react';
100
+ import { scripts } from './consent-scripts';
114
101
  ```
115
102
 
116
- and loads:
103
+ Keep the existing options and add `scripts`:
117
104
 
118
- ```txt
119
- https://cdn.rudderlabs.com/v3/modern/rsa.min.js
105
+ ```tsx
106
+ <ConsentProvider options={{ ...consentOptions, scripts }}>
107
+ {children}
108
+ </ConsentProvider>
120
109
  ```
121
110
 
122
- `writeKey` and `dataPlaneUrl` are both required and must be non-empty strings after trimming. `dataPlaneUrl` must be a valid HTTPS URL.
111
+ Here `consentOptions` is your existing configuration, including
112
+ `mode: hosted({ url: backendURL })`. Keep the banner, dialog and preferences
113
+ link inside the provider. See [React script loading](../frameworks/react/script-loader.md).
123
114
 
124
- ## Configure load options
115
+ **Nuxt**
125
116
 
126
- Pass `loadOptions` to provide RudderStack SDK options as the third `load()` argument. Values must be JSON-serializable: plain objects, arrays, strings, numbers, booleans, and `null`.
117
+ Attach one loader from the root `app.vue`, after the Nuxt module has
118
+ started its browser runtime. This keeps vendor callbacks in application code rather
119
+ than serialized `nuxt.config.ts` runtime configuration.
127
120
 
128
- ```ts
129
- import { rudderstack } from '@c15t/scripts/rudderstack';
121
+ ```vue title="app/app.vue"
122
+ <script setup lang="ts">
123
+ import { onUnmounted } from 'vue';
124
+ import { createScriptLoader } from 'c15t/modules/script-loader';
125
+ import { scripts } from '../src/consent-scripts';
126
+
127
+ const nuxtApp = useNuxtApp();
128
+ const kernel = useConsentKernel();
129
+ let loader: ReturnType<typeof createScriptLoader> | undefined;
130
130
 
131
- rudderstack({
132
- writeKey: 'WRITE_KEY',
133
- dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
134
- loadOptions: {
135
- useBeacon: true,
136
- plugins: ['BeaconQueue'],
137
- },
131
+ const removeMountedHook = nuxtApp.hook('app:mounted', () => {
132
+ loader = createScriptLoader({ kernel, scripts });
138
133
  });
134
+ onUnmounted(() => {
135
+ removeMountedHook();
136
+ loader?.dispose();
137
+ });
138
+ </script>
139
+
140
+ <template>
141
+ <ConsentRoot />
142
+ <NuxtPage />
143
+ </template>
139
144
  ```
140
145
 
141
- Do not pass functions, Dates, Maps, Sets, class instances, symbols, or other non-JSON values in `loadOptions`.
146
+ Merge the setup code into your root and retain its footer and preferences
147
+ link. `useConsentKernel` is auto-imported by the c15t Nuxt module. Adjust the
148
+ relative script import if your `app.vue` is at the project root. This loader
149
+ waits until the module has applied browser persistence and privacy signals,
150
+ then reads the current snapshot and observes future changes. Do not also register these scripts
151
+ in another loader. See the [Nuxt quickstart](https://c15t.com/docs/frameworks/nuxt/quickstart).
142
152
 
143
- ## Configure page tracking
153
+ **Vue**
144
154
 
145
- By default the helper queues `rudderanalytics.page()` before the vendor bundle loads. If you want to handle page views yourself, set `trackPageView` to `false`.
155
+ Use the kernel already provided by the Vue plugin. Merge this setup into
156
+ `App.vue`, whose lifetime covers the application:
146
157
 
147
- ```ts
148
- rudderstack({
149
- writeKey: 'WRITE_KEY',
150
- dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
151
- trackPageView: false,
152
- });
153
- ```
158
+ ```vue title="src/App.vue"
159
+ <script setup lang="ts">
160
+ import { onMounted, onUnmounted } from 'vue';
161
+ import { createScriptLoader } from 'c15t/modules/script-loader';
162
+ import { useConsentKernel } from 'c15t/vue/vue-plugin';
163
+ import ConsentRoot from 'c15t/vue/consent-root';
164
+ import { scripts } from './consent-scripts';
154
165
 
155
- To proxy or self-host the loader, pass a custom URL:
166
+ const kernel = useConsentKernel();
167
+ let loader: ReturnType<typeof createScriptLoader> | undefined;
156
168
 
157
- ```ts
158
- rudderstack({
159
- writeKey: 'WRITE_KEY',
160
- dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
161
- scriptUrl: 'https://analytics.example.com/rsa.min.js',
169
+ onMounted(() => {
170
+ loader = createScriptLoader({ kernel, scripts });
162
171
  });
163
- ```
164
-
165
- ## Consent behavior
166
-
167
- RudderStack exposes a `consent()` API for its own consent-management flow and pre-consent event handling. That API is not a simple runtime opt-out or revocation API for c15t to call after a user withdraws `measurement` consent.
172
+ onUnmounted(() => loader?.dispose());
173
+ </script>
168
174
 
169
- c15t therefore uses the post-consent model recommended by RudderStack's docs: it does not load the SDK until `measurement` consent is granted, and it unloads the script if that consent is later revoked.
175
+ <template>
176
+ <ConsentRoot />
177
+ <main>Your application</main>
178
+ </template>
179
+ ```
170
180
 
171
- ### Why c15t blocks the load instead of mapping consent into RudderStack
181
+ Keep your existing page content and preferences link. The plugin still owns
182
+ the kernel and persistence; this component owns only the vendor loader.
183
+ Do not register the same scripts in plugin configuration as well. See the
184
+ [Vue quickstart](https://c15t.com/docs/frameworks/vue/quickstart).
172
185
 
173
- Some integrations — Google Tag Manager is the clearest example — load immediately and receive c15t's consent state through the vendor's own consent API (Google Consent Mode v2). That model is only safe when the vendor API provides denied-by-default semantics where **nothing identifying is stored or transmitted before consent**.
186
+ **Astro**
174
187
 
175
- Loading the RudderStack SDK does not provide that guarantee on its own: once loaded normally it writes its `anonymousId` cookie and delivers events to your data plane, and the `consent()` API filters which downstream *destinations* receive those events rather than preventing collection. Even RudderStack's pre-consent mode defaults to `events.delivery: 'immediate'`, which still sends pre-decision events. "Loaded but consent-filtered" is still collection, so c15t treats blocking the load as the only default that reliably honors a missing or denied `measurement` consent.
188
+ Point the existing Astro integration at a client module. Keep its `mode`,
189
+ `ui` and framework integration from the [Astro quickstart](https://c15t.com/docs/frameworks/astro/quickstart).
190
+ Import `fileURLToPath` in your Astro configuration:
176
191
 
177
- RudderStack v3 does offer a pre-consent mode (`preConsent` load options with storage disabled and buffered delivery) designed for CMP integrations, which allows a GTM-style flow. c15t supports it as an explicit opt-in — see below. It is not the default because it runs vendor code before consent and depends on vendor-side configuration (consent IDs on every destination) that c15t cannot verify from the browser.
192
+ ```js title="astro.config.mjs"
193
+ import { fileURLToPath } from 'node:url';
194
+ ```
178
195
 
179
- The same reasoning applies to the other customer-data-platform helpers (Segment, Hightouch): their consent surfaces are destination filters, not collection gates, so those helpers block the load too.
196
+ Add this option to the existing `c15t({ ... })` call. Resolve the path from
197
+ the configuration file because Astro injects the import into a virtual module:
180
198
 
181
- ### Opt-in: pre-consent mode with consent ID mapping
199
+ ```js
200
+ clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)),
201
+ ```
182
202
 
183
- Pass `consentManagement` to make c15t the consent provider for RudderStack's pre-consent flow:
203
+ Export the scripts from that module:
184
204
 
185
- ```ts
186
- import { rudderstack } from '@c15t/scripts/rudderstack';
205
+ ```ts title="src/c15t.client.ts"
206
+ import type { C15tClientOptionsExtension } from '@c15t/astro';
207
+ import { scripts } from './consent-scripts';
187
208
 
188
- rudderstack({
189
- writeKey: 'WRITE_KEY',
190
- dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
191
- consentManagement: {
192
- // c15t category → RudderStack consent IDs (from your destination settings)
193
- mapping: {
194
- measurement: ['product-analytics'],
195
- marketing: ['ad-destinations'],
196
- },
197
- },
198
- });
209
+ export default { scripts } satisfies C15tClientOptionsExtension;
199
210
  ```
200
211
 
201
- In this mode:
212
+ The integration passes this extension to its shared browser runtime. Vendor
213
+ helpers contain callbacks, so do not put them in the serialized `scripts`
214
+ option in `astro.config.mjs`. Keep one runtime across consent islands and
215
+ `ClientRouter` navigation.
202
216
 
203
- * The SDK loads immediately for every visitor, but **inert**: `preConsent` is enabled with storage strategy `none` (no cookies, no localStorage) and buffered event delivery — nothing reaches your data plane before a consent decision.
204
- * On every consent decision and change, c15t calls `rudderanalytics.consent()` with `allowedConsentIds`/`deniedConsentIds` partitioned from your mapping. The initial signal is queued before the SDK loads, so consent state is known the moment the SDK initializes.
205
- * Consent revocation re-signals with the denied IDs instead of unloading the script.
217
+ **Svelte**
206
218
 
207
- **Event attribution.** This is the reason to opt in: events fired before the user interacts with the consent banner (the initial `page()` call, early product events) are buffered and delivered once consent is granted, so consenting users keep their full journey. In the default blocked-load mode those pre-consent events are simply lost. If you want session stitching across the consent boundary as well, pass your own `preConsent` in `loadOptions` with storage strategy `'session'` — c15t keeps your storage choice but always forces `preConsent.enabled`, buffered event delivery, and the `custom` consent provider, since any of those falling back to SDK defaults would leak pre-consent events.
219
+ Import the scripts in the component that owns your existing provider and
220
+ pass them as a top-level prop:
208
221
 
209
- **Requirements and caveats:**
222
+ ```svelte title="src/App.svelte"
223
+ <script lang="ts">
224
+ import { ConsentManagerProvider, hosted } from '@c15t/svelte';
225
+ import { scripts } from './consent-scripts';
210
226
 
211
- * Every destination in your RudderStack workspace must be assigned the consent IDs used in the mapping. Destinations without consent IDs receive events regardless of consent — that is RudderStack behavior c15t cannot detect or prevent from the browser.
212
- * Users who never consent have their buffered events discarded; nothing is persisted for them.
213
- * The daily [script vendor monitor](https://github.com/c15t/c15t/issues/899) probes this mode against the live SDK: it loads RudderStack with denied consent in a real browser and asserts zero data plane requests and zero `rl_*` storage, so a vendor-side change to pre-consent semantics is caught automatically.
227
+ const backendURL = import.meta.env.VITE_C15T_BACKEND_URL;
228
+ if (!backendURL) throw new Error('Set VITE_C15T_BACKEND_URL');
229
+ const mode = hosted({ url: backendURL });
230
+ </script>
214
231
 
215
- ### Choosing a consent model for CDPs
232
+ <ConsentManagerProvider {mode} {scripts}>
233
+ <!-- Keep your application, consent UI and preferences link here. -->
234
+ </ConsentManagerProvider>
235
+ ```
216
236
 
217
- * **Default (blocked load)** — strictest interpretation of consent; no vendor code runs pre-consent. Pre-consent events are lost. Right when compliance posture outweighs attribution.
218
- * **Pre-consent mode (`consentManagement`)** vendor-sanctioned CMP flow; pre-consent events are buffered and attributed for consenting users. Requires disciplined destination consent-ID configuration and accepts vendor code running before consent, with the live monitor verifying its inertness daily.
237
+ Retain the styles and consent UI from the [Svelte quickstart](https://c15t.com/docs/frameworks/svelte/quickstart).
238
+ The provider owns the loader and disposes it on unmount.
219
239
 
220
- ## Tracking events in your app
240
+ **SvelteKit**
221
241
 
222
- c15t gates the RudderStack browser SDK from loading until `measurement` consent is granted. Your application code that calls RudderStack's runtime API (`window.rudderanalytics.track`, `identify`, etc.) is **not** automatically gated - `window.rudderanalytics` does not exist until the script is loaded, so unguarded calls before consent throw.
242
+ Add the scripts to the existing root layout provider. Keep the server load
243
+ and its serializable prefetch data from the [SvelteKit quickstart](https://c15t.com/docs/frameworks/sveltekit/quickstart).
223
244
 
224
- Guard event calls by checking consent state. From React:
245
+ ```svelte title="src/routes/+layout.svelte"
246
+ <script lang="ts">
247
+ import { ConsentManagerProvider, hosted } from '@c15t/svelte';
248
+ import { scripts } from '../consent-scripts';
225
249
 
226
- ```tsx
227
- import { useCallback } from 'react';
228
- import { useConsentManager } from '@c15t/react';
250
+ let { children, data } = $props();
251
+ const mode = hosted({ url: data.backendURL });
252
+ </script>
229
253
 
230
- function SignupExample() {
231
- const { has } = useConsentManager();
232
-
233
- const trackSignup = useCallback(() => {
234
- if (has('measurement')) {
235
- window.rudderanalytics?.track('Signup Completed', { plan: 'pro' });
236
- }
237
- }, [has]);
238
- }
254
+ <ConsentManagerProvider {mode} {scripts} prefetch={data.prefetch}>
255
+ {@render children()}
256
+ <!-- Keep your consent UI and preferences link here. -->
257
+ </ConsentManagerProvider>
239
258
  ```
240
259
 
241
- From plain JavaScript:
260
+ Import vendor helpers in the layout component, not in `+layout.server.ts`.
261
+ For static hosting, keep your browser-only `mode` setup and omit request
262
+ prefetch; the `scripts` prop stays the same. If you pass an externally owned
263
+ `runtime` to the provider, register scripts when creating that runtime instead.
242
264
 
243
- ```ts
244
- import { getOrCreateConsentRuntime } from 'c15t';
265
+ **JavaScript**
245
266
 
246
- const { consentStore } = getOrCreateConsentRuntime();
267
+ Attach the loader to your existing kernel before calling
268
+ `kernel.commands.init()`:
247
269
 
248
- if (consentStore.getState().has('measurement')) {
249
- window.rudderanalytics?.track('Signup Completed', { plan: 'pro' });
250
- }
251
- ```
270
+ ```ts
271
+ import { createScriptLoader } from 'c15t/modules/script-loader';
272
+ import { scripts } from './consent-scripts';
252
273
 
253
- ## Types
274
+ const loader = createScriptLoader({ kernel, scripts });
275
+ ```
254
276
 
255
- ### RudderStackOptions
277
+ Call `loader.dispose()` when that application instance is destroyed.
278
+ `kernel` is the hosted kernel from your quickstart. A provider-owned kernel
279
+ already has a loader; do not attach a second one. See
280
+ [JavaScript script loading](../frameworks/javascript/script-loader.md).
256
281
 
257
- |Property|Value|
258
- |:--|:--|
259
- |Type Name|\`RudderStackOptions\`|
260
- |Source Path|\`./packages/scripts/src/vendors/analytics/rudderstack.ts\`|
282
+ ## Map destination consent when loading before permission
261
283
 
262
- \*ExtractedTypeTable: Could not extract "RudderStackOptions" from "./packages/scripts/src/vendors/analytics/rudderstack.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
284
+ `consentManagement` changes the loading contract. The SDK loads immediately,
285
+ receives pre-consent configuration, and stays loaded after revocation. c15t
286
+ sends consent updates through `rudderanalytics.consent()`.
263
287
 
264
- ### Script
288
+ ```ts title="src/consent-scripts.ts"
289
+ import { rudderstack } from '@c15t/scripts/rudderstack';
265
290
 
266
- |Property|Value|
267
- |:--|:--|
268
- |Type Name|\`Script\`|
269
- |Source Path|\`./packages/core/src/libs/script-loader/types.ts\`|
291
+ export const scripts = [
292
+ rudderstack({
293
+ writeKey: 'YOUR_SOURCE_WRITE_KEY',
294
+ dataPlaneUrl: 'https://your-data-plane.example.com',
295
+ consentManagement: {
296
+ mapping: {
297
+ measurement: ['product-analytics'],
298
+ marketing: ['advertising'],
299
+ },
300
+ },
301
+ }),
302
+ ];
303
+ ```
270
304
 
271
- \*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.\*
305
+ The IDs in this example are placeholders for your destination consent settings.
306
+ Allowed c15t categories contribute their IDs to `allowedConsentIds`; denied
307
+ categories contribute theirs to `deniedConsentIds`. Test each destination
308
+ independently. This mode does not prevent the initial SDK request.
309
+
310
+ ## Options
311
+
312
+ | Option | Behavior |
313
+ | --------------------------- | ----------------------------------------------------------------------------- |
314
+ | `writeKey` | Required non-empty browser source key. |
315
+ | `dataPlaneUrl` | Required HTTPS data plane URL. |
316
+ | `consentManagement.mapping` | Optional category-to-consent-ID map. Enables pre-consent loading. |
317
+ | `loadOptions` | Optional JSON-serializable SDK options; functions are not supported. |
318
+ | `trackPageView` | Defaults to `true`, queuing an initial `page()` call. |
319
+ | `scriptUrl` | Optional HTTPS loader override. Defaults to the modern v3 RudderStack loader. |
320
+
321
+ ## Verify the integration
322
+
323
+ In the default mode, confirm denial prevents the initial SDK load. With a
324
+ consent mapping, expect the SDK request and inspect the destination consent IDs
325
+ instead. The default mode has no vendor shutdown hook after loading, so verify
326
+ revocation beyond script removal. In both modes, check routing for duplicate
327
+ page events and stop disallowed application events. See
328
+ [consent verification](../guides/verify-consent.md).