@c15t/scripts 3.0.0-alpha.1 → 3.0.0-alpha.3

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 (300) hide show
  1. package/AGENTS.md +129 -59
  2. package/README.md +8 -29
  3. package/SKILL.md +33 -0
  4. package/dist/adobe-analytics.js +2 -0
  5. package/dist/ahrefs-analytics.js +2 -0
  6. package/dist/amplitude.js +2 -0
  7. package/dist/clearbit.js +2 -0
  8. package/dist/cloudflare-web-analytics.js +2 -0
  9. package/dist/cloudflare-zaraz.js +2 -0
  10. package/dist/crisp.js +2 -0
  11. package/dist/databuddy.js +2 -0
  12. package/dist/e2e-test-utils.js +2 -137
  13. package/dist/engine/compile.js +2 -89
  14. package/dist/engine/runtime.js +2 -448
  15. package/dist/events.js +2 -0
  16. package/dist/fathom-analytics.js +2 -0
  17. package/dist/front-chat.js +2 -0
  18. package/dist/google-tag-manager.js +2 -0
  19. package/dist/google-tag.js +2 -0
  20. package/dist/heap.js +2 -0
  21. package/dist/hightouch.js +2 -0
  22. package/dist/hotjar.js +2 -0
  23. package/dist/intercom.js +2 -0
  24. package/dist/klaviyo.js +2 -0
  25. package/dist/linkedin-insights.js +2 -0
  26. package/dist/logrocket.js +2 -0
  27. package/dist/matomo-analytics.js +2 -0
  28. package/dist/meta-pixel.js +2 -0
  29. package/dist/microsoft-clarity.js +2 -0
  30. package/dist/microsoft-uet.js +2 -0
  31. package/dist/mixpanel-analytics.js +2 -0
  32. package/dist/one-dollar-stats.js +2 -0
  33. package/dist/openai-pixel.js +2 -0
  34. package/dist/pinterest-tag.js +2 -0
  35. package/dist/pirsch.js +2 -0
  36. package/dist/plausible-analytics.js +2 -0
  37. package/dist/posthog.js +2 -0
  38. package/dist/promptwatch.js +2 -0
  39. package/dist/reddit-pixel.js +2 -0
  40. package/dist/registry.js +2 -392
  41. package/dist/resolve.js +2 -33
  42. package/dist/rudderstack.js +2 -0
  43. package/dist/rybbit-analytics.js +2 -0
  44. package/dist/segment.js +2 -0
  45. package/dist/snapchat-pixel.js +2 -0
  46. package/dist/tiktok-pixel.js +2 -0
  47. package/dist/types.js +2 -16
  48. package/dist/umami-analytics.js +2 -0
  49. package/dist/vendors/_shared/attributes.js +2 -14
  50. package/dist/vendors/_shared/google-consent.js +2 -27
  51. package/dist/vendors/_shared/install-builders.js +2 -21
  52. package/dist/vendors/_shared/required-id.js +2 -0
  53. package/dist/vendors/_shared/script-url.js +2 -28
  54. package/dist/vendors/ads-and-pixels/linkedin-insights.js +2 -48
  55. package/dist/vendors/ads-and-pixels/meta-pixel.js +2 -153
  56. package/dist/vendors/ads-and-pixels/microsoft-uet.js +2 -110
  57. package/dist/vendors/ads-and-pixels/openai-pixel.js +2 -88
  58. package/dist/vendors/ads-and-pixels/pinterest-tag.js +2 -0
  59. package/dist/vendors/ads-and-pixels/reddit-pixel.js +2 -107
  60. package/dist/vendors/ads-and-pixels/snapchat-pixel.js +2 -87
  61. package/dist/vendors/ads-and-pixels/tiktok-pixel.js +2 -89
  62. package/dist/vendors/ads-and-pixels/x-pixel.js +2 -48
  63. package/dist/vendors/analytics/adobe-analytics.js +2 -49
  64. package/dist/vendors/analytics/ahrefs-analytics.js +2 -27
  65. package/dist/vendors/analytics/amplitude.js +2 -134
  66. package/dist/vendors/analytics/clearbit.js +2 -28
  67. package/dist/vendors/analytics/cloudflare-web-analytics.js +2 -32
  68. package/dist/vendors/analytics/databuddy.js +2 -103
  69. package/dist/vendors/analytics/fathom-analytics.js +2 -35
  70. package/dist/vendors/analytics/google-tag.js +2 -66
  71. package/dist/vendors/analytics/heap.js +2 -134
  72. package/dist/vendors/analytics/hightouch.js +2 -109
  73. package/dist/vendors/analytics/hotjar.js +2 -44
  74. package/dist/vendors/analytics/logrocket.js +2 -58
  75. package/dist/vendors/analytics/matomo-analytics.js +2 -191
  76. package/dist/vendors/analytics/microsoft-clarity.js +2 -100
  77. package/dist/vendors/analytics/mixpanel-analytics.js +2 -93
  78. package/dist/vendors/analytics/one-dollar-stats.js +2 -0
  79. package/dist/vendors/analytics/pirsch.js +2 -67
  80. package/dist/vendors/analytics/plausible-analytics.js +2 -81
  81. package/dist/vendors/analytics/posthog.js +2 -200
  82. package/dist/vendors/analytics/promptwatch.js +2 -29
  83. package/dist/vendors/analytics/rudderstack.js +2 -183
  84. package/dist/vendors/analytics/rybbit-analytics.js +2 -63
  85. package/dist/vendors/analytics/segment.js +2 -56
  86. package/dist/vendors/analytics/umami-analytics.js +2 -39
  87. package/dist/vendors/analytics/vercel-analytics.js +2 -53
  88. package/dist/vendors/email-and-sms/klaviyo.js +2 -0
  89. package/dist/vendors/functional/crisp.js +2 -100
  90. package/dist/vendors/functional/front-chat.js +2 -0
  91. package/dist/vendors/functional/intercom.js +2 -45
  92. package/dist/vendors/tag-managers/cloudflare-zaraz.js +2 -98
  93. package/dist/vendors/tag-managers/google-tag-manager.js +2 -59
  94. package/dist/vercel-analytics.js +2 -0
  95. package/dist/x-pixel.js +2 -0
  96. package/dist-types/adobe-analytics.d.ts +2 -0
  97. package/dist-types/ahrefs-analytics.d.ts +2 -0
  98. package/dist-types/amplitude.d.ts +2 -0
  99. package/dist-types/clearbit.d.ts +2 -0
  100. package/dist-types/cloudflare-web-analytics.d.ts +2 -0
  101. package/dist-types/cloudflare-zaraz.d.ts +2 -0
  102. package/dist-types/crisp.d.ts +2 -0
  103. package/dist-types/databuddy.d.ts +2 -0
  104. package/dist-types/e2e-test-utils.d.ts +2 -0
  105. package/dist-types/engine/compile.d.ts +2 -3
  106. package/dist-types/engine/runtime.d.ts +2 -3
  107. package/dist-types/events.d.ts +2 -0
  108. package/dist-types/fathom-analytics.d.ts +2 -0
  109. package/dist-types/front-chat.d.ts +2 -0
  110. package/dist-types/google-tag-manager.d.ts +2 -0
  111. package/dist-types/google-tag.d.ts +2 -0
  112. package/dist-types/heap.d.ts +2 -0
  113. package/dist-types/hightouch.d.ts +2 -0
  114. package/dist-types/hotjar.d.ts +2 -0
  115. package/dist-types/intercom.d.ts +2 -0
  116. package/dist-types/klaviyo.d.ts +2 -0
  117. package/dist-types/linkedin-insights.d.ts +2 -0
  118. package/dist-types/logrocket.d.ts +2 -0
  119. package/dist-types/matomo-analytics.d.ts +2 -0
  120. package/dist-types/meta-pixel.d.ts +2 -0
  121. package/dist-types/microsoft-clarity.d.ts +2 -0
  122. package/dist-types/microsoft-uet.d.ts +2 -0
  123. package/dist-types/mixpanel-analytics.d.ts +2 -0
  124. package/dist-types/one-dollar-stats.d.ts +2 -0
  125. package/dist-types/openai-pixel.d.ts +2 -0
  126. package/dist-types/pinterest-tag.d.ts +2 -0
  127. package/dist-types/pirsch.d.ts +2 -0
  128. package/dist-types/plausible-analytics.d.ts +2 -0
  129. package/dist-types/posthog.d.ts +2 -0
  130. package/dist-types/promptwatch.d.ts +2 -0
  131. package/dist-types/reddit-pixel.d.ts +2 -0
  132. package/dist-types/registry.d.ts +2 -458
  133. package/dist-types/resolve.d.ts +2 -9
  134. package/dist-types/rudderstack.d.ts +2 -0
  135. package/dist-types/rybbit-analytics.d.ts +2 -0
  136. package/dist-types/segment.d.ts +2 -0
  137. package/dist-types/snapchat-pixel.d.ts +2 -0
  138. package/dist-types/tiktok-pixel.d.ts +2 -0
  139. package/dist-types/types.d.ts +2 -314
  140. package/dist-types/umami-analytics.d.ts +2 -0
  141. package/dist-types/vendors/_shared/attributes.d.ts +2 -35
  142. package/dist-types/vendors/_shared/google-consent.d.ts +2 -47
  143. package/dist-types/vendors/_shared/install-builders.d.ts +2 -30
  144. package/dist-types/vendors/_shared/required-id.d.ts +2 -0
  145. package/dist-types/vendors/_shared/script-url.d.ts +2 -75
  146. package/dist-types/vendors/ads-and-pixels/linkedin-insights.d.ts +2 -92
  147. package/dist-types/vendors/ads-and-pixels/meta-pixel.d.ts +2 -289
  148. package/dist-types/vendors/ads-and-pixels/microsoft-uet.d.ts +2 -105
  149. package/dist-types/vendors/ads-and-pixels/openai-pixel.d.ts +2 -211
  150. package/dist-types/vendors/ads-and-pixels/pinterest-tag.d.ts +2 -0
  151. package/dist-types/vendors/ads-and-pixels/reddit-pixel.d.ts +2 -210
  152. package/dist-types/vendors/ads-and-pixels/snapchat-pixel.d.ts +2 -171
  153. package/dist-types/vendors/ads-and-pixels/tiktok-pixel.d.ts +2 -106
  154. package/dist-types/vendors/ads-and-pixels/x-pixel.d.ts +2 -183
  155. package/dist-types/vendors/analytics/adobe-analytics.d.ts +2 -75
  156. package/dist-types/vendors/analytics/ahrefs-analytics.d.ts +2 -62
  157. package/dist-types/vendors/analytics/amplitude.d.ts +2 -234
  158. package/dist-types/vendors/analytics/clearbit.d.ts +2 -60
  159. package/dist-types/vendors/analytics/cloudflare-web-analytics.d.ts +2 -67
  160. package/dist-types/vendors/analytics/databuddy.d.ts +2 -147
  161. package/dist-types/vendors/analytics/fathom-analytics.d.ts +2 -90
  162. package/dist-types/vendors/analytics/google-tag.d.ts +2 -93
  163. package/dist-types/vendors/analytics/heap.d.ts +2 -316
  164. package/dist-types/vendors/analytics/hightouch.d.ts +2 -285
  165. package/dist-types/vendors/analytics/hotjar.d.ts +2 -73
  166. package/dist-types/vendors/analytics/logrocket.d.ts +2 -101
  167. package/dist-types/vendors/analytics/matomo-analytics.d.ts +2 -41
  168. package/dist-types/vendors/analytics/microsoft-clarity.d.ts +2 -97
  169. package/dist-types/vendors/analytics/mixpanel-analytics.d.ts +2 -113
  170. package/dist-types/vendors/analytics/one-dollar-stats.d.ts +2 -0
  171. package/dist-types/vendors/analytics/pirsch.d.ts +2 -96
  172. package/dist-types/vendors/analytics/plausible-analytics.d.ts +2 -122
  173. package/dist-types/vendors/analytics/posthog.d.ts +2 -175
  174. package/dist-types/vendors/analytics/promptwatch.d.ts +2 -36
  175. package/dist-types/vendors/analytics/rudderstack.d.ts +2 -330
  176. package/dist-types/vendors/analytics/rybbit-analytics.d.ts +2 -82
  177. package/dist-types/vendors/analytics/segment.d.ts +2 -158
  178. package/dist-types/vendors/analytics/umami-analytics.d.ts +2 -93
  179. package/dist-types/vendors/analytics/vercel-analytics.d.ts +2 -66
  180. package/dist-types/vendors/email-and-sms/klaviyo.d.ts +2 -0
  181. package/dist-types/vendors/functional/crisp.d.ts +2 -78
  182. package/dist-types/vendors/functional/front-chat.d.ts +2 -0
  183. package/dist-types/vendors/functional/intercom.d.ts +2 -135
  184. package/dist-types/vendors/tag-managers/cloudflare-zaraz.d.ts +2 -39
  185. package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +2 -94
  186. package/dist-types/vercel-analytics.d.ts +2 -0
  187. package/dist-types/x-pixel.d.ts +2 -0
  188. package/docs/README.md +129 -59
  189. package/docs/assets/v3/bottom-bar.png +0 -0
  190. package/docs/assets/v3/brand-card.png +0 -0
  191. package/docs/assets/v3/brand-preferences.png +0 -0
  192. package/docs/assets/v3/choice-wall.png +0 -0
  193. package/docs/assets/v3/headless-bar-html.png +0 -0
  194. package/docs/assets/v3/headless-bar-mobile.png +0 -0
  195. package/docs/assets/v3/headless-bar.png +0 -0
  196. package/docs/assets/v3/slim-bar.png +0 -0
  197. package/docs/concepts/choose-your-setup.md +87 -0
  198. package/docs/concepts/consent-categories.md +84 -0
  199. package/docs/concepts/consent-state.md +357 -0
  200. package/docs/{guides → concepts}/data-fetching.md +31 -27
  201. package/docs/concepts/how-consent-works.md +123 -0
  202. package/docs/concepts/policies.md +71 -0
  203. package/docs/customization/class-names.md +202 -0
  204. package/docs/customization/dark-mode.md +157 -0
  205. package/docs/customization/motion.md +119 -0
  206. package/docs/customization/overview.md +67 -33
  207. package/docs/customization/recipes.md +839 -47
  208. package/docs/customization/slots.md +216 -35
  209. package/docs/customization/stylesheets.md +147 -0
  210. package/docs/customization/tailwind.md +842 -0
  211. package/docs/customization/tokens.md +166 -36
  212. package/docs/customization/translations.md +61 -3
  213. package/docs/frameworks/astro/embeds.md +160 -0
  214. package/docs/frameworks/astro/network-blocker.md +86 -0
  215. package/docs/frameworks/astro/scripts.md +146 -0
  216. package/docs/frameworks/html/embeds.md +142 -0
  217. package/docs/frameworks/html/network-blocker.md +105 -0
  218. package/docs/frameworks/html/scripts.md +164 -0
  219. package/docs/frameworks/javascript/scripts.md +119 -0
  220. package/docs/frameworks/next/embeds.md +90 -0
  221. package/docs/frameworks/next/network-blocker.md +153 -0
  222. package/docs/frameworks/next/scripts.md +196 -0
  223. package/docs/frameworks/nuxt/embeds.md +81 -0
  224. package/docs/frameworks/nuxt/network-blocker.md +97 -0
  225. package/docs/frameworks/nuxt/scripts.md +89 -0
  226. package/docs/frameworks/react/embeds.md +89 -0
  227. package/docs/frameworks/react/network-blocker.md +140 -0
  228. package/docs/frameworks/react/scripts.md +115 -0
  229. package/docs/frameworks/svelte/embeds.md +96 -0
  230. package/docs/frameworks/svelte/network-blocker.md +141 -0
  231. package/docs/frameworks/svelte/scripts.md +137 -0
  232. package/docs/frameworks/sveltekit/embeds.md +103 -0
  233. package/docs/frameworks/sveltekit/network-blocker.md +149 -0
  234. package/docs/frameworks/sveltekit/scripts.md +141 -0
  235. package/docs/frameworks/tanstack-start/embeds.md +96 -0
  236. package/docs/frameworks/tanstack-start/network-blocker.md +145 -0
  237. package/docs/frameworks/tanstack-start/scripts.md +103 -0
  238. package/docs/frameworks/vue/embeds.md +84 -0
  239. package/docs/frameworks/vue/network-blocker.md +99 -0
  240. package/docs/frameworks/vue/scripts.md +93 -0
  241. package/docs/guides/banner-experiments.md +654 -0
  242. package/docs/guides/troubleshooting.md +120 -47
  243. package/docs/guides/verify-consent.md +81 -49
  244. package/docs/integrations/adobe-analytics.md +168 -160
  245. package/docs/integrations/ahrefs-analytics.md +153 -155
  246. package/docs/integrations/amplitude.md +163 -157
  247. package/docs/integrations/building-integrations.md +136 -37
  248. package/docs/integrations/clearbit.md +155 -155
  249. package/docs/integrations/cloudflare-web-analytics.md +157 -157
  250. package/docs/integrations/cloudflare-zaraz.md +210 -262
  251. package/docs/integrations/crisp.md +165 -159
  252. package/docs/integrations/databuddy.md +158 -174
  253. package/docs/integrations/fathom-analytics.md +159 -157
  254. package/docs/integrations/front-chat.md +322 -0
  255. package/docs/integrations/google-maps.md +119 -84
  256. package/docs/integrations/google-tag-manager.md +179 -164
  257. package/docs/integrations/google-tag.md +164 -161
  258. package/docs/integrations/heap.md +164 -156
  259. package/docs/integrations/hightouch.md +162 -158
  260. package/docs/integrations/hotjar.md +160 -156
  261. package/docs/integrations/intercom.md +184 -154
  262. package/docs/integrations/klaviyo.md +486 -0
  263. package/docs/integrations/linkedin-insights.md +175 -151
  264. package/docs/integrations/logrocket.md +161 -157
  265. package/docs/integrations/matomo-analytics.md +189 -179
  266. package/docs/integrations/meta-pixel.md +189 -151
  267. package/docs/integrations/microsoft-clarity.md +164 -156
  268. package/docs/integrations/microsoft-uet.md +149 -155
  269. package/docs/integrations/mixpanel-analytics.md +156 -161
  270. package/docs/integrations/one-dollar-stats.md +306 -0
  271. package/docs/integrations/openai-pixel.md +205 -302
  272. package/docs/integrations/overview.md +143 -83
  273. package/docs/integrations/pinterest-tag.md +329 -0
  274. package/docs/integrations/pirsch.md +170 -160
  275. package/docs/integrations/plausible-analytics.md +173 -159
  276. package/docs/integrations/posthog.md +227 -242
  277. package/docs/integrations/promptwatch.md +155 -155
  278. package/docs/integrations/reddit-pixel.md +186 -158
  279. package/docs/integrations/rudderstack.md +202 -187
  280. package/docs/integrations/rybbit-analytics.md +172 -161
  281. package/docs/integrations/segment.md +183 -155
  282. package/docs/integrations/snapchat-pixel.md +187 -157
  283. package/docs/integrations/tiktok-pixel.md +172 -151
  284. package/docs/integrations/umami-analytics.md +164 -159
  285. package/docs/integrations/vercel-analytics.md +167 -158
  286. package/docs/integrations/x-pixel.md +177 -151
  287. package/docs/integrations/youtube.md +122 -87
  288. package/docs/upgrade-v3.md +490 -354
  289. package/package.json +12 -236
  290. package/dist-types/__tests__/helpers.d.ts +0 -141
  291. package/docs/assets/v3/brand-bar.png +0 -0
  292. package/docs/assets/v3/mobile-card.png +0 -0
  293. package/docs/assets/v3/preferences.png +0 -0
  294. package/docs/frameworks/javascript/script-loader.md +0 -94
  295. package/docs/frameworks/next/script-loader.md +0 -210
  296. package/docs/frameworks/react/script-loader.md +0 -63
  297. package/docs/guides/consent-state.md +0 -60
  298. package/docs/guides/deployment-modes.md +0 -75
  299. package/docs/integrations/clear-on-revocation.md +0 -167
  300. package/docs/integrations/granular-consent.md +0 -208
