@c15t/nextjs 2.1.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/AGENTS.md +155 -0
  2. package/README.md +31 -15
  3. package/client/components/integrations.js +3 -0
  4. package/dist/components/integrations/index.cjs +1 -0
  5. package/dist/components/integrations/index.js +1 -0
  6. package/dist/headless.cjs +1 -1
  7. package/dist/index.cjs +1 -1
  8. package/dist/libs/browser-initial-data.cjs +1 -1
  9. package/dist/libs/initial-data.cjs +1 -1
  10. package/dist/styles.tw3.css +1 -1
  11. package/dist/version.cjs +1 -1
  12. package/dist/version.js +1 -1
  13. package/dist-types/components/integrations/index.d.ts +1 -0
  14. package/dist-types/libs/browser-initial-data.d.ts +1 -1
  15. package/dist-types/version.d.ts +1 -1
  16. package/docs/README.md +155 -73
  17. package/docs/{building-headless-components.md → frameworks/next/building-headless-components.md} +3 -1
  18. package/docs/{callbacks.md → frameworks/next/callbacks.md} +3 -1
  19. package/docs/{components → frameworks/next/components}/consent-banner.md +10 -21
  20. package/docs/{components → frameworks/next/components}/consent-dialog-link.md +8 -5
  21. package/docs/frameworks/next/components/consent-dialog-trigger.md +202 -0
  22. package/docs/{components → frameworks/next/components}/consent-dialog.md +7 -15
  23. package/docs/frameworks/next/components/consent-manager-provider.md +327 -0
  24. package/docs/{components → frameworks/next/components}/consent-widget.md +8 -6
  25. package/docs/{components → frameworks/next/components}/dev-tools.md +9 -6
  26. package/docs/{components → frameworks/next/components}/frame.md +8 -9
  27. package/docs/{concepts → frameworks/next/concepts}/client-modes.md +4 -2
  28. package/docs/{concepts → frameworks/next/concepts}/consent-categories.md +1 -0
  29. package/docs/{concepts → frameworks/next/concepts}/consent-models.md +1 -0
  30. package/docs/{concepts → frameworks/next/concepts}/cookie-management.md +3 -3
  31. package/docs/{concepts → frameworks/next/concepts}/glossary.md +1 -0
  32. package/docs/{concepts → frameworks/next/concepts}/initialization-flow.md +1 -0
  33. package/docs/{concepts → frameworks/next/concepts}/policy-packs.md +1 -0
  34. package/docs/{headless.md → frameworks/next/headless.md} +3 -1
  35. package/docs/{hooks → frameworks/next/hooks}/use-color-scheme.md +1 -0
  36. package/docs/{hooks → frameworks/next/hooks}/use-consent-manager/checking-consent.md +3 -1
  37. package/docs/{hooks → frameworks/next/hooks}/use-consent-manager/location-info.md +3 -1
  38. package/docs/frameworks/next/hooks/use-consent-manager/overview.md +185 -0
  39. package/docs/{hooks → frameworks/next/hooks}/use-consent-manager/setting-consent.md +3 -1
  40. package/docs/{hooks → frameworks/next/hooks}/use-draggable.md +3 -1
  41. package/docs/{hooks → frameworks/next/hooks}/use-focus-trap.md +1 -0
  42. package/docs/{hooks → frameworks/next/hooks}/use-reduced-motion.md +3 -1
  43. package/docs/{hooks → frameworks/next/hooks}/use-ssr-status.md +6 -5
  44. package/docs/{hooks → frameworks/next/hooks}/use-text-direction.md +1 -0
  45. package/docs/frameworks/next/hooks/use-translations.md +55 -0
  46. package/docs/{iab → frameworks/next/iab}/consent-banner.md +9 -12
  47. package/docs/{iab → frameworks/next/iab}/consent-dialog.md +9 -14
  48. package/docs/{iab → frameworks/next/iab}/overview.md +4 -2
  49. package/docs/{iab → frameworks/next/iab}/use-gvl-data.md +3 -2
  50. package/docs/{iframe-blocking.md → frameworks/next/iframe-blocking.md} +8 -9
  51. package/docs/{internationalization.md → frameworks/next/internationalization.md} +13 -3
  52. package/docs/{network-blocker.md → frameworks/next/network-blocker.md} +13 -51
  53. package/docs/{optimization.md → frameworks/next/optimization.md} +5 -4
  54. package/docs/{policy-packs.md → frameworks/next/policy-packs.md} +3 -1
  55. package/docs/{quickstart.md → frameworks/next/quickstart.md} +26 -42
  56. package/docs/{script-loader.md → frameworks/next/script-loader.md} +72 -90
  57. package/docs/{server-side.md → frameworks/next/server-side.md} +12 -15
  58. package/docs/{styling → frameworks/next/styling}/classnames.md +3 -1
  59. package/docs/{styling → frameworks/next/styling}/color-scheme.md +3 -1
  60. package/docs/frameworks/next/styling/css-variables.md +53 -0
  61. package/docs/frameworks/next/styling/overview.md +299 -0
  62. package/docs/frameworks/next/styling/slots.md +94 -0
  63. package/docs/{styling → frameworks/next/styling}/tailwind.md +3 -1
  64. package/docs/frameworks/next/styling/tokens.md +156 -0
  65. package/docs/{troubleshooting.md → frameworks/next/troubleshooting.md} +3 -1
  66. package/docs/integrations/adobe-analytics.md +160 -0
  67. package/docs/integrations/ahrefs-analytics.md +15 -82
  68. package/docs/integrations/amplitude.md +230 -0
  69. package/docs/integrations/building-integrations.md +15 -181
  70. package/docs/integrations/clearbit.md +130 -0
  71. package/docs/integrations/cloudflare-web-analytics.md +15 -83
  72. package/docs/integrations/crisp.md +13 -87
  73. package/docs/integrations/databuddy.md +16 -85
  74. package/docs/integrations/fathom-analytics.md +15 -86
  75. package/docs/integrations/google-maps.md +263 -0
  76. package/docs/integrations/google-tag-manager.md +18 -86
  77. package/docs/integrations/google-tag.md +15 -84
  78. package/docs/integrations/heap.md +219 -0
  79. package/docs/integrations/hightouch.md +199 -0
  80. package/docs/integrations/hotjar.md +15 -83
  81. package/docs/integrations/intercom.md +13 -83
  82. package/docs/integrations/linkedin-insights.md +15 -82
  83. package/docs/integrations/logrocket.md +175 -0
  84. package/docs/integrations/matomo-analytics.md +13 -88
  85. package/docs/integrations/meta-pixel.md +33 -316
  86. package/docs/integrations/microsoft-clarity.md +15 -83
  87. package/docs/integrations/microsoft-uet.md +16 -83
  88. package/docs/integrations/mixpanel-analytics.md +15 -83
  89. package/docs/integrations/overview.md +55 -6
  90. package/docs/integrations/pirsch.md +142 -0
  91. package/docs/integrations/plausible-analytics.md +14 -97
  92. package/docs/integrations/posthog.md +26 -98
  93. package/docs/integrations/promptwatch.md +16 -82
  94. package/docs/integrations/reddit-pixel.md +27 -122
  95. package/docs/integrations/rudderstack.md +271 -0
  96. package/docs/integrations/rybbit-analytics.md +15 -94
  97. package/docs/integrations/segment.md +15 -82
  98. package/docs/integrations/snapchat-pixel.md +21 -102
  99. package/docs/integrations/tiktok-pixel.md +13 -81
  100. package/docs/integrations/umami-analytics.md +16 -88
  101. package/docs/integrations/vercel-analytics.md +13 -85
  102. package/docs/integrations/x-pixel.md +27 -102
  103. package/docs/integrations/youtube.md +193 -0
  104. package/docs/shared/concepts/client-modes.md +103 -0
  105. package/docs/shared/concepts/consent-categories.md +41 -0
  106. package/docs/shared/concepts/consent-models.md +72 -0
  107. package/docs/shared/concepts/cookie-management.md +88 -0
  108. package/docs/shared/concepts/glossary.md +24 -0
  109. package/docs/shared/concepts/initialization-flow.md +105 -0
  110. package/docs/shared/concepts/policy-packs.md +225 -0
  111. package/docs/shared/react/components/consent-banner.md +242 -0
  112. package/docs/shared/react/components/consent-dialog-link.md +45 -0
  113. package/docs/shared/react/components/consent-dialog-trigger.md +185 -0
  114. package/docs/shared/react/components/consent-dialog.md +119 -0
  115. package/docs/shared/react/components/consent-manager-provider.md +225 -0
  116. package/docs/shared/react/components/consent-widget.md +121 -0
  117. package/docs/shared/react/components/dev-tools.md +81 -0
  118. package/docs/shared/react/components/frame.md +52 -0
  119. package/docs/shared/react/guides/building-headless-components.md +110 -0
  120. package/docs/shared/react/guides/callbacks.md +89 -0
  121. package/docs/shared/react/guides/headless.md +31 -0
  122. package/docs/shared/react/guides/iframe-blocking.md +65 -0
  123. package/docs/shared/react/guides/internationalization.md +123 -0
  124. package/docs/shared/react/guides/network-blocker.md +72 -0
  125. package/docs/shared/react/guides/optimization.md +44 -0
  126. package/docs/shared/react/guides/policy-packs.md +173 -0
  127. package/docs/shared/react/guides/script-loader.md +311 -0
  128. package/docs/shared/react/hooks/use-color-scheme.md +31 -0
  129. package/docs/shared/react/hooks/use-consent-manager/checking-consent.md +95 -0
  130. package/docs/shared/react/hooks/use-consent-manager/location-info.md +96 -0
  131. package/docs/shared/react/hooks/use-consent-manager/overview.md +74 -0
  132. package/docs/shared/react/hooks/use-consent-manager/setting-consent.md +93 -0
  133. package/docs/shared/react/hooks/use-draggable.md +30 -0
  134. package/docs/shared/react/hooks/use-focus-trap.md +20 -0
  135. package/docs/shared/react/hooks/use-reduced-motion.md +33 -0
  136. package/docs/shared/react/hooks/use-ssr-status.md +16 -0
  137. package/docs/shared/react/hooks/use-text-direction.md +38 -0
  138. package/docs/shared/react/hooks/use-translations.md +15 -0
  139. package/docs/shared/react/iab/consent-banner.md +60 -0
  140. package/docs/shared/react/iab/consent-dialog.md +76 -0
  141. package/docs/shared/react/iab/overview.md +80 -0
  142. package/docs/shared/react/iab/use-gvl-data.md +21 -0
  143. package/docs/shared/react/styling/classnames.md +93 -0
  144. package/docs/shared/react/styling/color-scheme.md +35 -0
  145. package/docs/shared/react/styling/css-variables.md +53 -0
  146. package/docs/shared/react/styling/overview.md +261 -0
  147. package/docs/shared/react/styling/slots.md +93 -0
  148. package/docs/shared/react/styling/stylesheet-entrypoint.md +8 -0
  149. package/docs/shared/react/styling/tailwind.md +88 -0
  150. package/docs/shared/react/styling/tokens.md +155 -0
  151. package/docs/shared/troubleshooting.md +82 -0
  152. package/package.json +19 -10
  153. package/readme.json +14 -8
  154. package/docs/ai-agents.md +0 -111
  155. package/docs/components/consent-dialog-trigger.md +0 -103
  156. package/docs/components/consent-manager-provider.md +0 -425
  157. package/docs/hooks/use-consent-manager/overview.md +0 -420
  158. package/docs/hooks/use-translations.md +0 -118
  159. package/docs/styling/css-variables.md +0 -92
  160. package/docs/styling/overview.md +0 -457
  161. package/docs/styling/slots.md +0 -128
  162. package/docs/styling/tokens.md +0 -216
