@c15t/react 3.0.0-alpha.0 → 3.0.0-alpha.10

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 (405) hide show
  1. package/AGENTS.md +96 -69
  2. package/README.md +21 -17
  3. package/SKILL.md +34 -0
  4. package/dist/aggregate-components.js +1 -1
  5. package/dist/chunk-warming.js +1 -1
  6. package/dist/component-hooks/use-headless-consent-ui.js +1 -1
  7. package/dist/component-hooks/use-headless-iab-consent-ui.js +1 -1
  8. package/dist/component-hooks/use-panel-trigger.js +1 -1
  9. package/dist/components/consent-gate/atoms.js +1 -0
  10. package/dist/components/consent-gate/consent-gate.js +2 -0
  11. package/dist/components/consent-gate/frame.js +2 -0
  12. package/dist/components/consent-gate/index.js +2 -0
  13. package/dist/components/consent-preferences-link/consent-preferences-link.js +1 -1
  14. package/dist/components/iab-panel/atoms/card.js +1 -1
  15. package/dist/components/iab-panel/atoms/feature-item.js +2 -0
  16. package/dist/components/iab-panel/atoms/header.js +1 -1
  17. package/dist/components/iab-panel/atoms/purpose-item.js +1 -1
  18. package/dist/components/iab-panel/atoms/root.js +1 -1
  19. package/dist/components/iab-panel/atoms/stack-item.js +1 -1
  20. package/dist/components/iab-panel/atoms/vendor-list.js +1 -1
  21. package/dist/components/iab-panel/hooks/use-gvl-data.js +1 -1
  22. package/dist/components/iab-panel/iab-panel.js +1 -1
  23. package/dist/components/iab-panel/index.js +1 -1
  24. package/dist/components/iab-prompt/atoms/overlay.js +1 -1
  25. package/dist/components/iab-prompt/atoms/root.js +1 -1
  26. package/dist/components/panel/atoms/card.js +1 -1
  27. package/dist/components/panel/atoms/overlay.js +1 -1
  28. package/dist/components/panel/atoms/root.js +1 -1
  29. package/dist/components/panel/panel.js +1 -1
  30. package/dist/components/panel-trigger/atoms/button.js +1 -1
  31. package/dist/components/panel-trigger/atoms/icon.js +1 -1
  32. package/dist/components/panel-trigger/atoms/root.js +1 -1
  33. package/dist/components/panel-trigger/atoms/toolbar.js +1 -1
  34. package/dist/components/panel-trigger/atoms/trigger-icons.js +1 -0
  35. package/dist/components/panel-trigger/panel-trigger-toolbar.js +1 -1
  36. package/dist/components/panel-trigger/panel-trigger.js +1 -1
  37. package/dist/components/preferences/atoms/accordion.js +1 -1
  38. package/dist/components/preferences/atoms/root.js +1 -1
  39. package/dist/components/preferences/atoms/vendor-list.js +1 -0
  40. package/dist/components/preferences/index.js +1 -1
  41. package/dist/components/prompt/atoms/early-tap-script.js +2 -0
  42. package/dist/components/prompt/atoms/overlay.js +1 -1
  43. package/dist/components/prompt/atoms/root.js +1 -1
  44. package/dist/components/prompt/components.js +1 -1
  45. package/dist/components/prompt/policy-actions.js +1 -1
  46. package/dist/components/prompt/prompt.js +1 -1
  47. package/dist/components/shared/dialog-sheets.js +1 -0
  48. package/dist/components/shared/first-paint-sheets.js +1 -0
  49. package/dist/components/shared/iab-dialog-sheets.js +1 -0
  50. package/dist/components/shared/iab-first-paint-sheets.js +1 -0
  51. package/dist/components/shared/libs/compose-refs.js +1 -0
  52. package/dist/components/shared/libs/slot.js +1 -1
  53. package/dist/components/shared/primitives/button.js +1 -1
  54. package/dist/components/shared/primitives/legal-links/index.js +1 -1
  55. package/dist/components/shared/streamed-surface.js +2 -0
  56. package/dist/components/shared/surface-styles.js +2 -0
  57. package/dist/components/shared/ui/dialog/dialog.js +1 -1
  58. package/dist/components/shared/ui/icon.js +1 -1
  59. package/dist/components/shared/ui/logo.js +1 -1
  60. package/dist/components/shared/ui/preference-item/preference-item.js +1 -1
  61. package/dist/consent-gate.js +2 -0
  62. package/dist/consent-theme.js +1 -0
  63. package/dist/context/consent-tracking-context.js +1 -1
  64. package/dist/context/index.js +1 -1
  65. package/dist/context.js +1 -1
  66. package/dist/devtools-launcher.js +2 -0
  67. package/dist/devtools.js +1 -1
  68. package/dist/draft-context.js +2 -0
  69. package/dist/draft.js +1 -1
  70. package/dist/external-iab-context.js +1 -1
  71. package/dist/gpp.js +2 -0
  72. package/dist/headless.js +1 -1
  73. package/dist/hooks/use-color-scheme.js +1 -1
  74. package/dist/hooks/use-committed-ref.js +2 -0
  75. package/dist/hooks/use-focus-trap.js +1 -1
  76. package/dist/hooks/use-headless-iab-consent-ui.js +1 -1
  77. package/dist/hooks/use-iab-policy-guard.js +1 -0
  78. package/dist/hooks/use-late-entry.js +2 -0
  79. package/dist/hooks.js +1 -1
  80. package/dist/iab/styles.tw3.css +5 -151
  81. package/dist/iab-context.js +1 -1
  82. package/dist/index-parts/consent-banner.js +1 -0
  83. package/dist/index-parts/consent-dialog-link.js +1 -0
  84. package/dist/index-parts/consent-dialog-trigger.js +1 -0
  85. package/dist/index-parts/consent-dialog.js +1 -0
  86. package/dist/index-parts/consent-gate.js +1 -0
  87. package/dist/index-parts/core.js +1 -0
  88. package/dist/index-parts/draft.js +1 -0
  89. package/dist/index-parts/frame.js +1 -0
  90. package/dist/index-parts/hooks.js +1 -0
  91. package/dist/index-parts/hosted.js +1 -0
  92. package/dist/index-parts/module-hooks.js +1 -0
  93. package/dist/index-parts/offline.js +1 -0
  94. package/dist/index-parts/presets.js +1 -0
  95. package/dist/index-parts/provider.js +1 -0
  96. package/dist/index-parts/theme.js +1 -0
  97. package/dist/index-parts/translations.js +1 -0
  98. package/dist/index.js +1 -1
  99. package/dist/kernel-selector.js +1 -0
  100. package/dist/modes.js +1 -0
  101. package/dist/module-hooks/iframe-blocker.js +1 -1
  102. package/dist/module-hooks/network-blocker.js +1 -1
  103. package/dist/module-hooks/network-hold.js +2 -0
  104. package/dist/module-hooks/persistence.js +1 -1
  105. package/dist/panel-link.js +1 -1
  106. package/dist/panel-trigger.js +1 -1
  107. package/dist/panel.js +1 -1
  108. package/dist/postcss-tailwind3.js +1 -0
  109. package/dist/preferences.js +1 -2
  110. package/dist/provider.js +1 -1
  111. package/dist/server/fetch-ssr-data.js +1 -1
  112. package/dist/server/headers.js +1 -1
  113. package/dist/server/normalize-url.js +1 -1
  114. package/dist/styles.tw3.css +35 -159
  115. package/dist/transports/hosted.js +1 -0
  116. package/dist/transports/manifest.js +1 -0
  117. package/dist/transports/offline.js +1 -1
  118. package/dist/utils/deferred-module.js +2 -0
  119. package/dist/utils/merge-slot-props.js +1 -1
  120. package/dist/utils/theme-utils.js +1 -1
  121. package/dist/version.js +1 -1
  122. package/dist-types/aggregate-components.d.ts +2 -2
  123. package/dist-types/chunk-warming.d.ts +45 -8
  124. package/dist-types/component-hooks/use-headless-consent-ui.d.ts +5 -5
  125. package/dist-types/component-hooks/use-headless-iab-consent-ui.d.ts +2 -2
  126. package/dist-types/components/consent-gate/atoms.d.ts +11 -0
  127. package/dist-types/components/consent-gate/consent-gate.d.ts +2 -0
  128. package/dist-types/components/consent-gate/frame.d.ts +19 -0
  129. package/dist-types/components/consent-gate/index.d.ts +25 -0
  130. package/dist-types/components/{frame → consent-gate}/types.d.ts +7 -7
  131. package/dist-types/components/consent-preferences-link/consent-preferences-link.d.ts +1 -1
  132. package/dist-types/components/consent-preferences-link/index.d.ts +1 -1
  133. package/dist-types/components/iab-panel/atoms/feature-item.d.ts +28 -0
  134. package/dist-types/components/iab-panel/atoms/purpose-item.d.ts +5 -2
  135. package/dist-types/components/iab-panel/atoms/stack-item.d.ts +7 -2
  136. package/dist-types/components/iab-panel/atoms/vendor-list.d.ts +1 -1
  137. package/dist-types/components/iab-panel/iab-panel.d.ts +3 -3
  138. package/dist-types/components/iab-panel/index.d.ts +29 -26
  139. package/dist-types/components/iab-panel/use-iab-translations.d.ts +4 -0
  140. package/dist-types/components/iab-prompt/iab-prompt.d.ts +3 -3
  141. package/dist-types/components/iab-prompt/index.d.ts +19 -19
  142. package/dist-types/components/panel/atoms/card.d.ts +5 -4
  143. package/dist-types/components/panel/atoms/overlay.d.ts +1 -1
  144. package/dist-types/components/panel/index.d.ts +8 -8
  145. package/dist-types/components/panel/panel.d.ts +3 -3
  146. package/dist-types/components/panel-link/index.d.ts +1 -1
  147. package/dist-types/components/panel-trigger/atoms/button.d.ts +1 -1
  148. package/dist-types/components/panel-trigger/atoms/icon.d.ts +1 -1
  149. package/dist-types/components/panel-trigger/atoms/root.d.ts +2 -2
  150. package/dist-types/components/panel-trigger/atoms/toolbar.d.ts +2 -2
  151. package/dist-types/components/panel-trigger/atoms/trigger-icons.d.ts +25 -0
  152. package/dist-types/components/panel-trigger/index.d.ts +4 -4
  153. package/dist-types/components/panel-trigger/panel-trigger-toolbar.d.ts +1 -1
  154. package/dist-types/components/panel-trigger/panel-trigger.d.ts +9 -17
  155. package/dist-types/components/panel-trigger/types.d.ts +1 -1
  156. package/dist-types/components/preferences/atoms/accordion.d.ts +6 -4
  157. package/dist-types/components/preferences/atoms/button.d.ts +1 -1
  158. package/dist-types/components/preferences/atoms/footer.d.ts +1 -1
  159. package/dist-types/components/preferences/atoms/root.d.ts +1 -1
  160. package/dist-types/components/preferences/atoms/vendor-list.d.ts +23 -0
  161. package/dist-types/components/preferences/index.d.ts +14 -12
  162. package/dist-types/components/preferences/policy-actions.d.ts +2 -2
  163. package/dist-types/components/preferences/preferences.d.ts +1 -1
  164. package/dist-types/components/preferences/types.d.ts +1 -1
  165. package/dist-types/components/prompt/atoms/early-tap-script.d.ts +17 -0
  166. package/dist-types/components/prompt/atoms/root.d.ts +4 -0
  167. package/dist-types/components/prompt/components.d.ts +9 -3
  168. package/dist-types/components/prompt/index.d.ts +12 -12
  169. package/dist-types/components/prompt/policy-actions.d.ts +2 -2
  170. package/dist-types/components/prompt/prompt.d.ts +5 -1
  171. package/dist-types/components/shared/dialog-sheets.d.ts +9 -0
  172. package/dist-types/components/shared/first-paint-sheets.d.ts +8 -0
  173. package/dist-types/components/shared/iab-dialog-sheets.d.ts +3 -0
  174. package/dist-types/components/shared/iab-first-paint-sheets.d.ts +3 -0
  175. package/dist-types/components/shared/libs/compose-refs.d.ts +20 -0
  176. package/dist-types/components/shared/policy-actions.d.ts +2 -2
  177. package/dist-types/components/shared/primitives/box.d.ts +1 -1
  178. package/dist-types/components/shared/primitives/button.d.ts +2 -2
  179. package/dist-types/components/shared/primitives/button.types.d.ts +1 -1
  180. package/dist-types/components/shared/streamed-surface.d.ts +23 -0
  181. package/dist-types/components/shared/surface-styles.d.ts +36 -0
  182. package/dist-types/components/shared/ui/accordion/accordion.d.ts +2 -2
  183. package/dist-types/components/shared/ui/accordion/index.d.ts +2 -2
  184. package/dist-types/components/shared/ui/animated-collapse/index.d.ts +2 -2
  185. package/dist-types/components/shared/ui/branding.d.ts +1 -1
  186. package/dist-types/components/shared/ui/button/button.d.ts +1 -1
  187. package/dist-types/components/shared/ui/button/index.d.ts +2 -2
  188. package/dist-types/components/shared/ui/collapsible/index.d.ts +1 -1
  189. package/dist-types/components/shared/ui/dialog/index.d.ts +1 -1
  190. package/dist-types/components/shared/ui/icon.d.ts +2 -1
  191. package/dist-types/components/shared/ui/logo.d.ts +0 -10
  192. package/dist-types/components/shared/ui/preference-item/index.d.ts +1 -1
  193. package/dist-types/components/shared/ui/preference-item/preference-item.d.ts +13 -0
  194. package/dist-types/components/shared/ui/switch/index.d.ts +2 -2
  195. package/dist-types/components/shared/ui/switch/switch.d.ts +1 -1
  196. package/dist-types/components/shared/ui/tabs/index.d.ts +1 -1
  197. package/dist-types/consent-gate.d.ts +1 -0
  198. package/dist-types/consent-theme.d.ts +38 -0
  199. package/dist-types/context/consent-tracking-context.d.ts +10 -0
  200. package/dist-types/context/index.d.ts +3 -3
  201. package/dist-types/context/theme-context.d.ts +3 -3
  202. package/dist-types/context.d.ts +25 -1
  203. package/dist-types/devtools-launcher.d.ts +29 -0
  204. package/dist-types/devtools.d.ts +13 -2
  205. package/dist-types/draft-context.d.ts +31 -0
  206. package/dist-types/draft.d.ts +81 -9
  207. package/dist-types/gpp.d.ts +27 -0
  208. package/dist-types/headless.d.ts +6 -7
  209. package/dist-types/hooks/use-committed-ref.d.ts +24 -0
  210. package/dist-types/hooks/use-focus-trap.d.ts +3 -1
  211. package/dist-types/hooks/use-headless-iab-consent-ui.d.ts +1 -1
  212. package/dist-types/hooks/use-iab-manager.d.ts +5 -5
  213. package/dist-types/hooks/use-iab-policy-guard.d.ts +35 -0
  214. package/dist-types/hooks/use-late-entry.d.ts +14 -0
  215. package/dist-types/hooks/use-theme.d.ts +1 -1
  216. package/dist-types/hooks.d.ts +106 -11
  217. package/dist-types/iab.d.ts +7 -7
  218. package/dist-types/index-parts/consent-banner.d.ts +7 -0
  219. package/dist-types/index-parts/consent-dialog-link.d.ts +7 -0
  220. package/dist-types/index-parts/consent-dialog-trigger.d.ts +7 -0
  221. package/dist-types/index-parts/consent-dialog.d.ts +7 -0
  222. package/dist-types/index-parts/consent-gate.d.ts +7 -0
  223. package/dist-types/index-parts/core.d.ts +7 -0
  224. package/dist-types/index-parts/draft.d.ts +7 -0
  225. package/dist-types/index-parts/frame.d.ts +7 -0
  226. package/dist-types/index-parts/hooks.d.ts +7 -0
  227. package/dist-types/index-parts/hosted.d.ts +7 -0
  228. package/dist-types/index-parts/module-hooks.d.ts +7 -0
  229. package/dist-types/index-parts/offline.d.ts +7 -0
  230. package/dist-types/index-parts/presets.d.ts +7 -0
  231. package/dist-types/index-parts/provider.d.ts +7 -0
  232. package/dist-types/index-parts/theme.d.ts +8 -0
  233. package/dist-types/index-parts/translations.d.ts +7 -0
  234. package/dist-types/index.d.ts +32 -28
  235. package/dist-types/kernel-selector.d.ts +68 -0
  236. package/dist-types/modes.d.ts +26 -0
  237. package/dist-types/module-hooks/iframe-blocker.d.ts +33 -1
  238. package/dist-types/module-hooks/network-blocker.d.ts +23 -0
  239. package/dist-types/module-hooks/network-hold.d.ts +47 -0
  240. package/dist-types/module-hooks.d.ts +4 -4
  241. package/dist-types/panel-link.d.ts +1 -1
  242. package/dist-types/panel-trigger.d.ts +1 -1
  243. package/dist-types/panel.d.ts +13 -1
  244. package/dist-types/postcss-tailwind3.d.ts +21 -0
  245. package/dist-types/preferences.d.ts +12 -1
  246. package/dist-types/primitives/accordion.d.ts +1 -1
  247. package/dist-types/primitives/button.d.ts +1 -1
  248. package/dist-types/primitives/collapsible.d.ts +1 -1
  249. package/dist-types/primitives/dialog.d.ts +1 -1
  250. package/dist-types/primitives/preference-item.d.ts +1 -1
  251. package/dist-types/primitives/switch.d.ts +1 -1
  252. package/dist-types/primitives/tabs.d.ts +1 -1
  253. package/dist-types/primitives.d.ts +7 -7
  254. package/dist-types/prompt.d.ts +1 -1
  255. package/dist-types/provider.d.ts +174 -28
  256. package/dist-types/server/fetch-ssr-data.d.ts +1 -1
  257. package/dist-types/server/headers.d.ts +14 -4
  258. package/dist-types/server/index.d.ts +5 -5
  259. package/dist-types/server/normalize-url.d.ts +14 -7
  260. package/dist-types/server/types.d.ts +12 -1
  261. package/dist-types/theme-provider.d.ts +2 -2
  262. package/dist-types/transports/hosted.d.ts +36 -0
  263. package/dist-types/transports/manifest.d.ts +48 -0
  264. package/dist-types/transports/offline.d.ts +7 -16
  265. package/dist-types/types/index.d.ts +3 -3
  266. package/dist-types/types/manager.d.ts +1 -1
  267. package/dist-types/types/theme/index.d.ts +1 -1
  268. package/dist-types/ui-config-context.d.ts +14 -2
  269. package/dist-types/utils/deferred-module.d.ts +13 -0
  270. package/dist-types/utils/index.d.ts +4 -4
  271. package/dist-types/utils/merge-slot-props.d.ts +17 -3
  272. package/dist-types/utils/merge-styles.d.ts +1 -1
  273. package/dist-types/utils/theme-utils.d.ts +18 -3
  274. package/dist-types/version.d.ts +1 -1
  275. package/docs/README.md +96 -69
  276. package/docs/assets/v3/bottom-bar.png +0 -0
  277. package/docs/assets/v3/brand-card.png +0 -0
  278. package/docs/assets/v3/brand-preferences.png +0 -0
  279. package/docs/assets/v3/choice-wall.png +0 -0
  280. package/docs/assets/v3/headless-bar-html.png +0 -0
  281. package/docs/assets/v3/headless-bar-mobile.png +0 -0
  282. package/docs/assets/v3/headless-bar.png +0 -0
  283. package/docs/assets/v3/slim-bar.png +0 -0
  284. package/docs/concepts/choose-your-setup.md +138 -0
  285. package/docs/concepts/consent-categories.md +84 -0
  286. package/docs/concepts/consent-state.md +421 -0
  287. package/docs/concepts/data-fetching.md +270 -0
  288. package/docs/concepts/how-consent-works.md +123 -0
  289. package/docs/concepts/modes.md +278 -0
  290. package/docs/{frameworks/react/concepts/policy-presets.md → concepts/policies.md} +8 -60
  291. package/docs/customization/class-names.md +202 -0
  292. package/docs/customization/dark-mode.md +157 -0
  293. package/docs/customization/motion.md +128 -0
  294. package/docs/customization/overview.md +68 -33
  295. package/docs/customization/recipes.md +838 -47
  296. package/docs/customization/slots.md +217 -35
  297. package/docs/customization/stylesheets.md +248 -0
  298. package/docs/customization/tailwind.md +863 -0
  299. package/docs/customization/tokens.md +167 -36
  300. package/docs/customization/translations.md +87 -3
  301. package/docs/frameworks/react/callbacks.md +118 -0
  302. package/docs/frameworks/react/clear-on-revocation.md +106 -0
  303. package/docs/frameworks/react/components/consent-banner.md +48 -27
  304. package/docs/frameworks/react/components/consent-dialog-link.md +13 -11
  305. package/docs/frameworks/react/components/consent-dialog-trigger.md +86 -76
  306. package/docs/frameworks/react/components/consent-dialog.md +111 -58
  307. package/docs/frameworks/react/components/{frame.md → consent-gate.md} +70 -49
  308. package/docs/frameworks/react/components/consent-provider.md +140 -0
  309. package/docs/frameworks/react/components/consent-widget.md +69 -24
  310. package/docs/frameworks/react/components/dev-tools.md +76 -85
  311. package/docs/frameworks/react/components.md +113 -0
  312. package/docs/frameworks/react/compose.md +354 -0
  313. package/docs/frameworks/react/content-security-policy.md +143 -0
  314. package/docs/frameworks/react/customize.md +258 -0
  315. package/docs/frameworks/react/embeds.md +89 -0
  316. package/docs/frameworks/react/gpp.md +163 -0
  317. package/docs/frameworks/react/headless.md +4 -4
  318. package/docs/frameworks/react/hooks.md +70 -0
  319. package/docs/frameworks/react/iab.md +259 -0
  320. package/docs/frameworks/react/network-blocker.md +140 -0
  321. package/docs/frameworks/react/quickstart.md +220 -102
  322. package/docs/frameworks/react/rendering.md +263 -0
  323. package/docs/frameworks/react/scripts.md +114 -0
  324. package/docs/frameworks/react/translations.md +155 -0
  325. package/docs/frameworks/react/troubleshooting.md +188 -61
  326. package/docs/frameworks/react/upgrade-v3.md +651 -0
  327. package/docs/frameworks/react/vendor-consent.md +188 -0
  328. package/docs/guides/banner-experiments.md +672 -0
  329. package/docs/guides/troubleshooting.md +192 -54
  330. package/docs/guides/verify-consent.md +96 -49
  331. package/docs/integrations/adobe-analytics.md +177 -183
  332. package/docs/integrations/ahrefs-analytics.md +162 -178
  333. package/docs/integrations/amplitude.md +172 -180
  334. package/docs/integrations/building-integrations.md +137 -33
  335. package/docs/integrations/clearbit.md +164 -178
  336. package/docs/integrations/cloudflare-web-analytics.md +166 -180
  337. package/docs/integrations/cloudflare-zaraz.md +333 -0
  338. package/docs/integrations/crisp.md +174 -182
  339. package/docs/integrations/databuddy.md +167 -197
  340. package/docs/integrations/fathom-analytics.md +168 -180
  341. package/docs/integrations/front-chat.md +308 -0
  342. package/docs/integrations/google-maps.md +142 -108
  343. package/docs/integrations/google-tag-manager.md +258 -185
  344. package/docs/integrations/google-tag.md +226 -182
  345. package/docs/integrations/heap.md +173 -179
  346. package/docs/integrations/hightouch.md +171 -181
  347. package/docs/integrations/hotjar.md +169 -179
  348. package/docs/integrations/intercom.md +193 -177
  349. package/docs/integrations/klaviyo.md +473 -0
  350. package/docs/integrations/linkedin-insights.md +184 -174
  351. package/docs/integrations/logrocket.md +170 -180
  352. package/docs/integrations/matomo-analytics.md +198 -202
  353. package/docs/integrations/meta-pixel.md +198 -174
  354. package/docs/integrations/microsoft-clarity.md +173 -179
  355. package/docs/integrations/microsoft-uet.md +158 -178
  356. package/docs/integrations/mixpanel-analytics.md +165 -184
  357. package/docs/integrations/one-dollar-stats.md +292 -0
  358. package/docs/integrations/openai-pixel.md +214 -325
  359. package/docs/integrations/overview.md +152 -83
  360. package/docs/integrations/pinterest-tag.md +315 -0
  361. package/docs/integrations/pirsch.md +179 -183
  362. package/docs/integrations/plausible-analytics.md +182 -182
  363. package/docs/integrations/posthog.md +323 -264
  364. package/docs/integrations/promptwatch.md +164 -178
  365. package/docs/integrations/reddit-pixel.md +195 -181
  366. package/docs/integrations/rudderstack.md +211 -210
  367. package/docs/integrations/rybbit-analytics.md +181 -184
  368. package/docs/integrations/segment.md +192 -178
  369. package/docs/integrations/sentry.md +402 -0
  370. package/docs/integrations/snapchat-pixel.md +196 -180
  371. package/docs/integrations/tiktok-pixel.md +181 -174
  372. package/docs/integrations/umami-analytics.md +173 -182
  373. package/docs/integrations/vercel-analytics.md +176 -181
  374. package/docs/integrations/x-pixel.md +186 -174
  375. package/docs/integrations/youtube.md +150 -111
  376. package/package.json +48 -17
  377. package/dist/component-hooks/use-manager.js +0 -2
  378. package/dist/components/frame/atoms.js +0 -1
  379. package/dist/components/frame/frame.js +0 -2
  380. package/dist/components/frame/index.js +0 -2
  381. package/dist/frame.js +0 -2
  382. package/dist/ui-save.js +0 -1
  383. package/dist-types/component-hooks/use-manager.d.ts +0 -40
  384. package/dist-types/components/frame/atoms.d.ts +0 -11
  385. package/dist-types/components/frame/frame.d.ts +0 -2
  386. package/dist-types/components/frame/index.d.ts +0 -24
  387. package/dist-types/frame.d.ts +0 -1
  388. package/dist-types/ui-save.d.ts +0 -5
  389. package/docs/assets/v3/brand-bar.png +0 -0
  390. package/docs/assets/v3/mobile-card.png +0 -0
  391. package/docs/assets/v3/preferences.png +0 -0
  392. package/docs/frameworks/react/components/consent-manager-provider.md +0 -62
  393. package/docs/frameworks/react/concepts/consent-categories.md +0 -33
  394. package/docs/frameworks/react/hooks/use-consent-manager/overview.md +0 -58
  395. package/docs/frameworks/react/iab/overview.md +0 -53
  396. package/docs/frameworks/react/script-loader.md +0 -55
  397. package/docs/frameworks/react/styling/overview.md +0 -207
  398. package/docs/guides/consent-state.md +0 -60
  399. package/docs/guides/data-fetching.md +0 -163
  400. package/docs/guides/deployment-modes.md +0 -63
  401. package/docs/upgrade-v3.md +0 -334
  402. package/readme.json +0 -48
  403. package/src/iab/styles.css +0 -11
  404. package/src/styles.css +0 -10
  405. /package/dist/components/{frame → consent-gate}/types.js +0 -0
@@ -1,220 +1,164 @@
1
1
  ---
2
2
  title: PostHog
3
- description: Choose PostHog loading and cookieless behavior, configure the
4
- region, and synchronize v3 permissions.
3
+ description: Load PostHog before or after measurement consent with the c15t
4
+ posthog helper, choose its cookieless behavior, turn off PostHog modules you
5
+ do not use, and sync consent with an SDK you already initialize.
6
+ icon: posthog
5
7
  group: integrations
6
8
  ---
7
9
 
8
10
  ## Configure PostHog
9
11
 
10
- Use the browser project token beginning with `phc_`. Select the region matching
11
- your PostHog project. This example waits for measurement permission before
12
- requesting the SDK.
12
+ Use the project token that starts with `phc_`, and the region of your PostHog
13
+ project. This example waits for measurement permission before requesting the
14
+ SDK, and turns off cookieless capture after a refusal.
13
15
 
14
- | Package manager | Command |
15
- | :-------------- | :-------------------------- |
16
- | npm | `npm install @c15t/scripts` |
17
- | pnpm | `pnpm add @c15t/scripts` |
18
- | yarn | `yarn add @c15t/scripts` |
19
- | bun | `bun add @c15t/scripts` |
16
+ | Package manager | Command |
17
+ | :-------------- | :------------------------------------- |
18
+ | npm | `npm install @c15t/integrations@alpha` |
19
+ | pnpm | `pnpm add @c15t/integrations@alpha` |
20
+ | yarn | `yarn add @c15t/integrations@alpha` |
21
+ | bun | `bun add @c15t/integrations@alpha` |
20
22
 
21
23
  ```ts title="src/consent-scripts.ts"
22
- import { posthog } from '@c15t/scripts/posthog';
24
+ import { posthog } from '@c15t/integrations/posthog';
23
25
 
24
26
  export const scripts = [
25
- posthog({
26
- id: 'phc_YOUR_PROJECT_TOKEN',
27
- region: 'eu',
28
- loadMode: 'after-consent',
29
- initOptions: { cookieless_mode: 'never' },
30
- }),
27
+ posthog({
28
+ id: 'phc_YOUR_PROJECT_TOKEN',
29
+ region: 'eu',
30
+ loadMode: 'after-consent',
31
+ initOptions: { cookieless_mode: 'never' },
32
+ }),
31
33
  ];
32
34
  ```
33
35
 
34
- The helper initializes PostHog. Remove a separate `posthog-js` initializer,
35
- framework plugin or array snippet before using this setup.
36
+ The helper initializes PostHog itself. Remove any `posthog-js` initializer,
37
+ framework plugin or array snippet that also does, or follow
38
+ [use an existing PostHog SDK](#use-an-existing-posthog-sdk) instead.
36
39
 
37
40
  ## Register the scripts
38
41
 
39
- Complete your [framework quickstart](https://c15t.com/docs/frameworks) first. Keep its Inth
42
+ Complete your [framework quickstart](https://v3.c15t.com/docs/frameworks) first. Keep its Inth
40
43
  endpoint, policy, styles and consent UI. Remove the vendor's original script,
41
- SDK initializer or tag-manager entry so c15t owns loading once.
44
+ SDK initializer or tag-manager entry, so the vendor loads only through c15t.
42
45
 
43
- The `scripts` export in `src/consent-scripts.ts` is a configuration, not an
44
- initializer. Add it to your existing consent owner using the registration point
45
- below. These are partial edits to that owner, not additional providers.
46
+ The vendor pages put the helper in `src/consent-scripts.ts`. If your framework
47
+ quickstart already has a `scripts` array, such as the one in `c15t.config.ts`
48
+ in the Next.js guide, add the helper to that array instead of creating a
49
+ second file.
50
+ The `scripts` export is a configuration, not an initializer. Add it to the c15t provider you already have, at the registration
51
+ point for your framework below. These are edits to that provider, not a second
52
+ provider.
46
53
 
47
54
  **Next.js**
48
55
 
49
- Import the configuration into the client boundary from your router guide:
56
+ Add the configuration to `scripts` in `c15t.config.ts`, next to
57
+ `next.config.ts`:
50
58
 
51
- ```ts
52
- import { ConsentRoot } from 'c15t/next';
53
- import { scripts } from './consent-scripts';
54
- ```
59
+ ```ts title="c15t.config.ts"
60
+ import { defineConsentConfig } from 'c15t/next';
61
+ import { scripts } from './src/consent-scripts';
55
62
 
56
- Keep the server-resolved `state` and shared `consentConfig` from your
57
- router guide. Its manifest, init and save URLs stay in effect. Add
58
- `scripts` as a top-level prop on the existing root:
59
-
60
- ```tsx
61
- <ConsentRoot state={state} config={consentConfig} scripts={scripts}>
62
- {children}
63
- </ConsentRoot>
63
+ export default defineConsentConfig({ scripts });
64
64
  ```
65
65
 
66
- For a Pages Router or static-export setup using `ConsentProvider`, add
67
- `scripts` to its existing `options` instead. Keep the router-specific setup
68
- from [Next.js script loading](https://c15t.com/docs/frameworks/next/script-loader).
66
+ Keep the rest of your config, such as `mode` and `routePrefix`, in the
67
+ same call. `ConsentRoot` reads the config in the browser, so the layout
68
+ keeps passing only `state`. App Router, Pages Router and static export all
69
+ read the same file. See
70
+ [Next.js scripts and embeds](https://v3.c15t.com/docs/frameworks/next/scripts).
69
71
 
70
72
  **TanStack Start**
71
73
 
72
- In your existing root route component, import the scripts alongside
73
- `ConsentRoot`. Keep the server loader from the [TanStack Start quickstart](https://c15t.com/docs/frameworks/tanstack-start/quickstart).
74
+ Import the configuration into your root route and pass it to the existing
75
+ `ConsentRoot` as a top-level prop. Keep the loader from the
76
+ [TanStack Start quickstart](https://v3.c15t.com/docs/frameworks/tanstack-start/quickstart):
74
77
 
75
- ```tsx
76
- import { Outlet } from '@tanstack/react-router';
77
- import { ConsentRoot } from 'c15t/tanstack-start';
78
+ ```tsx title="src/routes/__root.tsx"
78
79
  import { scripts } from '../consent-scripts';
79
80
 
80
- function Root() {
81
- const state = Route.useLoaderData();
82
- return (
83
- <ConsentRoot state={state} backendURL={backendURL} initRoute={false} scripts={scripts}>
84
- <Outlet />
85
- {/* Keep your consent banner, dialog and preferences link here. */}
86
- </ConsentRoot>
87
- );
88
- }
81
+ <ConsentRoot state={consent} scripts={scripts}>
89
82
  ```
90
83
 
91
- This edits the existing route. `Route` and `backendURL` come from its setup;
92
- keep the document shell and head components if they are part of your root.
93
- `initRoute={false}` keeps the quickstart's direct-backend initialization.
94
- If your app mounts a consent server route, retain its existing `initRoute`
95
- instead. Do not return script callbacks from a server function or route loader.
84
+ Import vendor helpers in the root route module, not in a server function.
85
+ A server function's return value must be serializable, and script
86
+ configurations carry callbacks. See
87
+ [TanStack Start scripts](https://v3.c15t.com/docs/frameworks/tanstack-start/scripts).
96
88
 
97
89
  **React**
98
90
 
99
- Import the scripts into your existing provider component:
91
+ Add the configuration to the existing `ConsentProvider` options, next to
92
+ `mode`:
100
93
 
101
- ```ts
102
- import { ConsentProvider } from 'c15t/react';
94
+ ```tsx title="src/consent.tsx"
103
95
  import { scripts } from './consent-scripts';
104
- ```
105
96
 
106
- Keep the existing options and add `scripts`:
107
-
108
- ```tsx
109
- <ConsentProvider options={{ ...consentOptions, scripts }}>
110
- {children}
111
- </ConsentProvider>
97
+ <ConsentProvider options={{ mode, scripts }}>
112
98
  ```
113
99
 
114
- Here `consentOptions` is your existing configuration, including
115
- `mode: hosted({ url: backendURL })`. Keep the banner, dialog and preferences
116
- link inside the provider. See [React script loading](../frameworks/react/script-loader.md).
100
+ `mode` is the `manifest()` value from the
101
+ [React quickstart](../frameworks/react/quickstart.md). Keep the banner,
102
+ dialog and preferences link inside the provider. See
103
+ [React scripts and embeds](../frameworks/react/scripts.md).
117
104
 
118
105
  **Nuxt**
119
106
 
120
- Attach one loader from the root `app.vue`, after the Nuxt module has
121
- started its browser runtime. This keeps vendor callbacks in application code rather
122
- than serialized `nuxt.config.ts` runtime configuration.
107
+ Register the scripts under the `c15t` key in `app/app.config.ts`. Adjust the
108
+ relative import to where you created `consent-scripts.ts`:
123
109
 
124
- ```vue title="app/app.vue"
125
- <script setup lang="ts">
126
- import { onUnmounted } from 'vue';
127
- import { createScriptLoader } from 'c15t/modules/script-loader';
110
+ ```ts title="app/app.config.ts"
128
111
  import { scripts } from '../src/consent-scripts';
129
112
 
130
- const nuxtApp = useNuxtApp();
131
- const kernel = useConsentKernel();
132
- let loader: ReturnType<typeof createScriptLoader> | undefined;
133
-
134
- const removeMountedHook = nuxtApp.hook('app:mounted', () => {
135
- loader = createScriptLoader({ kernel, scripts });
136
- });
137
- onUnmounted(() => {
138
- removeMountedHook();
139
- loader?.dispose();
113
+ export default defineAppConfig({
114
+ c15t: { scripts },
140
115
  });
141
- </script>
142
-
143
- <template>
144
- <ConsentRoot />
145
- <NuxtPage />
146
- </template>
147
116
  ```
148
117
 
149
- Merge the setup code into your root and retain its footer and preferences
150
- link. `useConsentKernel` is auto-imported by the c15t Nuxt module. Adjust the
151
- relative script import if your `app.vue` is at the project root. This loader
152
- waits until the module has applied browser persistence and privacy signals,
153
- then reads the current snapshot and observes future changes. Do not also register these scripts
154
- in another loader. See the [Nuxt quickstart](https://c15t.com/docs/frameworks/nuxt/quickstart).
118
+ The Nuxt module merges this over its options in `nuxt.config.ts` and starts
119
+ one script loader in the browser after hydration, once it has applied the
120
+ visitor's stored choice and privacy signals. Keep `scripts` out of
121
+ `nuxt.config.ts`, which reaches the browser as JSON and drops the vendor
122
+ callbacks. Write the vendor IDs into `consent-scripts.ts`. See
123
+ [Nuxt scripts and embeds](https://v3.c15t.com/docs/frameworks/nuxt/scripts).
155
124
 
156
125
  **Vue**
157
126
 
158
- Use the kernel already provided by the Vue plugin. Merge this setup into
159
- `App.vue`, whose lifetime covers the application:
127
+ Pass the scripts to the existing `c15tVue` plugin call in `src/main.ts`:
160
128
 
161
- ```vue title="src/App.vue"
162
- <script setup lang="ts">
163
- import { onMounted, onUnmounted } from 'vue';
164
- import { createScriptLoader } from 'c15t/modules/script-loader';
165
- import { useConsentKernel } from 'c15t/vue/vue-plugin';
166
- import ConsentRoot from 'c15t/vue/consent-root';
129
+ ```ts title="src/main.ts"
130
+ import { c15tVue, manifest } from 'c15t/vue/vue-plugin';
167
131
  import { scripts } from './consent-scripts';
168
132
 
169
- const kernel = useConsentKernel();
170
- let loader: ReturnType<typeof createScriptLoader> | undefined;
171
-
172
- onMounted(() => {
173
- loader = createScriptLoader({ kernel, scripts });
133
+ app.use(c15tVue, {
134
+ mode: manifest(),
135
+ scripts,
174
136
  });
175
- onUnmounted(() => loader?.dispose());
176
- </script>
177
-
178
- <template>
179
- <ConsentRoot />
180
- <main>Your application</main>
181
- </template>
182
137
  ```
183
138
 
184
- Keep your existing page content and preferences link. The plugin still owns
185
- the kernel and persistence; this component owns only the vendor loader.
186
- Do not register the same scripts in plugin configuration as well. See the
187
- [Vue quickstart](https://c15t.com/docs/frameworks/vue/quickstart).
139
+ Keep your existing `mode` and other options. The plugin starts one
140
+ script loader when the app mounts, after it has applied the visitor's stored
141
+ choice. Do not also call `createScriptLoader` from a component. See
142
+ [Vue scripts and embeds](https://v3.c15t.com/docs/frameworks/vue/scripts).
188
143
 
189
144
  **Astro**
190
145
 
191
- Point the existing Astro integration at a client module. Keep its `mode`,
192
- `ui` and framework integration from the [Astro quickstart](https://c15t.com/docs/frameworks/astro/quickstart).
193
- Import `fileURLToPath` in your Astro configuration:
194
-
195
- ```js title="astro.config.mjs"
196
- import { fileURLToPath } from 'node:url';
197
- ```
198
-
199
- Add this option to the existing `c15t({ ... })` call. Resolve the path from
200
- the configuration file because Astro injects the import into a virtual module:
201
-
202
- ```js
203
- clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)),
204
- ```
205
-
206
- Export the scripts from that module:
146
+ Add the scripts to the client entrypoint from the
147
+ [Astro quickstart](https://v3.c15t.com/docs/frameworks/astro/quickstart), `src/c15t.client.ts`,
148
+ which the integration finds on its own. Keep `astro.config.mjs` as it is.
149
+ If the module already exports scripts, combine the two arrays.
207
150
 
208
151
  ```ts title="src/c15t.client.ts"
209
- import type { C15tClientOptionsExtension } from '@c15t/astro';
152
+ import type { C15tClientOptionsExtension } from 'c15t/astro';
210
153
  import { scripts } from './consent-scripts';
211
154
 
212
155
  export default { scripts } satisfies C15tClientOptionsExtension;
213
156
  ```
214
157
 
215
- The integration passes this extension to its shared browser runtime. Vendor
216
- helpers contain callbacks, so do not put them in the serialized `scripts`
217
- option in `astro.config.mjs`. Keep one runtime across consent islands and
158
+ Vendor helpers contain callbacks, and the integration options in
159
+ `astro.config.mjs` are serialized into the page, so do not put helpers in
160
+ the integration's `scripts` option. The integration passes the client
161
+ entrypoint to the one runtime every page shares, including across
218
162
  `ClientRouter` navigation.
219
163
 
220
164
  **Svelte**
@@ -224,174 +168,289 @@ pass them as a top-level prop:
224
168
 
225
169
  ```svelte title="src/App.svelte"
226
170
  <script lang="ts">
227
- import { ConsentManagerProvider, hosted } from '@c15t/svelte';
171
+ import { ConsentProvider, manifest } from '@c15t/svelte';
228
172
  import { scripts } from './consent-scripts';
229
-
230
- const backendURL = import.meta.env.VITE_C15T_BACKEND_URL;
231
- if (!backendURL) throw new Error('Set VITE_C15T_BACKEND_URL');
232
- const mode = hosted({ url: backendURL });
233
173
  </script>
234
174
 
235
- <ConsentManagerProvider {mode} {scripts}>
175
+ <ConsentProvider mode={manifest()} {scripts}>
236
176
  <!-- Keep your application, consent UI and preferences link here. -->
237
- </ConsentManagerProvider>
177
+ </ConsentProvider>
238
178
  ```
239
179
 
240
- Retain the styles and consent UI from the [Svelte quickstart](https://c15t.com/docs/frameworks/svelte/quickstart).
180
+ Retain the styles and consent UI from the [Svelte quickstart](https://v3.c15t.com/docs/frameworks/svelte/quickstart).
241
181
  The provider owns the loader and disposes it on unmount.
242
182
 
243
183
  **SvelteKit**
244
184
 
245
- Add the scripts to the existing root layout provider. Keep the server load
246
- and its serializable prefetch data from the [SvelteKit quickstart](https://c15t.com/docs/frameworks/sveltekit/quickstart).
185
+ Add the scripts to the existing `ConsentRoot` in the root layout. Keep the
186
+ handle and the layout load from the [SvelteKit quickstart](https://v3.c15t.com/docs/frameworks/sveltekit/quickstart).
247
187
 
248
188
  ```svelte title="src/routes/+layout.svelte"
249
189
  <script lang="ts">
250
- import { ConsentManagerProvider, hosted } from '@c15t/svelte';
190
+ import { ConsentRoot } from '@c15t/svelte';
251
191
  import { scripts } from '../consent-scripts';
252
192
 
253
193
  let { children, data } = $props();
254
- const mode = hosted({ url: data.backendURL });
255
194
  </script>
256
195
 
257
- <ConsentManagerProvider {mode} {scripts} prefetch={data.prefetch}>
196
+ <ConsentRoot state={data.consent} {scripts}>
258
197
  {@render children()}
259
198
  <!-- Keep your consent UI and preferences link here. -->
260
- </ConsentManagerProvider>
199
+ </ConsentRoot>
261
200
  ```
262
201
 
263
- Import vendor helpers in the layout component, not in `+layout.server.ts`.
264
- For static hosting, keep your browser-only `mode` setup and omit request
265
- prefetch; the `scripts` prop stays the same. If you pass an externally owned
202
+ Import vendor helpers in the layout component, not in `+layout.server.ts`:
203
+ a server load cannot send functions to the browser. Prerendered, static and
204
+ SPA-mode pages use the same `scripts` prop. If you pass an externally owned
266
205
  `runtime` to the provider, register scripts when creating that runtime instead.
267
206
 
207
+ **HTML**
208
+
209
+ The helpers in `@c15t/integrations` are ES modules that need a bundler. On a
210
+ page that loads the c15t script tag, paste the vendor's own snippet instead
211
+ and keep it inert until its category is allowed:
212
+
213
+ ```html
214
+ <script type="text/plain" data-c15t-category="measurement">
215
+ // The vendor's snippet, unchanged
216
+ </script>
217
+ ```
218
+
219
+ Use the category this guide names for the vendor. c15t runs the snippet
220
+ once that category is allowed, and reloads the page when the visitor
221
+ withdraws it. Helper options on this page, such as `loadMode`, do not apply
222
+ to a pasted snippet. See [HTML scripts](https://v3.c15t.com/docs/frameworks/html/scripts).
223
+
268
224
  **JavaScript**
269
225
 
270
- Attach the loader to your existing kernel before calling
271
- `kernel.commands.init()`:
226
+ Pass the scripts to `init()` from `@c15t/browser`, next to your mode:
272
227
 
273
228
  ```ts
274
- import { createScriptLoader } from 'c15t/modules/script-loader';
229
+ import { init, manifest } from '@c15t/browser';
275
230
  import { scripts } from './consent-scripts';
276
231
 
277
- const loader = createScriptLoader({ kernel, scripts });
232
+ const consent = init({
233
+ mode: manifest(),
234
+ scripts,
235
+ });
278
236
  ```
279
237
 
280
- Call `loader.dispose()` when that application instance is destroyed.
281
- `kernel` is the hosted kernel from your quickstart. A provider-owned kernel
282
- already has a loader; do not attach a second one. See
283
- [JavaScript script loading](https://c15t.com/docs/frameworks/javascript/script-loader).
238
+ Keep the mode from your quickstart. With
239
+ `createConsentRuntime` from `c15t/runtime`, pass `scripts` to it instead.
240
+ A kernel you create yourself needs a loader from
241
+ `c15t/modules/script-loader`. Attach one loader per kernel. See
242
+ [JavaScript scripts](https://v3.c15t.com/docs/frameworks/javascript/scripts).
243
+
244
+ ## Options
245
+
246
+ | Option | Default | Behavior |
247
+ | ----------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
248
+ | `id` | Required | Project token, starting with `phc_`. The helper trims it. Empty or whitespace-only values log an error and the script does not load. |
249
+ | `region` | `'eu'` | `'eu'` or `'us'`. Picks the API, UI and loader hosts when you do not set them. |
250
+ | `apiHost` | `https://eu.i.posthog.com` | API host for a proxy or self-hosted PostHog. Without `scriptUrl`, the loader URL becomes `<apiHost>/static/array.js`. |
251
+ | `uiHost` | The region's UI host | UI host, for example `https://eu.posthog.com`. A custom `apiHost` with no `region` uses the API host. |
252
+ | `scriptUrl` | `https://eu-assets.i.posthog.com/static/array.js` | Loader URL override. A blank value falls back to the default. |
253
+ | `loadMode` | `'always'` | When the SDK loads. See the table below. |
254
+ | `features.surveys` | Unset | `false` sets `disable_surveys: true` and skips `surveys.js`. See [turn off features you do not use](#turn-off-features-you-do-not-use). |
255
+ | `features.heatmaps` | Unset, follows the project | Sets `capture_heatmaps`. |
256
+ | `features.deadClicks` | Unset, follows the project | Sets `capture_dead_clicks`. |
257
+ | `features.webVitals` | Unset, follows the project | Sets `capture_performance: { web_vitals }`. Replay network timing keeps following the project. |
258
+ | `features.featureFlags` | Unset, follows the project | `false` sets `advanced_disable_feature_flags: true` and stops `/flags` requests. |
259
+ | `initOptions` | `{ cookieless_mode: 'on_reject', defaults: '2026-01-30' }` | Options passed to `posthog.init`, merged over the defaults and `features`. The helper sets `api_host` and `ui_host` after your values, so change hosts with the options above. |
260
+
261
+ ## Loading and revocation
262
+
263
+ | `loadMode` | When PostHog loads | Consent sync |
264
+ | ----------------- | --------------------------------- | --------------------------------------------------------------------------- |
265
+ | `'always'` | On every page, before consent | Calls `opt_in_capturing` or `opt_out_capturing` at load and on every change |
266
+ | `'after-consent'` | Only while measurement is allowed | Calls `opt_in_capturing` at load and `opt_out_capturing` on revocation |
267
+ | `'disabled'` | Never | None. The helper returns an empty callback-only script |
268
+
269
+ `posthog` uses the `measurement` category. With the default
270
+ `cookieless_mode: 'on_reject'`, PostHog keeps capturing without cookies after a
271
+ refusal. That mode needs cookieless server hashing turned on in your PostHog
272
+ project; see
273
+ [PostHog's cookieless guide](https://posthog.com/tutorials/cookieless-tracking).
274
+ Set `cookieless_mode: 'never'`, as in the example, if a refusal must stop
275
+ capture.
284
276
 
285
- ## Choose loading and capture behavior separately
277
+ ## Turn off features you do not use
286
278
 
287
- | `loadMode` | SDK loading | Consent handling |
288
- | ------------------------------ | ------------------------------------- | --------------------------------------------------------------- |
289
- | `'after-consent'` | Waits for measurement permission | Calls PostHog opt-in and opt-out APIs after load and on changes |
290
- | `'always'`, the helper default | Loads even while permission is denied | Calls the same consent APIs |
291
- | `'disabled'` | Does not load PostHog | Does not synchronize consent with an SDK loaded elsewhere |
279
+ After `array.js` loads, PostHog reads your `posthog.init` options and the
280
+ project's remote config, then decides which extra modules to download and
281
+ whether to request `/flags`. Set a `features` switch to `false` for each
282
+ feature your site does not use:
292
283
 
293
- The helper defaults `initOptions.cookieless_mode` to `'on_reject'`. In that
294
- mode, PostHog can continue cookieless capture after denial. It requires the
295
- project's cookieless server hash setting. See
296
- [PostHog's cookieless guide](https://posthog.com/tutorials/cookieless-tracking).
284
+ ```ts
285
+ posthog({
286
+ id: 'phc_YOUR_PROJECT_TOKEN',
287
+ region: 'eu',
288
+ loadMode: 'after-consent',
289
+ features: {
290
+ surveys: false,
291
+ heatmaps: false,
292
+ deadClicks: false,
293
+ webVitals: false,
294
+ featureFlags: false,
295
+ },
296
+ });
297
+ ```
297
298
 
298
- The example overrides this with `'never'` so opting out is not a switch to
299
- cookieless capture. Loading after consent only controls the initial request;
300
- for later revocation, verify PostHog's opt-out behavior and stop application
301
- capture calls too. SDK code that already executed cannot be undone by removing
302
- its script element.
303
-
304
- ## Configure hosts and initialization
305
-
306
- | Option | Behavior |
307
- | ------------------------------ | ---------------------------------------------------------------------------------------- |
308
- | `id` | Browser project token. |
309
- | `region` | `'eu'` by default; use `'us'` for a US project. |
310
- | `apiHost / uiHost / scriptUrl` | Explicit overrides for proxy or self-hosted PostHog deployments. Keep all hosts aligned. |
311
- | `loadMode` | Defaults to `'always'`; choose deliberately. |
312
- | `initOptions` | Additional serializable SDK options, including the cookieless override. |
313
-
314
- The helper applies the resolved API and UI hosts after `initOptions`; use the
315
- top-level host fields to change them. A global `posthog` queue may exist before
316
- the SDK is ready. Neither API presence nor SDK readiness is a consent grant.
317
-
318
- ## Keep application events behind permission
319
-
320
- With the script helper registered, a React client component can guard an event
321
- using the current effective permission:
322
-
323
- ```tsx title="src/signup-event.tsx"
324
- 'use client';
325
-
326
- import { useConsent } from 'c15t/react';
327
-
328
- export function SignupEvent() {
329
- const allowed = useConsent('measurement');
330
-
331
- return (
332
- <button
333
- type="button"
334
- onClick={() => {
335
- if (allowed) window.posthog?.capture('signup_started');
336
- }}
337
- >
338
- Start signup
339
- </button>
340
- );
299
+ | Switch | `false` sets | What PostHog skips |
300
+ | -------------- | -------------------------------------------- | --------------------------------------------------------------------------- |
301
+ | `surveys` | `disable_surveys: true` | `surveys.js`, about 29 KB |
302
+ | `heatmaps` | `capture_heatmaps: false` | Heatmap capture. With `deadClicks: false` too, `dead-clicks-autocapture.js` |
303
+ | `deadClicks` | `capture_dead_clicks: false` | `dead-clicks-autocapture.js`, about 8 KB, once heatmaps are off too |
304
+ | `webVitals` | `capture_performance: { web_vitals: false }` | `web-vitals-with-attribution.js`, about 6 KB |
305
+ | `featureFlags` | `advanced_disable_feature_flags: true` | `/flags` requests. The remote config still loads |
306
+
307
+ Sizes are brotli-compressed, measured from posthog-js 1.436.1.
308
+
309
+ An unset switch adds nothing to `posthog.init`. For heatmaps, dead clicks, web
310
+ vitals and feature flags, PostHog then follows the setting in your PostHog
311
+ project. `true` sets the opposite value and overrides the project. For
312
+ `surveys` and `featureFlags`, `true` is PostHog's own default, so it behaves
313
+ the same as unset.
314
+
315
+ Surveys work differently. PostHog downloads `surveys.js` whenever the remote
316
+ config includes a `surveys` value, even when surveys are off in the project.
317
+ `surveys: false` is the only way to skip it.
318
+
319
+ `initOptions` wins over a switch that sets the same key. A
320
+ `capture_performance` value in `initOptions` replaces the whole object that
321
+ `webVitals` builds.
322
+
323
+ ### Avoid PostHog's option traps
324
+
325
+ These rules also apply when you pass PostHog options yourself, in
326
+ `initOptions` or in your own `posthog.init`:
327
+
328
+ * Use `advanced_disable_feature_flags: true` to stop `/flags`, not
329
+ `advanced_disable_flags: true`. The second also stops PostHog loading the
330
+ remote config, so session replay never starts and other features fall back to
331
+ local config.
332
+ * With feature flags off, surveys that target a feature flag never show.
333
+ PostHog logs a warning about it. If you need those surveys, leave
334
+ `featureFlags` unset and pass
335
+ `advanced_only_evaluate_survey_feature_flags: true` instead. PostHog still
336
+ requests `/flags`, but evaluates only survey flags.
337
+ * While heatmaps are on, in `posthog.init` or in the project, PostHog loads
338
+ `dead-clicks-autocapture.js` whatever `capture_dead_clicks` says. Turn off
339
+ both to skip it.
340
+ * `capture_performance: false` turns off web vitals and session replay network
341
+ timing. `{ web_vitals: false }`, which `webVitals: false` sets, leaves network
342
+ timing to the project. `capture_performance: true` forces both on.
343
+
344
+ Product tours (`product-tours.js`, about 36 KB) and exception autocapture
345
+ (`exception-autocapture.js`, about 6 KB) load only when the project turns them
346
+ on. To keep them off whatever the project says, pass
347
+ `disable_product_tours: true` or `capture_exceptions: false` in `initOptions`.
348
+
349
+ ## Guard your own capture calls
350
+
351
+ Events your code sends need their own permission check. The `posthog` global
352
+ exists before the SDK loads, so its presence does not mean measurement is
353
+ allowed:
354
+
355
+ ```ts title="src/track-signup.ts"
356
+ export function trackSignupStarted(measurementAllowed: boolean) {
357
+ if (!measurementAllowed) return;
358
+ window.posthog?.capture('signup_started');
341
359
  }
342
360
  ```
343
361
 
344
- This is an event-call example, not a signup implementation. Next.js client
345
- components can import `useConsent` from `c15t/next`.
362
+ Pass the current measurement permission from your framework, for example
363
+ `useConsent('measurement')` in React.
346
364
 
347
365
  ## Use an existing PostHog SDK
348
366
 
349
- If your app already initializes `posthog-js`, keep that SDK owner and attach a
350
- callback-only script instead of the loading helper. Initialize your SDK with
351
- `opt_out_capturing_by_default: true` and `cookieless_mode: 'never'` before
352
- mounting c15t when denied permission must stop capture.
367
+ If your app already initializes `posthog-js`, keep that setup and register a
368
+ callback-only script instead of the helper. Initialize the SDK with
369
+ `opt_out_capturing_by_default: true` and `cookieless_mode: 'never'` so it
370
+ captures nothing before c15t reports a permission.
353
371
 
354
372
  ```ts title="src/posthog-consent.ts"
355
373
  import type { Script, ScriptCallbackInfo } from 'c15t/modules/script-loader';
356
374
 
357
375
  type PostHogConsentApi = {
358
- opt_in_capturing: () => unknown;
359
- opt_out_capturing: () => unknown;
376
+ opt_in_capturing: () => unknown;
377
+ opt_out_capturing: () => unknown;
360
378
  };
361
379
 
362
380
  export function posthogConsent(instance: PostHogConsentApi): Script {
363
- const sync = ({ hasConsent }: ScriptCallbackInfo) => {
364
- if (hasConsent) instance.opt_in_capturing();
365
- else instance.opt_out_capturing();
366
- };
367
-
368
- return {
369
- id: 'posthog-sdk-consent',
370
- category: 'measurement',
371
- callbackOnly: true,
372
- alwaysLoad: true,
373
- onBeforeLoad: sync,
374
- onConsentChange: sync,
375
- };
381
+ const sync = ({ hasConsent }: ScriptCallbackInfo) => {
382
+ if (hasConsent) instance.opt_in_capturing();
383
+ else instance.opt_out_capturing();
384
+ };
385
+
386
+ return {
387
+ id: 'posthog-sdk-consent',
388
+ category: 'measurement',
389
+ callbackOnly: true,
390
+ alwaysLoad: true,
391
+ onBeforeLoad: sync,
392
+ onConsentChange: sync,
393
+ };
376
394
  }
377
395
  ```
378
396
 
379
- Pass `posthogConsent(posthog)` in the existing provider's `scripts` array, using
380
- your initialized SDK instance. The callback-only entry synchronizes initial
381
- and changed effective permissions without loading a second SDK. It does not
382
- block the SDK import or its initial request. `loadMode: 'disabled'` on the
383
- loading helper is not a substitute, because it performs no synchronization.
384
-
385
- Keep c15t as the source of truth for the banner and saved choices. Effective
386
- permission can come from policy defaults; a synchronization callback is not
387
- proof that the visitor explicitly accepted. Do not reuse v2
388
- `getOrCreateConsentRuntime` or `onBannerFetched` examples with v3.
389
-
390
- ## Verify the integration
391
-
392
- With the example above, a fresh opt-in session should make no PostHog SDK
393
- request until measurement is allowed. Grant, capture one test event, revoke,
394
- and confirm later application calls stop. Repeat with persisted consent and
395
- client navigation. If you choose cookieless capture, verify that behavior
396
- explicitly in the project rather than expecting silence after denial. See
397
- [consent verification](../guides/verify-consent.md).
397
+ Add `posthogConsent(posthog)` to the `scripts` you register, passing your
398
+ initialized SDK instance. `callbackOnly` means c15t inserts no script element.
399
+ `alwaysLoad` makes `onBeforeLoad` run on the first page load even while
400
+ measurement is denied, so the SDK is told to opt out. `onConsentChange` runs on
401
+ every later change. This does not delay the SDK import or its first request.
402
+ `loadMode: 'disabled'` is not a substitute, because it syncs nothing.
403
+
404
+ `features` belongs to the helper, so it does nothing here. To skip modules you
405
+ do not use, pass the PostHog options from
406
+ [turn off features you do not use](#turn-off-features-you-do-not-use) to your
407
+ own `posthog.init`, for example `disable_surveys: true`.
408
+
409
+ ## Measure opt-in rate
410
+
411
+ If you run a banner experiment, the backend already counts visitors and
412
+ choices per arm. To see the arm in PostHog as well, forward the `onSurfaceShown` and
413
+ `onChoiceRecorded` callbacks, which carry `experiment: { id, arm }`. See
414
+ [banner experiments](../guides/banner-experiments.md#send-the-events-to-your-own-analytics-too).
415
+
416
+ ## Verify PostHog
417
+
418
+ These checks assume `loadMode: 'after-consent'` from the example. After you
419
+ allow measurement, `array.js` loads and capture requests to your API host
420
+ follow. Trigger one guarded event and check that it is sent.
421
+
422
+ With `loadMode: 'always'`, `array.js` loads before a choice instead. Check that
423
+ no capture request is sent while measurement is denied, unless you chose
424
+ cookieless capture.
425
+
426
+ If you turned features off, allow measurement and filter the DevTools Network
427
+ panel by `posthog`. Reload the page. You should see `array.js`, the remote
428
+ config and capture requests, but no `/flags` request with `featureFlags: false`
429
+ and none of the modules you turned off, such as `surveys.js` or
430
+ `dead-clicks-autocapture.js`.
431
+
432
+ Test in a private window with an opt-in policy. Open DevTools Network, disable
433
+ the cache and filter by the vendor's domain:
434
+
435
+ 1. Load the page. No request goes to the vendor before you choose.
436
+ 2. Click Reject, then reload. There is still no vendor request.
437
+ 3. Open Privacy settings and allow the helper's category. The vendor script
438
+ loads without a page reload.
439
+ 4. Turn the category off again and save. c15t reloads the page, and the new
440
+ page makes no vendor request.
441
+
442
+ c15t reloads on revocation because removing a script element does not stop
443
+ code that already ran. The vendor's listeners, timers and queued events stay
444
+ alive until the page unloads. If you set `reloadOnConsentRevoked: false`, stop
445
+ the vendor yourself. Register a callback-only script whose `onConsentChange`
446
+ calls the vendor's opt-out API, as shown in
447
+ [custom integrations](./building-integrations.md), and check the
448
+ permission before each of your own event calls. The reload does not delete
449
+ cookies the vendor already set; see
450
+ [clear on revocation for your framework](./overview.md#vendor-switches-and-cookie-cleanup).
451
+
452
+ The helper sets `vendor` to its script ID, so once you declare that vendor a
453
+ visitor can turn it off inside an allowed category. See
454
+ [vendor consent for your framework](./overview.md#vendor-switches-and-cookie-cleanup). The
455
+ [consent verification guide](../guides/verify-consent.md) covers navigation,
456
+ expiry and hosting checks.