@@ -1,68 +1,141 @@
1
1
  ---
2
- title: Troubleshoot consent
3
- description: Diagnose missing banners, early vendor requests, lost choices and
4
- hydration differences.
2
+ title: Troubleshooting
3
+ description: Fix a missing banner, analytics that load before consent, choices
4
+ lost on reload, CORS errors, hydration differences and failed static builds in
5
+ c15t v3.
5
6
  group: guides
6
7
  ---
7
8
 
9
+ ## Start with three checks
10
+
11
+ Most problems show up in one of these places. Run them before changing code.
12
+
13
+ 1. **Which c15t is running.** In the browser console, run `window.c15t`. v3
14
+ prints `{ version, pkg, mode }`, for example `mode: 'manifest'` from
15
+ `@c15t/nextjs`. `undefined` means no c15t provider has mounted on this
16
+ page. A `window.c15tStore` object means the page runs v2. With the script
17
+ tag, `window.c15t` is the full browser API instead.
18
+ 2. **The backend request.** In DevTools Network, filter by your backend URL.
19
+ Look for `/init` or `/manifest` and check its status. A CORS error means
20
+ the backend does not trust your site's origin.
21
+ 3. **Consent state.** Add the c15t DevTools panel from your framework's guide.
22
+ It shows the resolved policy, whether a prompt is needed, each category's
23
+ permission and the scripts c15t manages.
24
+
25
+ Your framework's troubleshooting page covers adapter-specific failures, such
26
+ as Next.js prerendering errors or SvelteKit hydration.
27
+
28
+ ## "Can't resolve 'c15t/next'" or a missing export
29
+
30
+ npm's `latest` tag still points to c15t v2, which has no framework entry
31
+ points. A plain `npm install c15t` therefore installs v2, and imports such as
32
+ `c15t/next`, `c15t/react` or `ConsentRoot` fail with "Package subpath is not
33
+ defined by exports" or "Module not found".
34
+
35
+ Install the v3 release and check the lockfile:
36
+
37
+ | Package manager | Command |
38
+ | :-------------- | :----------------------- |
39
+ | npm | `npm install c15t@alpha` |
40
+ | pnpm | `pnpm add c15t@alpha` |
41
+ | yarn | `yarn add c15t@alpha` |
42
+ | bun | `bun add c15t@alpha` |
43
+
44
+ Keep every c15t package, including `@c15t/integrations`, on the same release.
45
+ Mixing v2 and v3 packages is not supported.
46
+
8
47
  ## Why is there no banner?
9
48
 
10
- Inspect `resolution` and `promptRequirement` before changing styles. Pending or
11
- failed initialization, no matching rule, a valid stored choice and a rule that
12
- requires no prompt can all produce no banner for different reasons. A missing
13
- stylesheet can also make rendered controls appear incorrectly.
49
+ No banner is sometimes correct. Find out which case you have:
50
+
51
+ | What DevTools shows | Cause | Fix |
52
+ | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
53
+ | The backend request failed or has a CORS error | Wrong backend URL, or your origin is not trusted | Copy the URL from your Inth project exactly, including any path. Add the site's origin, such as `https://www.example.com` or `http://localhost:3000`, to the project's trusted origins. |
54
+ | Requests go to `your-project.inth.app` and fail | The placeholder backend URL from the guides is still in your code | Replace `https://your-project.inth.app` with the URL from your Inth project, including any path prefix. |
55
+ | No backend request at all | No provider mounted, or the provider runs in offline mode | Check `window.c15t`. Confirm the provider receives `hosted()` with your backend URL, or the `backendURL` option your framework uses. |
56
+ | The policy resolved and no prompt is needed | The visitor's location maps to a policy without a prompt, such as a US state without a privacy law in the recommended rules | Expected. Test from a location that needs a prompt. Server helpers such as Next.js `resolveConsent` accept a `country` override for testing; remove it before you deploy. |
57
+ | The policy resolved and a choice is stored | A returning visitor | Expected. Clear site data or use a private window. |
58
+ | The banner is in the DOM but invisible or unstyled | The stylesheet is missing, or loaded before Tailwind CSS 4 | Import your framework's c15t stylesheet from your global CSS. See [customization](../customization/overview.md). |
59
+
60
+ Do not "fix" a missing banner by granting every category or turning c15t off.
61
+ While the policy is unresolved, every optional category stays denied. Turning
62
+ the runtime off lets optional scripts load.
63
+
64
+ ## Why does analytics load before the visitor chooses?
65
+
66
+ c15t only controls scripts you register with it. Find every other loader:
67
+
68
+ * A `<script>` tag in your HTML, layout or `_document`.
69
+ * A framework plugin, such as `@next/third-parties`, `nuxt-gtag` or a Vercel
70
+ or Netlify analytics toggle.
71
+ * A tag in Google Tag Manager that fires on page view.
72
+ * An embed, such as a YouTube iframe, rendered without `ConsentGate`.
73
+
74
+ Remove the extra loader and register the vendor through
75
+ [integrations](../integrations/overview.md). Then reload with the Network panel
76
+ open and cache disabled. The vendor's domain should be absent until you allow
77
+ its category.
78
+
79
+ Also check the policy. Under an opt-out policy, optional categories are allowed
80
+ before a choice, so the request is expected.
14
81
 
15
- Check the backend URL and Network response, then confirm the active policy for
16
- the visitor's location. Do not solve missing UI by granting every category or
17
- setting `enabled: false`: disabling the runtime permits optional loading.
82
+ Google Tag and Google Tag Manager are an exception by design. Their helpers
83
+ load before a choice and send Google Consent Mode signals, so a request to
84
+ Google before consent is expected. If you need no request at all before
85
+ consent, read [Google Tag Manager](../integrations/google-tag-manager.md) first.
18
86
 
19
- ## Why does the UI disappear with a content blocker?
87
+ ## Why does the choice disappear on reload?
20
88
 
21
- Check the browser Network panel for `ERR_BLOCKED_BY_CLIENT` or a failed dynamic
22
- import. Older c15t builds used component filenames such as
23
- `consent-dialog-*.js`, which some cookie-annoyance lists block. Update the c15t
24
- packages and rebuild the app. Current component modules use neutral filenames;
25
- public component imports stay the same. This also covers Vite development
26
- requests used by TanStack Start and other Vite integrations.
89
+ | Check | Fix |
90
+ | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
91
+ | After saving, does DevTools Application show a `c15t` cookie and a `c15t` localStorage entry? | If not, look for `persistence: false` in your config. Examples use it on purpose; production apps should not. |
92
+ | Does the browser block storage, for example in a sandboxed iframe or a strict privacy mode? | The choice works for the current page only. Nothing to fix in your app. |
93
+ | Did the domain, subdomain or protocol change between visits? | Cookies and localStorage are per origin. Serve the site from one origin, or share the cookie across subdomains. |
94
+ | Did the policy change since the visitor chose? | A changed policy, a new required category or an expired choice prompts again. This is intended. |
27
95
 