@@ -0,0 +1,110 @@
1
+ ---
2
+ title: Building Headless Components
3
+ description: Reference page for building headless components.
4
+ group: reference
5
+ ---
6
+ Building custom consent UI is easier now because c15t exposes multiple layers of policy-aware primitives instead of forcing you to reconstruct banner rules by hand.
7
+
8
+ Think of customization as a ladder:
9
+
10
+ * stock component props for the shortest path
11
+ * `ConsentBanner.PolicyActions` and `ConsentWidget.PolicyActions` when you want custom structure but still want c15t to resolve policy-aware actions
12
+ * `useHeadlessConsentUI()` when you need fully manual action rendering, custom controls, or non-standard flow
13
+
14
+ > ⚠️ **Warning:**
15
+ > Headless is the last step in the customization ladder. Use this guide only when pre-built components, tokens, slots, compound components, and noStyle are no longer sufficient.
16
+
17
+ The headless stack underneath that is:
18
+
19
+ * `useHeadlessConsentUI()` for policy-aware banner/dialog actions, ordering, layout, and primary actions hints
20
+ * `@c15t/ui/utils` for the pure policy-action helpers that framework packages build on
21
+ * `useConsentManager()` for runtime state, categories, selected consent state, and policy metadata
22
+ * `useTranslations()` for the resolved copy
23
+ * `offlinePolicy.policyPacks` for offline previews that behave like backend policy resolution
24
+
25
+ The split is intentional: `@c15t/ui` owns pure policy-action resolution, while the framework hooks own visibility, consent mutations, and reactive state.
26
+
27
+ > ℹ️ **Info:**
28
+ > This guide is about building your own components while still respecting resolved policy-pack behavior. For the general headless overview, see Headless Mode.
29
+
30
+ ## Choose the Smallest Layer That Solves the Job
31
+
32
+ Start with the smallest API surface that still gives you the behavior you need:
33
+
34
+ * Stay with stock components when you only need theming, spacing, copy, or legal-link changes
35
+ * Use `ConsentBanner.PolicyActions` or `ConsentWidget.PolicyActions` when you want a custom compound-component layout but still want grouped actions, ordering, and primary emphasis to come from policy
36
+ * Add `renderAction` when the grouping is still correct but you want to remap actions to stock c15t button compounds
37
+ * Reach for `useHeadlessConsentUI()` only when you need custom button elements, need to map `actionGroups` yourself, wire non-button controls, or coordinate the consent UI with a more custom state machine
38
+
39
+ This order matters because every step down the ladder gives you more control, but also makes it easier for your UI to drift away from the resolved policy if you stop using the provided state.
40
+
41
+ ## Before You Build Headless UI
42
+
43
+ Do not use headless mode for problems that are still inside the stock component model:
44
+
45
+ * Use `layout`, `direction`, `primaryButton`, and `legalLinks` before you rebuild banner markup
46
+ * Use `theme.consentActions` before you swap out stock actions
47
+ * Use tokens such as `colors.surface` and `colors.surfaceHover` before raw CSS overrides
48
+ * Use slots such as `consentBannerCard`, `consentBannerFooter`, and `consentDialogCard` before compound components
49
+ * Use `ConsentManagerProvider.options.i18n` before rebuilding UI just to change text
50
+
51
+ A good rule: if the stock banner or dialog structure is still correct, you probably do not need headless mode.
52
+
53
+ ## What the Headless Tooling Gives You
54
+
55
+ The main win is that your custom UI can stay aligned with policy packs without duplicating policy logic in your components.
56
+
57
+ `useHeadlessConsentUI()` already resolves:
58
+
59
+ * which actions are allowed
60
+ * the order those actions should render in
61
+ * grouped actions from policy `layout`
62
+ * layout `direction` (`row` or `column`)
63
+ * the primary actions
64
+ * UI profile and scroll-lock hints
65
+ * whether the banner or dialog should currently be visible
66
+
67
+ The hook also gives you the policy-aware action helpers you are expected to call:
68
+
69
+ * `performBannerAction('accept' | 'reject')`
70
+ * `performDialogAction('accept' | 'reject')`
71
+ * `saveCustomPreferences()` for the dialog `customize` action
72
+ * `openDialog()`, `openBanner()`, and `closeUI()` for surface visibility
73
+
74
+ That means your component mostly focuses on markup and design-system concerns instead of re-implementing policy interpretation.
75
+
76
+ For most compound-component layouts, start with `ConsentBanner.PolicyActions` or `ConsentWidget.PolicyActions`. They render stock c15t buttons and translations by default, and `renderAction` is only needed when you want to override which stock compound renders for each action. Reach for manual `actionGroups` mapping when you need action rendering that no longer fits the stock button compounds.
77
+
78
+ ## What Headless Is Not For
79
+
80
+ Headless mode is not the recommended path for:
81
+
82
+ * changing the banner footer background
83
+ * rounding the stock banner card
84
+ * restyling stock banner or dialog buttons
85
+ * changing consent copy
86
+
87
+ Those should stay in the pre-built stack with tokens, slots, `theme.consentActions`, and provider `i18n`.
88
+
89
+ ## What a Policy-Aware Headless Component Should Respect
90
+
91
+ When you build custom banner or dialog components, make sure they use:
92
+
93
+ * `activeUI` or `banner.isVisible` / `dialog.isVisible` for visibility
94
+ * `allowedActions`, `actionGroups`, and `primaryActions` instead of hard-coding buttons
95
+ * `primaryActions` for visual emphasis
96
+ * `consentCategories` when deciding which category toggles to render
97
+ * `policyDecision` when you want to debug why a specific UI state was chosen
98
+
99
+ If you ignore those values, your custom UI can drift away from the resolved policy pack even though the underlying consent engine is configured correctly.
100
+
101
+ ## Validation and Testing
102
+
103
+ If you are building a reusable headless component library, validate your rendered UI against the resolved runtime policy in tests.
104
+
105
+ The core package exposes:
106
+
107
+ * `getEffectivePolicy(initData)` to read the resolved policy from `/init`
108
+ * `validateUIAgainstPolicy({ policy, state })` to detect mismatches such as wrong actions, layout, or mode
109
+
110
+ This is useful when your design system renders custom button arrangements and you want tests to catch policy drift early.
@@ -0,0 +1,89 @@
1
+ ---
2
+ title: Callbacks
3
+ description: Reference page for callbacks.
4
+ group: reference
5
+ ---
6
+ Callbacks let you run custom code at key points in the consent lifecycle. Define them in the provider or runtime `callbacks` option, or register them dynamically after initialization.
7
+
8
+ For analytics SDKs and other change-only integrations, prefer `subscribeToConsentChanges()` or `onConsentChanged`. Use `onConsentSet` when you want the broader lifecycle signal, including initialization, automatic defaults, and replay-aware registration.
9
+
10
+ ## Choose the Right Surface
11
+
12
+ |Surface|Replays when registered late?|Fires on init / hydration / auto-grants?|Best for|
13
+ |--|--|--|--|
14
+ |`onBannerFetched`|Yes, via `setCallback('onBannerFetched', ...)` after init|Yes|Logging resolved policy, location, and translations|
15
+ |`onConsentSet`|Yes, via `setCallback('onConsentSet', ...)`|Yes|Broad lifecycle hooks, debugging, and integrations that want the latest full state regardless of how it was reached|
16
+ |`onConsentChanged`|No|No|Declarative change-only integrations|
17
+ |`subscribeToConsentChanges()`|No|No|Canonical change-only subscriptions after mount|
18
+
19
+ > ℹ️ **Info:**
20
+ > Script.onConsentChange is a script-scoped lifecycle hook. It is not the global consent change API for analytics SDKs or other app-wide integrations.
21
+
22
+ ## Available Callbacks
23
+
24
+ ### `onBannerFetched`
25
+
26
+ Called when the consent banner data is fetched from the backend (or loaded from SSR data). The payload includes jurisdiction info, location data, and resolved translations.
27
+
28
+ ```tsx
29
+ onBannerFetched: ({ jurisdiction, location, translations }) => {
30
+ // jurisdiction: 'GDPR' | 'CCPA' | { code: 'GDPR', message: '...' } | ...
31
+ // location: { countryCode: 'DE', regionCode: 'BY' }
32
+ // translations: { language: 'de', translations: {...} }
33
+ }
34
+ ```
35
+
36
+ ### `onConsentSet`
37
+
38
+ Called whenever c15t broadly settles consent state: store initialization, automatic defaults during init, explicit saves, and replay via `setCallback('onConsentSet', ...)`.
39
+
40
+ ```tsx
41
+ onConsentSet: ({ preferences }) => {
42
+ // preferences: { necessary: true, measurement: true, marketing: false, ... }
43
+ console.log('Latest consent state:', preferences);
44
+ }
45
+ ```
46
+
47
+ ### `onConsentChanged`
48
+
49
+ Called only after an explicit `saveConsents()` or `setConsent()` that actually changes the saved consent state. It never fires on store creation, hydration, automatic grants, unchanged saves, or `setCallback('onConsentChanged', ...)`.
50
+
51
+ ```tsx
52
+ onConsentChanged: ({
53
+ preferences,
54
+ previousPreferences,
55
+ allowedCategories,
56
+ deniedCategories,
57
+ previousAllowedCategories,
58
+ previousDeniedCategories,
59
+ }) => {
60
+ analytics.syncConsent({
61
+ allowedCategories,
62
+ deniedCategories,
63
+ previousAllowedCategories,
64
+ previousDeniedCategories,
65
+ });
66
+ }
67
+ ```
68
+
69
+ ### `onError`
70
+
71
+ Called when an error occurs during consent operations (e.g., API request failure). If no `onError` callback is provided, errors are logged to `console.error`.
72
+
73
+ ```tsx
74
+ onError: ({ error }) => {
75
+ // error: string describing what went wrong
76
+ Sentry.captureMessage(`Consent error: ${error}`);
77
+ }
78
+ ```
79
+
80
+ ### `onBeforeConsentRevocationReload`
81
+
82
+ Called synchronously before the page reloads due to consent revocation. This is your last chance to run cleanup before the reload. Keep this callback fast - avoid async operations.
83
+
84
+ ```tsx
85
+ onBeforeConsentRevocationReload: ({ preferences }) => {
86
+ // Flush any pending data
87
+ navigator.sendBeacon('/api/flush', JSON.stringify({ session: sessionId }));
88
+ }
89
+ ```
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Headless
3
+ description: Reference page for headless.
4
+ group: reference
5
+ ---
6
+ c15t's headless mode means using the hooks (`useConsentManager`, `useTranslations`, etc.) without any pre-built UI components. This gives you complete control over the consent experience.
7
+
8
+ Before you go headless, walk the customization ladder in order:
9
+
10
+ 1. **Pre-built components** - Use provider options, component props, tokens, slots, and `theme.consentActions`
11
+ 2. **Compound components** - Rearrange c15t primitives when the markup order must change
12
+ 3. **`noStyle`** - Keep c15t structure but replace its styling
13
+ 4. **Headless** - Use only hooks and build the entire UI yourself
14
+
15
+ ## When to Go Headless
16
+
17
+ Go headless when:
18
+
19
+ * Your design system requires complete control over markup
20
+ * You need a consent flow that doesn't fit the banner/dialog pattern
21
+ * You want to embed consent choices inline rather than as overlays
22
+
23
+ Use a lower-power tool instead when:
24
+
25
+ * The component structure works but the styling doesn't -> use tokens, slots, or `noStyle`
26
+ * You only need to rearrange existing c15t parts -> use compound components
27
+ * You want to change copy -> use `ConsentManagerProvider.options.i18n`
28
+ * You only need to restyle stock actions -> use `theme.consentActions`
29
+
30
+ > ⚠️ **Warning:**
31
+ > Headless mode is not the first answer for pure theming. If you are still trying to debug why a banner footer color did not change, stay in the styling system and verify the token-to-component mapping before you rebuild the UI.
@@ -0,0 +1,65 @@
1
+ ---
2
+ title: Iframe Blocking
3
+ description: Reference page for iframe blocking.
4
+ group: reference
5
+ ---
6
+ Embedded iframes from third parties (YouTube, Google Maps, social media widgets) can set cookies and track users without their consent. c15t provides two approaches to gate iframes behind consent:
7
+
8
+ 1. **`<Frame>` component** - A React component that conditionally renders children based on consent
9
+ 2. **HTML `data-category` attribute** - For raw `<iframe>` elements outside of React
10
+
11
+ ### Custom Placeholder
12
+
13
+ Replace the default placeholder with your own UI:
14
+
15
+ ```tsx
16
+ <Frame
17
+ category="marketing"
18
+ placeholder={
19
+ <div className="flex items-center justify-center h-64 bg-gray-100 rounded">
20
+ <p>Enable marketing cookies to watch this video.</p>
21
+ </div>
22
+ }
23
+ >
24
+ <iframe src="https://www.youtube.com/embed/..." />
25
+ </Frame>
26
+ ```
27
+
28
+ ### Compound Components
29
+
30
+ Build custom placeholder layouts using compound components:
31
+
32
+ ```tsx
33
+ <Frame.Root category="marketing">
34
+ <Frame.Title category="marketing" />
35
+ <Frame.Button category="marketing" />
36
+ </Frame.Root>
37
+ ```
38
+
39
+ ## HTML Attribute Approach
40
+
41
+ For iframes outside of React (e.g., CMS content, server-rendered HTML), add `data-category` and use `data-src` instead of `src`:
42
+
43
+ ```html
44
+ <iframe
45
+ data-src="https://www.youtube.com/embed/dQw4w9WgXcQ"
46
+ data-category="marketing"
47
+ width="560"
48
+ height="315"
49
+ ></iframe>
50
+ ```
51
+
52
+ When consent for the specified category is granted, c15t automatically swaps `data-src` to `src`, loading the iframe. When consent is revoked, `src` is moved back to `data-src`.
53
+
54
+ ### Dynamic Iframes
55
+
56
+ c15t uses a `MutationObserver` to watch for dynamically added iframes. Any iframe with `data-category` added to the DOM after initialization is automatically processed.
57
+
58
+ ## API Reference
59
+
60
+ |Property|Value|
61
+ |:--|:--|
62
+ |Type Name|\`FrameProps\`|
63
+ |Source Path|\`./packages/react/src/components/frame/types.ts\`|
64
+
65
+ \*ExtractedTypeTable: Could not extract "FrameProps" from "./packages/react/src/components/frame/types.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
@@ -0,0 +1,123 @@
1
+ ---
2
+ title: Internationalization
3
+ description: Reference page for internationalization.
4
+ group: reference
5
+ ---
6
+ c15t ships with built-in translations for 30+ languages via the `@c15t/translations` package. Language detection happens automatically based on the browser's language preference, and you can override or extend translations for any language.
7
+
8
+ In c15t v2, the preferred config shape is `i18n` with `locale`, `detectBrowserLanguage`, and `messages`.
9
+
10
+ There are two ways c15t can load translations: client-side or server-side.
11
+
12
+ |Server-side|Client-side|
13
+ |--|--|
14
+ |The best way to reduce bundle size and improve performance. We can detect the user's language based on the browser's language settings, allowing for the most accurate translations. By default, when using a [inth.com](https://inth.com) hosted instance, [these languages](https://github.com/c15t/c15t/tree/main/packages/translations/src/translations) are supported.|Bundled with the application allowing for multiple languages to be supported without the need for a backend. The more translations you have, the larger the bundle size will be, which may impact the performance of your application.|
15
+
16
+ ## Translation Package Imports
17
+
18
+ Use the import path that matches your use case:
19
+
20
+ * `@c15t/translations`: types, utilities, and `enTranslations` only (smallest client bundle)
21
+ * `@c15t/translations/en`: English-only translation object
22
+ * `@c15t/translations/all`: full `baseTranslations` map for all bundled locales
23
+
24
+ If you bundle translations client-side and need multiple languages, import from `@c15t/translations/all` explicitly:
25
+
26
+ ```tsx
27
+ import { baseTranslations } from '@c15t/translations/all';
28
+
29
+ const translations = {
30
+ en: baseTranslations.en,
31
+ de: baseTranslations.de,
32
+ fr: baseTranslations.fr,
33
+ };
34
+ ```
35
+
36
+ ## Translation Sections
37
+
38
+ The `Translations` object is organized into sections:
39
+
40
+ |Section|Controls|
41
+ |--|--|
42
+ |`common`|Shared button labels: acceptAll, rejectAll, customize, save|
43
+ |`cookieBanner`|Banner title and description|
44
+ |`consentManagerDialog`|Dialog title and description|
45
+ |`consentTypes`|Per-category title and description (keyed by AllConsentNames)|
46
+ |`frame`|Frame placeholder title, button, loading, and error text (title and button support `{category}`)|
47
+ |`legalLinks`|Privacy policy, cookie policy, terms of service link text|
48
+ |`iab`|IAB TCF banner, preference center, vendor list translations|
49
+
50
+ ## Automatic Language Detection
51
+
52
+ By default, c15t detects the browser's language (`navigator.language`) and selects the closest matching translation. If custom `messages` are configured, fallback stays within your configured languages before using `locale` (or `'en'`) as the preferred fallback language.
53
+
54
+ When backend policy packs use `i18n.messageProfile`, the active language pool comes only from that resolved profile.
55
+
56
+ Example: if your Europe profile defines `en`, `fr`, and `de`, and your default profile defines `en`, `es`, and `pt`, a Europe visitor can resolve to `en`, `fr`, or `de`, but not `es`, `pt`, or `zh`.
57
+
58
+ Use profile-local `fallbackLanguage` inside backend `i18n.messages` to choose which configured language a policy profile should fall back to when the browser asks for an unsupported locale.
59
+
60
+ Disable auto-detection to always use `locale`:
61
+
62
+ ```tsx
63
+ i18n: {
64
+ locale: 'de',
65
+ detectBrowserLanguage: false,
66
+ messages: { ... },
67
+ }
68
+ ```
69
+
70
+ If you need a policy to always use one specific language regardless of browser preference, set `policy.i18n.language` on the backend policy pack.
71
+
72
+ ## Custom Consent Type Labels
73
+
74
+ Override the title and description for individual consent categories. Frame
75
+ placeholders use that title anywhere their message contains `{category}`, so
76
+ the title and action stay consistent:
77
+
78
+ ```tsx
79
+ i18n: {
80
+ messages: {
81
+ en: {
82
+ consentTypes: {
83
+ measurement: {
84
+ title: 'Analytics & Performance',
85
+ description: 'Help us understand how visitors interact with our site.',
86
+ },
87
+ marketing: {
88
+ title: 'Advertising',
89
+ description: 'Used to deliver relevant ads and measure campaign effectiveness.',
90
+ },
91
+ },
92
+ frame: {
93
+ title: 'Allow {category} consent to view this content.',
94
+ actionButton: 'Enable {category} consent',
95
+ loading: 'Loading content…',
96
+ error: 'This content could not be loaded.',
97
+ },
98
+ },
99
+ },
100
+ }
101
+ ```
102
+
103
+ ## Legacy `translations` Compatibility
104
+
105
+ The legacy syntax is still supported in 2.0 for RC compatibility:
106
+
107
+ ```tsx
108
+ // Legacy (still supported)
109
+ translations: {
110
+ defaultLanguage: 'en',
111
+ disableAutoLanguageSwitch: true,
112
+ translations: { ... },
113
+ }
114
+
115
+ // Preferred in v2
116
+ i18n: {
117
+ locale: 'en',
118
+ detectBrowserLanguage: false,
119
+ messages: { ... },
120
+ }
121
+ ```
122
+
123
+ If both are provided, `i18n` takes precedence.
@@ -0,0 +1,72 @@
1
+ ---
2
+ title: Network Blocker
3
+ description: Reference page for network blocker.
4
+ group: reference
5
+ ---
6
+ The network blocker intercepts outgoing `fetch` and `XMLHttpRequest` calls and blocks them based on consent state and domain rules. This catches tracking requests that happen outside of script loading - for example, beacon calls, API requests to analytics endpoints, or pixel fires from already-loaded scripts.
7
+
8
+ ## Rule Matching
9
+
10
+ Rules match requests using three criteria:
11
+
12
+ ### Domain matching
13
+
14
+ The `domain` field matches the request hostname. Subdomains are automatically included - a rule for `google-analytics.com` also matches `www.google-analytics.com` and `stats.google-analytics.com`.
15
+
16
+ ### Path matching
17
+
18
+ The optional `pathIncludes` field requires the request URL path to contain the specified substring. This lets you target specific endpoints without blocking the entire domain.
19
+
20
+ ### Method matching
21
+
22
+ The optional `methods` array restricts the rule to specific HTTP methods. If omitted, the rule applies to all methods.
23
+
24
+ ## Consent Conditions
25
+
26
+ Like the script loader, `category` accepts a `HasCondition`:
27
+
28
+ ```tsx
29
+ // Simple
30
+ { category: 'measurement' }
31
+
32
+ // Must have both
33
+ { category: { and: ['measurement', 'marketing'] } }
34
+
35
+ // Must have either
36
+ { category: { or: ['measurement', 'marketing'] } }
37
+ ```
38
+
39
+ ## Monitoring Blocked Requests
40
+
41
+ ### Console logging
42
+
43
+ Blocked requests are logged to the console by default. Disable with `logBlockedRequests: false`.
44
+
45
+ ### Callback
46
+
47
+ Use `onRequestBlocked` to handle blocked requests programmatically:
48
+
49
+ ```tsx
50
+ networkBlocker: {
51
+ rules: [...],
52
+ onRequestBlocked: ({ method, url, rule }) => {
53
+ console.log(`Blocked ${method} ${url} (rule: ${rule?.id})`);
54
+ },
55
+ }
56
+ ```
57
+
58
+ ## API Reference
59
+
60
+ |Property|Value|
61
+ |:--|:--|
62
+ |Type Name|\`NetworkBlockerRule\`|
63
+ |Source Path|\`./packages/core/src/libs/network-blocker/types.ts\`|
64
+
65
+ \*ExtractedTypeTable: Could not extract "NetworkBlockerRule" from "./packages/core/src/libs/network-blocker/types.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
66
+
67
+ |Property|Value|
68
+ |:--|:--|
69
+ |Type Name|\`NetworkBlockerConfig\`|
70
+ |Source Path|\`./packages/core/src/libs/network-blocker/types.ts\`|
71
+
72
+ \*ExtractedTypeTable: Could not extract "NetworkBlockerConfig" from "./packages/core/src/libs/network-blocker/types.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Optimization
3
+ description: Reference page for optimization.
4
+ group: reference
5
+ ---
6
+ Use this guide when you care about banner visibility speed, route static-ness, and reducing backend round-trip cost.
7
+
8
+ Why this helps:
9
+
10
+ * Same-origin requests avoid extra DNS/TLS setup in many deployments
11
+ * Ad blockers are less likely to block your init endpoint
12
+ * You can change backend infrastructure without touching client code
13
+
14
+ In production benchmarks with a same-origin rewrite, prefetching strategies show measurable improvement over client-only init:
15
+
16
+ |Strategy|Scripts loaded|Data request starts|Banner visible|
17
+ |--|--|--|--|
18
+ |Client-only (no prefetch)|baseline|baseline|baseline|
19
+ |Browser prefetch|\~1.3x faster|\~2.6x earlier|\~1.25x faster|
20
+ |Server prefetch|\~2x faster|before page loads|\~1.9x faster|
21
+
22
+ ## Keep The Provider Mounted Across Navigation
23
+
24
+ Mount the consent provider at the app root so route transitions do not remount it.
25
+
26
+ Why this helps:
27
+
28
+ * Avoids re-running init work on client-side navigation
29
+ * Prevents extra callback churn from remount cycles
30
+ * Keeps banner/dialog state stable between route transitions
31
+
32
+ ## Animation Performance
33
+
34
+ The default motion tokens are tuned for speed-first product UI:
35
+
36
+ |Token|Duration|Used for|
37
+ |--|--|--|
38
+ |`fast`|80ms|Banner slide + overlay, card scale, button hover, widget entry/exit|
39
+ |`normal`|150ms|Accordion, switch toggle|
40
+ |`slow`|200ms|Dialog trigger snap, tab indicator|
41
+
42
+ These defaults follow the principle that product UI should be fast and purposeful — animations exist for spatial continuity, not decoration. In benchmarks, animation duration contributes a constant floor to "data fetched → banner visible" timing. The default tokens sit at the lower end of standard UI ranges (80-200ms) to minimize that floor.
43
+
44
+ If you must use a cross-origin backend URL, add preconnect so the browser starts DNS/TLS early: