@c15t/react 3.0.0-alpha.9 → 3.0.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 (147) hide show
  1. package/AGENTS.md +7 -9
  2. package/README.md +41 -70
  3. package/SKILL.md +1 -1
  4. package/dist/aggregate-components.js +1 -1
  5. package/dist/components/consent-gate/atoms.js +1 -1
  6. package/dist/components/consent-gate/frame.js +2 -0
  7. package/dist/components/consent-gate/index.js +1 -1
  8. package/dist/components/iab-panel/atoms/root.js +1 -1
  9. package/dist/components/iab-panel/iab-panel.js +1 -1
  10. package/dist/components/iab-prompt/atoms/root.js +1 -1
  11. package/dist/components/iab-prompt/iab-prompt.js +1 -1
  12. package/dist/components/panel/atoms/root.js +1 -1
  13. package/dist/components/panel-trigger/atoms/root.js +1 -1
  14. package/dist/components/panel-trigger/panel-trigger.js +1 -1
  15. package/dist/components/panel-trigger/toolbar-loader.js +2 -0
  16. package/dist/components/preferences/atoms/root.js +1 -1
  17. package/dist/components/prompt/atoms/early-tap-script.js +2 -0
  18. package/dist/components/prompt/atoms/root.js +1 -1
  19. package/dist/components/shared/primitives/button.js +1 -1
  20. package/dist/components/shared/surface-styles.js +1 -1
  21. package/dist/consent-gate.js +1 -1
  22. package/dist/context/index.js +1 -1
  23. package/dist/devtools.js +1 -1
  24. package/dist/iab/styles.tw3.css +2 -2
  25. package/dist/iab-dialog-deferred.js +2 -0
  26. package/dist/iab.js +1 -1
  27. package/dist/index-parts/consent-gate.js +1 -1
  28. package/dist/index-parts/core.js +1 -1
  29. package/dist/index-parts/frame.js +1 -0
  30. package/dist/index-parts/hosted.js +1 -0
  31. package/dist/index-parts/offline.js +1 -0
  32. package/dist/index-parts/presets.js +1 -0
  33. package/dist/index.js +1 -1
  34. package/dist/modes.js +1 -0
  35. package/dist/panel-link.js +1 -1
  36. package/dist/panel-trigger.js +1 -1
  37. package/dist/provider.js +1 -1
  38. package/dist/styles.tw3.css +2 -2
  39. package/dist/transports/hosted.js +1 -0
  40. package/dist/transports/manifest.js +1 -0
  41. package/dist/utils/deferred-module.js +1 -1
  42. package/dist/version.js +1 -1
  43. package/dist-types/chunk-warming.d.ts +7 -6
  44. package/dist-types/components/consent-gate/frame.d.ts +19 -0
  45. package/dist-types/components/consent-gate/index.d.ts +3 -19
  46. package/dist-types/components/iab-prompt/iab-prompt.d.ts +1 -1
  47. package/dist-types/components/panel/index.d.ts +1 -1
  48. package/dist-types/components/panel-trigger/toolbar-loader.d.ts +34 -0
  49. package/dist-types/components/preferences/index.d.ts +1 -1
  50. package/dist-types/components/prompt/atoms/early-tap-script.d.ts +17 -0
  51. package/dist-types/components/prompt/index.d.ts +1 -1
  52. package/dist-types/components/shared/surface-styles.d.ts +26 -2
  53. package/dist-types/consent-gate.d.ts +1 -1
  54. package/dist-types/context/index.d.ts +3 -3
  55. package/dist-types/context.d.ts +2 -0
  56. package/dist-types/gpp.d.ts +1 -1
  57. package/dist-types/iab-dialog-deferred.d.ts +36 -0
  58. package/dist-types/iab.d.ts +3 -2
  59. package/dist-types/index-parts/consent-gate.d.ts +1 -1
  60. package/dist-types/index-parts/core.d.ts +1 -2
  61. package/dist-types/index-parts/frame.d.ts +7 -0
  62. package/dist-types/index-parts/hosted.d.ts +7 -0
  63. package/dist-types/index-parts/offline.d.ts +7 -0
  64. package/dist-types/index-parts/presets.d.ts +7 -0
  65. package/dist-types/index.d.ts +5 -1
  66. package/dist-types/modes.d.ts +26 -0
  67. package/dist-types/panel-link.d.ts +1 -1
  68. package/dist-types/panel-trigger.d.ts +1 -1
  69. package/dist-types/provider.d.ts +3 -3
  70. package/dist-types/transports/hosted.d.ts +36 -0
  71. package/dist-types/transports/manifest.d.ts +48 -0
  72. package/dist-types/version.d.ts +1 -1
  73. package/docs/README.md +7 -9
  74. package/docs/concepts/choose-your-setup.md +45 -10
  75. package/docs/concepts/consent-categories.md +1 -1
  76. package/docs/concepts/consent-state.md +5 -2
  77. package/docs/concepts/data-fetching.md +100 -42
  78. package/docs/concepts/modes.md +281 -0
  79. package/docs/customization/dark-mode.md +1 -1
  80. package/docs/customization/motion.md +2 -2
  81. package/docs/customization/recipes.md +4 -4
  82. package/docs/customization/slots.md +25 -25
  83. package/docs/customization/stylesheets.md +12 -14
  84. package/docs/customization/tailwind.md +17 -11
  85. package/docs/customization/tokens.md +36 -7
  86. package/docs/frameworks/react/components/consent-banner.md +14 -10
  87. package/docs/frameworks/react/components/consent-dialog.md +14 -10
  88. package/docs/frameworks/react/components/consent-provider.md +51 -44
  89. package/docs/frameworks/react/components.md +14 -10
  90. package/docs/frameworks/react/content-security-policy.md +21 -12
  91. package/docs/frameworks/react/hooks.md +2 -2
  92. package/docs/frameworks/react/iab.md +20 -2
  93. package/docs/frameworks/react/quickstart.md +63 -97
  94. package/docs/frameworks/react/rendering.md +168 -94
  95. package/docs/frameworks/react/scripts.md +19 -28
  96. package/docs/frameworks/react/troubleshooting.md +57 -25
  97. package/docs/frameworks/react/upgrade-v3.md +110 -62
  98. package/docs/guides/banner-experiments.md +21 -6
  99. package/docs/guides/troubleshooting.md +89 -25
  100. package/docs/guides/verify-consent.md +23 -8
  101. package/docs/integrations/adobe-analytics.md +60 -64
  102. package/docs/integrations/ahrefs-analytics.md +58 -63
  103. package/docs/integrations/amplitude.md +60 -64
  104. package/docs/integrations/clearbit.md +59 -63
  105. package/docs/integrations/cloudflare-web-analytics.md +56 -60
  106. package/docs/integrations/cloudflare-zaraz.md +55 -57
  107. package/docs/integrations/crisp.md +64 -69
  108. package/docs/integrations/databuddy.md +62 -64
  109. package/docs/integrations/fathom-analytics.md +56 -60
  110. package/docs/integrations/front-chat.md +56 -60
  111. package/docs/integrations/google-maps.md +25 -13
  112. package/docs/integrations/google-tag-manager.md +153 -77
  113. package/docs/integrations/google-tag.md +134 -78
  114. package/docs/integrations/heap.md +56 -60
  115. package/docs/integrations/hightouch.md +55 -60
  116. package/docs/integrations/hotjar.md +60 -64
  117. package/docs/integrations/intercom.md +55 -60
  118. package/docs/integrations/klaviyo.md +65 -66
  119. package/docs/integrations/linkedin-insights.md +58 -63
  120. package/docs/integrations/logrocket.md +55 -60
  121. package/docs/integrations/matomo-analytics.md +58 -60
  122. package/docs/integrations/meta-pixel.md +56 -60
  123. package/docs/integrations/microsoft-clarity.md +57 -60
  124. package/docs/integrations/microsoft-uet.md +58 -61
  125. package/docs/integrations/mixpanel-analytics.md +73 -75
  126. package/docs/integrations/one-dollar-stats.md +53 -59
  127. package/docs/integrations/openai-pixel.md +58 -60
  128. package/docs/integrations/overview.md +59 -42
  129. package/docs/integrations/pinterest-tag.md +56 -60
  130. package/docs/integrations/pirsch.md +54 -60
  131. package/docs/integrations/plausible-analytics.md +55 -60
  132. package/docs/integrations/posthog.md +56 -60
  133. package/docs/integrations/promptwatch.md +57 -63
  134. package/docs/integrations/reddit-pixel.md +57 -60
  135. package/docs/integrations/rudderstack.md +65 -67
  136. package/docs/integrations/rybbit-analytics.md +70 -75
  137. package/docs/integrations/segment.md +56 -60
  138. package/docs/integrations/sentry.md +65 -60
  139. package/docs/integrations/snapchat-pixel.md +54 -60
  140. package/docs/integrations/tiktok-pixel.md +59 -63
  141. package/docs/integrations/umami-analytics.md +54 -60
  142. package/docs/integrations/vercel-analytics.md +53 -59
  143. package/docs/integrations/vercel-speed-insights.md +317 -0
  144. package/docs/integrations/x-pixel.md +57 -63
  145. package/docs/integrations/youtube.md +25 -13
  146. package/package.json +18 -8
  147. package/docs/upgrade-v3.md +0 -429