28
- Extensions can separately hide elements with cosmetic filters or block a
29
- configured backend URL. Check the failed request or hidden element to distinguish
30
- those cases from a missing component module.
96
+ Never save a choice automatically on page load to make persistence "stick".
97
+ That records consent the visitor did not give.
31
98
 
32
- ## Why does analytics run before a choice?
99
+ ## Why does the page reload after saving preferences?
33
100
 
34
- Check effective permission under the selected policy, then find every loader
35
- for that vendor. Remove unconditional script tags, framework analytics plugins
36
- and duplicate tag-manager entries. c15t's script registration only controls the
37
- scripts registered with it.
101
+ A visitor turned off a category or vendor they had allowed. Scripts that
102
+ already ran cannot be unloaded, so c15t reloads the page to start clean with
103
+ only permitted code. Set `reloadOnConsentRevoked: false` if you clean up
104
+ revoked vendors yourself; [clear on revocation for your framework](../integrations/overview.md#vendor-switches-and-cookie-cleanup)
105
+ covers the options.
38
106
 
39
- Google helpers intentionally load with Consent Mode defaults. A Google request
40
- is not by itself proof that its storage consent was granted. If your requirement
41
- is no request at all, do not use an always-loaded helper unchanged.
107
+ ## Why does the server HTML differ from the browser?
42
108
 
43
- ## Why does a choice disappear on reload?
109
+ Pass the value your framework's server helper returns to the provider
110
+ unchanged. Do not merge it with defaults or rebuild it from permissions. Make
111
+ sure the server and browser use the same backend URL, because two backends can
112
+ resolve different policies.
44
113
 
45
- Check whether persistence is disabled, browser storage is blocked, the origin
46
- changed, or the receipt expired or no longer matches the current policy.
47
- A development example with `persistence: false` deliberately resets on reload.
48
- Do not "repair" persistence by saving permissions automatically on mount.
114
+ Never keep consent state in a module-level variable on the server. One
115
+ visitor's state can leak into another request. Create it per request, as the
116
+ framework guides do.
49
117
 
50
- ## Why does hydration differ from server HTML?
118
+ ## Why does the static build fail when development works?
51
119
 
52
- Use the adapter's request helper and pass the returned configuration unchanged
53
- to its boundary. Check that server and browser use the same backend and policy
54
- inputs. A module-level mutable runtime on a server can share one visitor's state
55
- with another request; create request-owned state instead.
120
+ A static host serves files only. Route handlers, server functions, rewrites
121
+ and proxies that worked under the dev server do not exist after deployment.
122
+ Point the browser at the absolute backend URL from Inth instead of a
123
+ same-origin `/api/c15t` path, then test the built output with a static file
124
+ server, not the dev server. [Choose your setup](../concepts/choose-your-setup.md)
125
+ lists the static path for each framework.
56
126
 
57
- ## Why does static hosting fail when development works?
127
+ ## Why does the UI disappear with an ad blocker?
58
128
 
59
- A static host has no app server for init routes, proxies or server functions.
60
- Use absolute external consent URLs or an explicitly local policy. Test the
61
- production output with a static file server, not the framework dev server.
129
+ Check the Network panel for `ERR_BLOCKED_BY_CLIENT`. Some filter lists block
130
+ the consent backend's domain or old c15t chunk names such as
131
+ `consent-dialog-*.js`. Current releases use neutral chunk names; update and
132
+ rebuild. If the backend domain is blocked, the banner cannot load policy and
133
+ every optional category stays denied.
62
134
 
63
- ## Why does customization do nothing?
135
+ ## Why does my theme do nothing?
64
136
 
65
- Check the imported stylesheet, the correct token or slot, and which element
66
- carries the state attribute. `data-variant` on a banner root is not a matching
67
- attribute on its child card. Check cascade layers and the Tailwind version
68
- before adding specificity. See [customization](../customization/overview.md).
137
+ Check that the c15t stylesheet loads, that you set a token or slot the
138
+ component actually reads, and that the state attribute you target is on the
139
+ element you style. A `data-variant` on the banner root is not on its card.
140
+ Check the Tailwind version and CSS layer order before adding specificity. See
141
+ [customization](../customization/overview.md).
@@ -1,62 +1,94 @@
1
1
  ---
2
- title: Verify consent before shipping
3
- description: Test requests, policy resolution, persistence, navigation and
4
- preference changes in a production build.
2
+ title: Verify consent
3
+ description: Check in a production build that vendor requests wait for consent,
4
+ rejection survives a reload, preferences reopen and privacy signals apply.
5
5
  group: guides
6
6
  ---
7
7
 
8
- ## Establish the policy under test
8
+ ## What you are checking
9
9
 
10
- Use a fresh browser profile and a known policy. For an opt-in choice policy,
11
- optional requests should be absent before a choice. Opt-out and notice policies
12
- have different defaults; inspect the resolved rule rather than expecting every
13
- region to show the same banner. Keep test geography overrides out of production.
10
+ A banner on screen proves only that the banner renders. Before shipping,
11
+ confirm four things in a production build:
14
12
 
15
- Inventory scripts in your HTML, application code, tag manager, plugins and
16
- embeds. A c15t provider cannot make an independently loaded vendor wait for a
17
- choice. Remove duplicate loaders before interpreting the result.
13
+ 1. Optional vendors make no requests before the visitor allows them.
14
+ 2. A rejection survives a reload and a new tab.
15
+ 3. The visitor can reopen preferences and change their mind.
16
+ 4. The policy is right for each location you serve.
17
+
18
+ Run the checks against `next build && next start`, `vite preview`, or your
19
+ framework's equivalent. Dev servers load code differently and hide problems.
20
+
21
+ ## Set up the browser
22
+
23
+ 1. Open a private window, so no earlier choice is stored.
24
+ 2. Open DevTools, select Network, and turn on **Disable cache** and
25
+ **Preserve log**.
26
+ 3. List the vendors you expect, such as `posthog.com`, `googletagmanager.com`,
27
+ `connect.facebook.net` or `youtube-nocookie.com`. You will filter by each.
28
+
29
+ Before testing, list every place a vendor could load: `<script>` tags,
30
+ framework analytics plugins, tag manager tags and embeds. c15t cannot hold
31
+ back code it does not load. Remove duplicates first, or the results mean
32
+ nothing.
18
33
 
19
34
  ## Run the visitor flow
20
35
 
21
- | Action | Check |
22
- | ------------------------------------------ | ---------------------------------------------------------------------------------------- |
23
- | Load without a stored choice | Correct policy and prompt; category-gated vendors stay blocked when permission is denied |
24
- | Reject optional categories | Prompt closes; denied vendors remain blocked |
25
- | Reload | Valid rejection persists; no new choice event is emitted by hydration |
26
- | Reopen preferences | Settings remain reachable after the banner closes |
27
- | Save one category | Only that category gets a new confirmation time |
28
- | Navigate without reloading | One runtime remains active; no duplicate vendor initialization |
29
- | Revoke a grant | Future gated work stops and configured cleanup runs |
30
- | Load with an expired or incompatible grant | It does not silently restore optional permissions |
31
- | Block the consent backend | Failed resolution is observable; absence of a banner does not grant permission |
32
- | Block browser storage | Interaction still works where supported; verify whether the choice survives reload |
33
-
34
- Inspect Network before the page starts loading, with cache disabled for the test.
35
- Filter by the vendor's script and collection domains. Hiding an iframe after it
36
- loads is too late to prevent the initial request.
37
-
38
- Google Consent Mode integrations intentionally load their scripts and send
39
- consent signals. Test their default and update commands separately from a
40
- zero-request gate. See [Google Tag Manager](../integrations/google-tag-manager.md)
41
- and [Google Tag](../integrations/google-tag.md).
42
-
43
- ## Test the production hosting shape
44
-
45
- For static sites, serve the generated files. Confirm no request depends on an
46
- API route or rewrite that only exists in development. For SSR, inspect the
47
- initial HTML and check that hydration does not change a valid stored choice.
48
- Test a direct visit as well as client navigation.
49
-
50
- For a cross-origin backend, check allowed origins, protocol and reachable URLs.
51
- A public backend URL is not an API secret. Keep credentials out of client props
52
- and public environment variables.
36
+ | Step | What to check |
37
+ | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
38
+ | Load the page | The banner appears under an opt-in policy. Filter Network by each vendor domain; opt-in vendors show no requests. |
39
+ | Click Reject | The banner closes. Vendor domains still show no requests. |
40
+ | Reload | No banner. Still no vendor requests. DevTools Application shows a `c15t` cookie. |
41
+ | Open a new tab on the same site | Same result as the reload. |
42
+ | Open preferences from your footer link | The dialog opens with the categories you rejected turned off. |
43
+ | Allow one category and save | Only vendors in that category start loading. The others stay silent. |
44
+ | Turn that category off again | The page reloads, and the vendor does not load after the reload. |
45
+ | Navigate between pages without a full reload | Each vendor loads once, not once per navigation. |
46
+
47
+ Google Tag and Google Tag Manager load before consent on purpose and send
48
+ Consent Mode signals. For them, check that the consent state in the request
49
+ parameters changes when the visitor chooses, not that requests are absent.
50
+ See [Google Tag Manager](../integrations/google-tag-manager.md).
51
+
52
+ ## Check each location
53
+
54
+ Policies usually differ by region. Test at least:
55
+
56
+ * A location that needs a choice, such as Germany or the United Kingdom.
57
+ * A location without a prompt, such as a US state without a privacy law in
58
+ your rules.
59
+ * A request with no location headers at all. c15t applies your policy's
60
+ fallback for unknown locations; make sure that fallback is what you want.
61
+
62
+ Use a VPN, your host's geolocation preview, or the `country` option on your
63
+ framework's server helper while testing. Remove test overrides before you
64
+ deploy.
65
+
66
+ ## Check privacy signals
67
+
68
+ Turn on Global Privacy Control in the browser. Brave and DuckDuckGo send it by
69
+ default; in Firefox, enable it in Privacy settings. Reload and confirm the
70
+ categories your policy restricts for GPC are denied, without the visitor
71
+ having clicked anything. Turn GPC off and confirm the restriction ends.
72
+
73
+ ## Check failure behavior
74
+
75
+ Block the backend URL in DevTools (right-click the request, then **Block
76
+ request URL**) and reload. No banner appears, and no optional vendor loads.
77
+ A missing banner must never mean "allowed". Then unblock it and confirm the
78
+ page recovers.
53
79
 
54
80
  ## Check the interface
55
81
 
56
- Use a narrow viewport, long translated labels and keyboard-only navigation.
57
- Check that blocking dialogs trap focus, return it to the trigger when closed,
58
- and do not leave scrolling locked. Non-blocking notices should allow interaction
59
- with the page. Test contrast and focus indicators after applying a theme.
82
+ * Tab through the banner and dialog with the keyboard only. Focus stays inside
83
+ a modal dialog and returns to the button that opened it when it closes.
84
+ * Set the viewport to 375 pixels wide and switch to a language with long
85
+ labels, such as German.
86
+ * After applying your theme, check text contrast and that focus rings are
87
+ visible.
88
+
89
+ ## Record the result
60
90
 
61
- Record the policy, framework, deployment and observed request behavior with the
62
- test result. "The banner appears" is only one assertion.
91
+ Write down the framework, the rendering mode, the policy you tested, and the
92
+ requests you saw before and after consent. "The banner appears" is not a test
93
+ result. If something fails, [troubleshooting](./troubleshooting.md)
94
+ starts with three checks that locate most problems.