@@ -0,0 +1,317 @@
1
+ ---
2
+ title: Vercel Speed Insights
3
+ description: Load the Vercel Speed Insights collector only after measurement
4
+ consent with the c15t vercelSpeedInsights helper, drop Web Vitals reports on
5
+ revocation, and check it in DevTools.
6
+ seoTitle: Vercel Speed Insights cookie consent with c15t
7
+ seoDescription: Load Vercel Speed Insights only with measurement consent. The
8
+ c15t vercelSpeedInsights helper drops every Web Vitals report after a
9
+ withdrawal.
10
+ icon: vercel-analytics
11
+ group: integrations
12
+ ---
13
+
14
+ The c15t `vercelSpeedInsights` helper keeps the Vercel Speed Insights collector
15
+ off the page until `measurement` has consent. The helper sends no consent signal
16
+ to Vercel. It registers a `beforeSend` callback that drops every Web Vitals
17
+ report while `measurement` has no consent. If the visitor withdraws consent,
18
+ c15t removes the script element. The collector keeps running, so the callback
19
+ drops its reports. By default, c15t also reloads the page.
20
+
21
+ ## Configure Vercel Speed Insights
22
+
23
+ Enable Speed Insights for the project in Vercel. Remove the `SpeedInsights`
24
+ component or `injectSpeedInsights()` call from `@vercel/speed-insights`. The
25
+ collector starts once per page, so a copy loaded outside c15t keeps reporting
26
+ before consent.
27
+
28
+ | Package manager | Command |
29
+ | :-------------- | :------------------------------- |
30
+ | npm | `npm install @c15t/integrations` |
31
+ | pnpm | `pnpm add @c15t/integrations` |
32
+ | yarn | `yarn add @c15t/integrations` |
33
+ | bun | `bun add @c15t/integrations` |
34
+
35
+ ```ts title="src/consent-scripts.ts"
36
+ import { vercelSpeedInsights } from '@c15t/integrations/vercel-speed-insights';
37
+
38
+ export const scripts = [vercelSpeedInsights()];
39
+ ```
40
+
41
+ ## Register the scripts
42
+
43
+ Complete your [framework quickstart](https://c15t.com/docs/frameworks) first. Keep its Inth
44
+ endpoint, policy, styles and consent UI. Remove the vendor's original script,
45
+ SDK initializer or tag-manager entry, so the vendor loads only through c15t.
46
+
47
+ The vendor pages put the helper in `src/consent-scripts.ts`. If your framework
48
+ quickstart already has a `scripts` array, such as the one in `c15t.config.ts`
49
+ in the Next.js guide, add the helper to that array instead of creating a
50
+ second file.
51
+ The `scripts` export is a configuration, not an initializer. Add it to the c15t provider you already have, at the registration
52
+ point for your framework below. These are edits to that provider, not a second
53
+ provider.
54
+
55
+ **Next.js**
56
+
57
+ Add the configuration to `scripts` in `c15t.config.ts`, next to
58
+ `next.config.ts`:
59
+
60
+ ```ts title="c15t.config.ts"
61
+ import { defineConsentConfig } from 'c15t/next';
62
+ import { scripts } from './src/consent-scripts';
63
+
64
+ export default defineConsentConfig({ scripts });
65
+ ```
66
+
67
+ Keep the rest of your config, such as `mode` and `routePrefix`, in the
68
+ same call. `ConsentRoot` reads the config in the browser, so the layout
69
+ keeps passing only `state`. App Router, Pages Router and static export all
70
+ read the same file. See
71
+ [Next.js scripts and embeds](https://c15t.com/docs/frameworks/next/scripts).
72
+
73
+ **TanStack Start**
74
+
75
+ Import the configuration into your root route and pass it to the existing
76
+ `ConsentRoot` as a top-level prop. Keep the loader from the
77
+ [TanStack Start quickstart](https://c15t.com/docs/frameworks/tanstack-start/quickstart):
78
+
79
+ ```tsx title="src/routes/__root.tsx"
80
+ import { scripts } from '../consent-scripts';
81
+
82
+ <ConsentRoot state={consent} scripts={scripts}>
83
+ ```
84
+
85
+ Import vendor helpers in the root route module, not in a server function.
86
+ A server function's return value must be serializable, and script
87
+ configurations carry callbacks. See
88
+ [TanStack Start scripts](https://c15t.com/docs/frameworks/tanstack-start/scripts).
89
+
90
+ **React**
91
+
92
+ Add the configuration to the existing `ConsentProvider` options, next to
93
+ `mode`:
94
+
95
+ ```tsx title="src/consent.tsx"
96
+ import { scripts } from './consent-scripts';
97
+
98
+ <ConsentProvider options={{ mode, scripts }}>
99
+ ```
100
+
101
+ `mode` is the `manifest()` value from the
102
+ [React quickstart](../frameworks/react/quickstart.md). Keep the banner,
103
+ dialog and preferences link inside the provider. See
104
+ [React scripts and embeds](../frameworks/react/scripts.md).
105
+
106
+ **Nuxt**
107
+
108
+ Register the scripts under the `c15t` key in `app/app.config.ts`. Adjust the
109
+ relative import to where you created `consent-scripts.ts`:
110
+
111
+ ```ts title="app/app.config.ts"
112
+ import { scripts } from '../src/consent-scripts';
113
+
114
+ export default defineAppConfig({
115
+ c15t: { scripts },
116
+ });
117
+ ```
118
+
119
+ The Nuxt module merges this over its options in `nuxt.config.ts` and starts
120
+ one script loader in the browser after hydration, once it has applied the
121
+ visitor's stored choice and privacy signals. Keep `scripts` out of
122
+ `nuxt.config.ts`, which reaches the browser as JSON and drops the vendor
123
+ callbacks. Write the vendor IDs into `consent-scripts.ts`. See
124
+ [Nuxt scripts and embeds](https://c15t.com/docs/frameworks/nuxt/scripts).
125
+
126
+ **Vue**
127
+
128
+ Pass the scripts to the existing `c15tVue` plugin call in `src/main.ts`:
129
+
130
+ ```ts title="src/main.ts"
131
+ import { c15tVue, manifest } from 'c15t/vue/vue-plugin';
132
+ import { scripts } from './consent-scripts';
133
+
134
+ app.use(c15tVue, {
135
+ mode: manifest(),
136
+ scripts,
137
+ });
138
+ ```
139
+
140
+ Keep your existing `mode` and other options. The plugin starts one
141
+ script loader when the app mounts, after it has applied the visitor's stored
142
+ choice. Do not also call `createScriptLoader` from a component. See
143
+ [Vue scripts and embeds](https://c15t.com/docs/frameworks/vue/scripts).
144
+
145
+ **Astro**
146
+
147
+ Add the scripts to the client entrypoint from the
148
+ [Astro quickstart](https://c15t.com/docs/frameworks/astro/quickstart), `src/c15t.client.ts`,
149
+ which the integration finds on its own. Keep `astro.config.mjs` as it is.
150
+ If the module already exports scripts, combine the two arrays.
151
+
152
+ ```ts title="src/c15t.client.ts"
153
+ import type { C15tClientOptionsExtension } from 'c15t/astro';
154
+ import { scripts } from './consent-scripts';
155
+
156
+ export default { scripts } satisfies C15tClientOptionsExtension;
157
+ ```
158
+
159
+ Vendor helpers contain callbacks, and the integration options in
160
+ `astro.config.mjs` are serialized into the page, so do not put helpers in
161
+ the integration's `scripts` option. The integration passes the client
162
+ entrypoint to the one runtime every page shares, including across
163
+ `ClientRouter` navigation.
164
+
165
+ **Svelte**
166
+
167
+ Import the scripts in the component that owns your existing provider and
168
+ pass them as a top-level prop:
169
+
170
+ ```svelte title="src/App.svelte"
171
+ <script lang="ts">
172
+ import { ConsentProvider, manifest } from '@c15t/svelte';
173
+ import { scripts } from './consent-scripts';
174
+ </script>
175
+
176
+ <ConsentProvider mode={manifest()} {scripts}>
177
+ <!-- Keep your application, consent UI and preferences link here. -->
178
+ </ConsentProvider>
179
+ ```
180
+
181
+ Retain the styles and consent UI from the [Svelte quickstart](https://c15t.com/docs/frameworks/svelte/quickstart).
182
+ The provider owns the loader and disposes it on unmount.
183
+
184
+ **SvelteKit**
185
+
186
+ Add the scripts to the existing `ConsentRoot` in the root layout. Keep the
187
+ handle and the layout load from the [SvelteKit quickstart](https://c15t.com/docs/frameworks/sveltekit/quickstart).
188
+
189
+ ```svelte title="src/routes/+layout.svelte"
190
+ <script lang="ts">
191
+ import { ConsentRoot } from '@c15t/svelte';
192
+ import { scripts } from '../consent-scripts';
193
+
194
+ let { children, data } = $props();
195
+ </script>
196
+
197
+ <ConsentRoot state={data.consent} {scripts}>
198
+ {@render children()}
199
+ <!-- Keep your consent UI and preferences link here. -->
200
+ </ConsentRoot>
201
+ ```
202
+
203
+ Import vendor helpers in the layout component, not in `+layout.server.ts`:
204
+ a server load cannot send functions to the browser. Prerendered, static and
205
+ SPA-mode pages use the same `scripts` prop. If you pass an externally owned
206
+ `runtime` to the provider, register scripts when creating that runtime instead.
207
+
208
+ **HTML**
209
+
210
+ The helpers in `@c15t/integrations` are ES modules that need a bundler. On a
211
+ page that loads the c15t script tag, paste the vendor's own snippet instead
212
+ and keep it inert until its category is allowed:
213
+
214
+ ```html
215
+ <script type="text/plain" data-c15t-category="measurement">
216
+ // The vendor's snippet, unchanged
217
+ </script>
218
+ ```
219
+
220
+ Use the category this guide names for the vendor. c15t runs the snippet
221
+ once that category is allowed, and reloads the page when the visitor
222
+ withdraws it. Helper options on this page, such as `loadMode`, do not apply
223
+ to a pasted snippet. See [HTML scripts](https://c15t.com/docs/frameworks/html/scripts).
224
+
225
+ **JavaScript**
226
+
227
+ Pass the scripts to `init()` from `@c15t/browser`, next to your mode:
228
+
229
+ ```ts
230
+ import { init, manifest } from '@c15t/browser';
231
+ import { scripts } from './consent-scripts';
232
+
233
+ const consent = init({
234
+ mode: manifest(),
235
+ scripts,
236
+ });
237
+ ```
238
+
239
+ Keep the mode from your quickstart. With
240
+ `createConsentRuntime` from `c15t/runtime`, pass `scripts` to it instead.
241
+ A kernel you create yourself needs a loader from
242
+ `c15t/modules/script-loader`. Attach one loader per kernel. See
243
+ [JavaScript scripts](https://c15t.com/docs/frameworks/javascript/scripts).
244
+
245
+ ## Options
246
+
247
+ | Option | Default | Behavior |
248
+ | ------------ | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
249
+ | `dsn` | None | Project DSN for deployments outside Vercel, set as `data-dsn`. Reports go to Vercel's vitals endpoint for that DSN. |
250
+ | `mode` | None | `'development'` loads the debug script. `'auto'` and `'production'` load the production script. The helper does not detect your environment. |
251
+ | `debug` | None | `true` loads `https://va.vercel-scripts.com/v1/speed-insights/script.debug.js`, which logs reports to the console and sends nothing. |
252
+ | `endpoint` | None | Custom vitals endpoint, set as `data-endpoint`. |
253
+ | `scriptUrl` | `https://va.vercel-scripts.com/v1/speed-insights/script.js` | Loader URL override, such as `/_vercel/speed-insights/script.js` on Vercel. Takes precedence over `mode` and `debug`. |
254
+ | `sampleRate` | `1` | Share of page loads that report, from `0` to `1`, set as `data-sample-rate`. Other values throw a `TypeError`. |
255
+ | `beforeSend` | None | Edits or drops a report while measurement is allowed. Return the event, with a changed `url` if needed, or `null` to drop it. |
256
+
257
+ The helper also sets `data-sdkn="c15t"` on the script element. Without `dsn`
258
+ or `endpoint`, the collector posts to `/_vercel/speed-insights/vitals` on your
259
+ own origin, which exists only on Vercel deployments with Speed Insights on.
260
+
261
+ ## Loading and revocation
262
+
263
+ `vercelSpeedInsights` uses the `measurement` category. When measurement becomes
264
+ allowed, the helper defines the `window.siq` queue and a `window.si` stub,
265
+ unless they exist, registers a `beforeSend` callback and loads the script.
266
+
267
+ The collector keeps its listeners after its script element is removed and
268
+ sends queued reports on `pagehide` and navigation. On revocation the helper
269
+ removes the script element and its `beforeSend` callback starts returning
270
+ `null`, so no report is sent, including during the reload c15t runs on
271
+ revocation. A later grant re-adds the script, which does not start a second
272
+ collector, and reports resume. Reports also stop when the provider that owns
273
+ the scripts unmounts.
274
+
275
+ The collector holds one `beforeSend` callback. Pass yours through the
276
+ `beforeSend` option. Calling `window.si('beforeSend', ...)` yourself replaces
277
+ the helper's consent check.
278
+
279
+ Reports only cover page loads after consent. The collector reads buffered
280
+ paint and navigation timings, but interactions before consent are missed. The
281
+ helper does not set `data-route`, so Vercel groups reports by URL rather than
282
+ by route pattern such as `/blog/[slug]`.
283
+
284
+ ## Verify Vercel Speed Insights
285
+
286
+ Filter DevTools Network by `speed-insights`. After you allow measurement,
287
+ `script.js` loads from `va.vercel-scripts.com` with `data-sdkn="c15t"`. Change
288
+ route or switch tabs, and a `POST` to `/_vercel/speed-insights/vitals` follows.
289
+ Automated browsers that set `navigator.webdriver` load the collector but send
290
+ nothing. With `debug` or `mode: 'development'` the reports appear in the
291
+ console instead.
292
+
293
+ Test in a private window with an opt-in policy. Open DevTools Network, disable
294
+ the cache and filter by the vendor's domain:
295
+
296
+ 1. Load the page. No request goes to the vendor before you choose.
297
+ 2. Click Reject, then reload. There is still no vendor request.
298
+ 3. Open Privacy settings and allow the helper's category. The vendor script
299
+ loads without a page reload.
300
+ 4. Turn the category off again and save. c15t reloads the page, and the new
301
+ page makes no vendor request.
302
+
303
+ c15t reloads on revocation because removing a script element does not stop
304
+ code that already ran. The vendor's listeners, timers and queued events stay
305
+ alive until the page unloads. If you set `reloadOnConsentRevoked: false`, stop
306
+ the vendor yourself. Register a callback-only script whose `onConsentChange`
307
+ calls the vendor's opt-out API, as shown in
308
+ [custom integrations](./building-integrations.md), and check the
309
+ permission before each of your own event calls. The reload does not delete
310
+ cookies the vendor already set; see
311
+ [clear on revocation for your framework](./overview.md#vendor-switches-and-cookie-cleanup).
312
+
313
+ The helper lists its vendor by name in the preference dialog, so a visitor can
314
+ turn it off inside an allowed category. See
315
+ [vendor consent for your framework](./overview.md#vendor-switches-and-cookie-cleanup). The
316
+ [consent verification guide](../guides/verify-consent.md) covers navigation,
317
+ expiry and hosting checks.
@@ -2,21 +2,29 @@
2
2
  title: X Pixel
3
3
  description: Load the X Pixel only after marketing consent with the c15t xPixel
4
4
  helper, guard twq conversion events, and check it in DevTools.
5
+ seoTitle: X Pixel cookie consent with c15t
6
+ seoDescription: Load the X Pixel only with marketing consent. The c15t xPixel
7
+ helper keeps uwt.js off the page until then.
5
8
  icon: x
6
9
  group: integrations
7
10
  ---
8
11
 
12
+ The c15t `xPixel` helper keeps the X Pixel off the page until `marketing` has
13
+ consent. Until then, c15t does not define `twq`. X has no API to update consent,
14
+ so the helper sends no consent signal to X. If the visitor withdraws consent,
15
+ c15t removes the script element. By default, c15t also reloads the page.
16
+
9
17
  ## Configure the X Pixel
10
18
 
11
19
  Copy your X Pixel ID. The helper passes it to `twq('config', ...)`. Conversion
12
20
  event IDs, which look like `tw-xxxx-xxxx`, are separate from the pixel ID.
13
21
 
14
- | Package manager | Command |
15
- | :-------------- | :------------------------------------- |
16
- | npm | `npm install @c15t/integrations@alpha` |
17
- | pnpm | `pnpm add @c15t/integrations@alpha` |
18
- | yarn | `yarn add @c15t/integrations@alpha` |
19
- | bun | `bun add @c15t/integrations@alpha` |
22
+ | Package manager | Command |
23
+ | :-------------- | :------------------------------- |
24
+ | npm | `npm install @c15t/integrations` |
25
+ | pnpm | `pnpm add @c15t/integrations` |
26
+ | yarn | `yarn add @c15t/integrations` |
27
+ | bun | `bun add @c15t/integrations` |
20
28
 
21
29
  ```ts title="src/consent-scripts.ts"
22
30
  import { xPixel } from '@c15t/integrations/x-pixel';
@@ -31,51 +39,41 @@ endpoint, policy, styles and consent UI. Remove the vendor's original script,
31
39
  SDK initializer or tag-manager entry, so the vendor loads only through c15t.
32
40
 
33
41
  The vendor pages put the helper in `src/consent-scripts.ts`. If your framework
34
- quickstart already created a scripts file, such as `lib/scripts.ts` in the
35
- Next.js guide, add the helper to that array instead of creating a second file.
42
+ quickstart already has a `scripts` array, such as the one in `c15t.config.ts`
43
+ in the Next.js guide, add the helper to that array instead of creating a
44
+ second file.
36
45
  The `scripts` export is a configuration, not an initializer. Add it to the c15t provider you already have, at the registration
37
46
  point for your framework below. These are edits to that provider, not a second
38
47
  provider.
39
48
 
40
49
  **Next.js**
41
50
 
42
- Import the configuration into the client boundary from your router guide:
43
-
44
- ```ts
45
- import { ConsentRoot } from 'c15t/next';
46
- import { scripts } from './consent-scripts';
47
- ```
51
+ Add the configuration to `scripts` in `c15t.config.ts`, next to
52
+ `next.config.ts`:
48
53
 
49
- Keep the server-resolved `state` and shared `consentConfig` from your
50
- router guide. Its manifest, init and save URLs stay in effect. Add
51
- `scripts` as a top-level prop on the existing root:
54
+ ```ts title="c15t.config.ts"
55
+ import { defineConsentConfig } from 'c15t/next';
56
+ import { scripts } from './src/consent-scripts';
52
57
 
53
- ```tsx
54
- <ConsentRoot state={state} config={consentConfig} scripts={scripts}>
55
- {children}
56
- </ConsentRoot>
58
+ export default defineConsentConfig({ scripts });
57
59
  ```
58
60
 
59
- App Router, Pages Router and static export all use this `ConsentRoot` in
60
- the `'use client'` wrapper `components/consent.tsx`. Keep `scripts` there,
61
- because a Server Component cannot pass script callbacks to it. See
61
+ Keep the rest of your config, such as `mode` and `routePrefix`, in the
62
+ same call. `ConsentRoot` reads the config in the browser, so the layout
63
+ keeps passing only `state`. App Router, Pages Router and static export all
64
+ read the same file. See
62
65
  [Next.js scripts and embeds](https://c15t.com/docs/frameworks/next/scripts).
63
66
 
64
67
  **TanStack Start**
65
68
 
66
69
  Import the configuration into your root route and pass it to the existing
67
- `ConsentRoot` as a top-level prop. Keep the loader, `backendURL` and
68
- `initRoute` from the [TanStack Start quickstart](https://c15t.com/docs/frameworks/tanstack-start/quickstart):
70
+ `ConsentRoot` as a top-level prop. Keep the loader from the
71
+ [TanStack Start quickstart](https://c15t.com/docs/frameworks/tanstack-start/quickstart):
69
72
 
70
73
  ```tsx title="src/routes/__root.tsx"
71
74
  import { scripts } from '../consent-scripts';
72
75
 
73
- <ConsentRoot
74
- state={consent}
75
- backendURL={backendURL}
76
- initRoute={false}
77
- scripts={scripts}
78
- >
76
+ <ConsentRoot state={consent} scripts={scripts}>
79
77
  ```
80
78
 
81
79
  Import vendor helpers in the root route module, not in a server function.
@@ -94,8 +92,8 @@ import { scripts } from './consent-scripts';
94
92
  <ConsentProvider options={{ mode, scripts }}>
95
93
  ```
96
94
 
97
- `mode` is the `hosted({ url: 'https://your-project.inth.app' })` value
98
- from the [React quickstart](../frameworks/react/quickstart.md). Keep the banner,
95
+ `mode` is the `manifest()` value from the
96
+ [React quickstart](../frameworks/react/quickstart.md). Keep the banner,
99
97
  dialog and preferences link inside the provider. See
100
98
  [React scripts and embeds](../frameworks/react/scripts.md).
101
99
 
@@ -124,15 +122,16 @@ callbacks. Write the vendor IDs into `consent-scripts.ts`. See
124
122
  Pass the scripts to the existing `c15tVue` plugin call in `src/main.ts`:
125
123
 
126
124
  ```ts title="src/main.ts"
125
+ import { c15tVue, manifest } from 'c15t/vue/vue-plugin';
127
126
  import { scripts } from './consent-scripts';
128
127
 
129
128
  app.use(c15tVue, {
130
- backendURL: 'https://your-project.inth.app',
129
+ mode: manifest(),
131
130
  scripts,
132
131
  });
133
132
  ```
134
133
 
135
- Keep your existing backend URL and other options. The plugin starts one
134
+ Keep your existing `mode` and other options. The plugin starts one
136
135
  script loader when the app mounts, after it has applied the visitor's stored
137
136
  choice. Do not also call `createScriptLoader` from a component. See
138
137
  [Vue scripts and embeds](https://c15t.com/docs/frameworks/vue/scripts).
@@ -140,12 +139,11 @@ choice. Do not also call `createScriptLoader` from a component. See
140
139
  **Astro**
141
140
 
142
141
  Add the scripts to the client entrypoint from the
143
- [Astro quickstart](https://c15t.com/docs/frameworks/astro/quickstart), the module that the
144
- integration's `clientEntrypoint` option names. Keep `mode`, `ui` and the
145
- framework integration in `astro.config.mjs` as they are. If the module
146
- already exports scripts, combine the two arrays.
142
+ [Astro quickstart](https://c15t.com/docs/frameworks/astro/quickstart), `src/c15t.client.ts`,
143
+ which the integration finds on its own. Keep `astro.config.mjs` as it is.
144
+ If the module already exports scripts, combine the two arrays.
147
145
 
148
- ```ts title="src/consent-client.ts"
146
+ ```ts title="src/c15t.client.ts"
149
147
  import type { C15tClientOptionsExtension } from 'c15t/astro';
150
148
  import { scripts } from './consent-scripts';
151
149
 
@@ -165,15 +163,13 @@ pass them as a top-level prop:
165
163
 
166
164
  ```svelte title="src/App.svelte"
167
165
  <script lang="ts">
168
- import { ConsentManagerProvider, hosted } from '@c15t/svelte';
166
+ import { ConsentProvider, manifest } from '@c15t/svelte';
169
167
  import { scripts } from './consent-scripts';
170
-
171
- const mode = hosted({ url: 'https://your-project.inth.app' });
172
168
  </script>
173
169
 
174
- <ConsentManagerProvider {mode} {scripts}>
170
+ <ConsentProvider mode={manifest()} {scripts}>
175
171
  <!-- Keep your application, consent UI and preferences link here. -->
176
- </ConsentManagerProvider>
172
+ </ConsentProvider>
177
173
  ```
178
174
 
179
175
  Retain the styles and consent UI from the [Svelte quickstart](https://c15t.com/docs/frameworks/svelte/quickstart).
@@ -181,22 +177,21 @@ The provider owns the loader and disposes it on unmount.
181
177
 
182
178
  **SvelteKit**
183
179
 
184
- Add the scripts to the existing root layout provider. Keep the server load
185
- and its serializable prefetch data from the [SvelteKit quickstart](https://c15t.com/docs/frameworks/sveltekit/quickstart).
180
+ Add the scripts to the existing `ConsentRoot` in the root layout. Keep the
181
+ handle and the layout load from the [SvelteKit quickstart](https://c15t.com/docs/frameworks/sveltekit/quickstart).
186
182
 
187
183
  ```svelte title="src/routes/+layout.svelte"
188
184
  <script lang="ts">
189
- import { ConsentManagerProvider, hosted } from '@c15t/svelte';
185
+ import { ConsentRoot } from '@c15t/svelte';
190
186
  import { scripts } from '../consent-scripts';
191
187
 
192
188
  let { children, data } = $props();
193
- const mode = hosted({ url: 'https://your-project.inth.app' });
194
189
  </script>
195
190
 
196
- <ConsentManagerProvider {mode} {scripts} prefetch={data.prefetch}>
191
+ <ConsentRoot state={data.consent} {scripts}>
197
192
  {@render children()}
198
193
  <!-- Keep your consent UI and preferences link here. -->
199
- </ConsentManagerProvider>
194
+ </ConsentRoot>
200
195
  ```
201
196
 
202
197
  Import vendor helpers in the layout component, not in `+layout.server.ts`:
@@ -223,20 +218,19 @@ to a pasted snippet. See [HTML scripts](https://c15t.com/docs/frameworks/html/sc
223
218
 
224
219
  **JavaScript**
225
220
 
226
- Pass the scripts to `init()` from `@c15t/browser`, next to your backend
227
- URL:
221
+ Pass the scripts to `init()` from `@c15t/browser`, next to your mode:
228
222
 
229
223
  ```ts
230
- import { init } from '@c15t/browser';
224
+ import { init, manifest } from '@c15t/browser';
231
225
  import { scripts } from './consent-scripts';
232
226
 
233
227
  const consent = init({
234
- backendURL: 'https://your-project.inth.app',
228
+ mode: manifest(),
235
229
  scripts,
236
230
  });
237
231
  ```
238
232
 
239
- Keep the backend URL from your quickstart. With
233
+ Keep the mode from your quickstart. With
240
234
  `createConsentRuntime` from `c15t/runtime`, pass `scripts` to it instead.
241
235
  A kernel you create yourself needs a loader from
242
236
  `c15t/modules/script-loader`. Attach one loader per kernel. See
@@ -244,10 +238,10 @@ A kernel you create yourself needs a loader from
244
238
 
245
239
  ## Options
246
240
 
247
- | Option | Default | Behavior |
248
- | ----------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------- |
249
- | `pixelId` | Required | Pixel ID passed to `twq('config', ...)`. The helper trims it. Empty or whitespace-only values throw. |
250
- | `scriptSrc` | `https://static.ads-twitter.com/uwt.js` | Loader URL override. A blank value falls back to the default. |
241
+ | Option | Default | Behavior |
242
+ | ----------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
243
+ | `pixelId` | Required | Pixel ID passed to `twq('config', ...)`. The helper trims it. Empty or whitespace-only values log an error and the script does not load. |
244
+ | `scriptSrc` | `https://static.ads-twitter.com/uwt.js` | Loader URL override. A blank value falls back to the default. |
251
245
 
252
246
  ## Loading and revocation
253
247
 
@@ -310,8 +304,8 @@ permission before each of your own event calls. The reload does not delete
310
304
  cookies the vendor already set; see
311
305
  [clear on revocation for your framework](./overview.md#vendor-switches-and-cookie-cleanup).
312
306
 
313
- The helper sets `vendor` to its script ID, so once you declare that vendor a
314
- visitor can turn it off inside an allowed category. See
307
+ The helper lists its vendor by name in the preference dialog, so a visitor can
308
+ turn it off inside an allowed category. See
315
309
  [vendor consent for your framework](./overview.md#vendor-switches-and-cookie-cleanup). The
316
310
  [consent verification guide](../guides/verify-consent.md) covers navigation,
317
311
  expiry and hosting checks.
@@ -2,10 +2,22 @@
2
2
  title: YouTube
3
3
  description: Gate YouTube embeds with c15t v3 in Next.js, TanStack Start, React,
4
4
  Nuxt, Vue, Astro, Svelte, SvelteKit or JavaScript.
5
+ seoTitle: YouTube embed cookie consent with c15t
6
+ seoDescription: Show YouTube videos only with consent. c15t loads the video
7
+ iframe only when its category has consent, in Next.js, React, Vue, Svelte,
8
+ Astro and HTML.
5
9
  icon: youtube
6
10
  group: integrations
7
11
  ---
8
12
 
13
+ c15t has no YouTube helper. This guide puts a YouTube iframe inside each
14
+ framework's `ConsentGate`, or uses `data-category` with the HTML script tag. The
15
+ example uses the `marketing` category, but you can choose a different category.
16
+ Until that category has consent, the page has no iframe that loads a YouTube
17
+ URL, so the browser does not connect to YouTube. If the visitor withdraws
18
+ consent, `ConsentGate` removes the iframe. With `data-category`, c15t moves the
19
+ URL from `src` to `data-src`.
20
+
9
21
  ## Configure the video
10
22
 
11
23
  Use the ID of an embeddable video and the category matching its purpose in your
@@ -112,7 +124,7 @@ on revocation. Keep your existing consent styles and preferences dialog.
112
124
 
113
125
  **Nuxt**
114
126
 
115
- The Nuxt module registers `ConsentGate` and `ConsentPreferencesLink`, so
127
+ The Nuxt module registers `ConsentGate` and `ConsentDialogLink`, so
116
128
  this component imports only the embed configuration.
117
129
 
118
130
  ```vue title="app/components/ConsentEmbed.vue"
@@ -131,7 +143,7 @@ import { embedCategory, embedURL, embedTitle, embedAspectRatio } from '../../src
131
143
  />
132
144
  <template #placeholder>
133
145
  <p>Allow {{ embedCategory }} to load this content.</p>
134
- <ConsentPreferencesLink>Open privacy settings</ConsentPreferencesLink>
146
+ <ConsentDialogLink>Open privacy settings</ConsentDialogLink>
135
147
  </template>
136
148
  </ConsentGate>
137
149
  </template>
@@ -147,8 +159,7 @@ Render this component inside the app that installed the c15t Vue plugin.
147
159
 
148
160
  ```vue title="src/ConsentEmbed.vue"
149
161
  <script setup lang="ts">
150
- import ConsentGate from 'c15t/vue/runtime/components/consent-gate.vue';
151
- import ConsentPreferencesLink from 'c15t/vue/runtime/components/consent-preferences-link.vue';
162
+ import { ConsentDialogLink, ConsentGate } from 'c15t/vue/vue-plugin';
152
163
  import { embedCategory, embedURL, embedTitle, embedAspectRatio } from './embed-config';
153
164
  </script>
154
165
 
@@ -163,7 +174,7 @@ import { embedCategory, embedURL, embedTitle, embedAspectRatio } from './embed-c
163
174
  />
164
175
  <template #placeholder>
165
176
  <p>Allow {{ embedCategory }} to load this content.</p>
166
- <ConsentPreferencesLink>Open privacy settings</ConsentPreferencesLink>
177
+ <ConsentDialogLink>Open privacy settings</ConsentDialogLink>
167
178
  </template>
168
179
  </ConsentGate>
169
180
  </template>
@@ -224,7 +235,7 @@ runtime for this embed.
224
235
 
225
236
  **Svelte**
226
237
 
227
- Render this component inside the existing `ConsentManagerProvider`.
238
+ Render this component inside the existing `ConsentProvider`.
228
239
  The provider from your quickstart supplies its consent state.
229
240
 
230
241
  ```svelte title="src/ConsentEmbed.svelte"
@@ -253,8 +264,8 @@ iframe.
253
264
 
254
265
  **SvelteKit**
255
266
 
256
- Render this component inside the existing `ConsentManagerProvider`.
257
- Keep the SvelteKit root provider and its server prefetch unchanged.
267
+ Render this component inside the existing `ConsentRoot`.
268
+ Keep the SvelteKit root and its server-resolved state unchanged.
258
269
 
259
270
  ```svelte title="src/lib/ConsentEmbed.svelte"
260
271
  <script lang="ts">
@@ -283,14 +294,15 @@ iframe.
283
294
  **HTML**
284
295
 
285
296
  The c15t script tag gates iframes that name a category. Put the embed's URL
286
- in `data-src` instead of `src`, using the values from the configuration on
287
- this page:
297
+ in `data-src` instead of `src`. Replace `EMBED_URL`, `EMBED_CATEGORY` and
298
+ `EMBED_TITLE` with `embedURL`, `embedCategory` and `embedTitle` from the
299
+ configuration on this page:
288
300
 
289
301
  ```html
290
302
  <iframe
291
- data-src="https://www.youtube-nocookie.com/embed/VIDEO_ID?playsinline=1"
292
- data-category="measurement"
293
- title="Product video"
303
+ data-src="EMBED_URL"
304
+ data-category="EMBED_CATEGORY"
305
+ title="EMBED_TITLE"
294
306
  loading="lazy"
295
307
  allowfullscreen
296
308
  ></iframe>