@c15t/react 2.0.0-rc.9 → 2.0.2

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 (59) hide show
  1. package/README.md +25 -20
  2. package/dist/components/consent-banner/consent-banner.cjs +1 -1
  3. package/dist/components/consent-banner/consent-banner.js +1 -1
  4. package/dist/components/consent-dialog/atoms/card.cjs +1 -1
  5. package/dist/components/consent-dialog/atoms/card.js +1 -1
  6. package/dist/components/consent-dialog/atoms/overlay.cjs +1 -1
  7. package/dist/components/consent-dialog/atoms/overlay.js +1 -1
  8. package/dist/components/consent-widget/atoms/root.cjs +1 -1
  9. package/dist/components/consent-widget/atoms/root.js +1 -1
  10. package/dist/components/consent-widget/consent-widget.cjs +1 -1
  11. package/dist/components/consent-widget/consent-widget.js +1 -1
  12. package/dist/components/iab-consent-banner/iab-consent-banner.cjs +1 -1
  13. package/dist/components/iab-consent-banner/iab-consent-banner.js +1 -1
  14. package/dist/components/iab-consent-dialog/iab-consent-dialog.cjs +1 -1
  15. package/dist/components/iab-consent-dialog/iab-consent-dialog.js +1 -1
  16. package/dist/components/shared/ui/branding.cjs +1 -1
  17. package/dist/components/shared/ui/branding.js +1 -1
  18. package/dist/hooks/index.cjs +1 -1
  19. package/dist/iab/styles.tw3.css +54 -11
  20. package/dist/index.cjs +1 -1
  21. package/dist/styles.tw3.css +70 -10
  22. package/dist/version.cjs +1 -1
  23. package/dist/version.js +1 -1
  24. package/dist-types/components/consent-dialog/atoms/card.d.ts +1 -0
  25. package/dist-types/components/consent-dialog/atoms/overlay.d.ts +8 -16
  26. package/dist-types/components/consent-dialog/index.d.ts +2 -1
  27. package/dist-types/components/consent-widget/atoms/root.d.ts +0 -5
  28. package/dist-types/components/shared/ui/branding.d.ts +5 -1
  29. package/dist-types/components/shared/ui/logo.d.ts +10 -0
  30. package/dist-types/types/consent-manager.d.ts +2 -2
  31. package/dist-types/version.d.ts +1 -1
  32. package/docs/ai-agents.md +111 -0
  33. package/docs/building-headless-components.md +118 -16
  34. package/docs/components/consent-banner.md +1 -30
  35. package/docs/components/consent-dialog.md +4 -3
  36. package/docs/components/consent-manager-provider.md +13 -13
  37. package/docs/components/consent-widget.md +1 -28
  38. package/docs/components/dev-tools.md +33 -0
  39. package/docs/concepts/client-modes.md +1 -1
  40. package/docs/concepts/policy-packs.md +1 -1
  41. package/docs/hooks/use-consent-manager/overview.md +18 -2
  42. package/docs/iab/consent-banner.md +8 -6
  43. package/docs/iab/consent-dialog.md +8 -6
  44. package/docs/iab/overview.md +13 -12
  45. package/docs/iab/use-gvl-data.md +11 -199
  46. package/docs/internationalization.md +1 -1
  47. package/docs/optimization.md +35 -1
  48. package/docs/policy-packs.md +1 -1
  49. package/docs/quickstart.md +12 -9
  50. package/docs/styling/color-scheme.md +1 -1
  51. package/docs/styling/css-variables.md +1 -1
  52. package/docs/styling/overview.md +11 -4
  53. package/docs/styling/slots.md +7 -3
  54. package/docs/styling/tailwind.md +5 -1
  55. package/docs/styling/tokens.md +3 -1
  56. package/iab/styles.tw3.css +1 -0
  57. package/package.json +28 -15
  58. package/readme.json +4 -4
  59. package/styles.tw3.css +1 -0
@@ -15,7 +15,7 @@ c15t supports three client modes that determine how consent data is stored and s
15
15
 
16
16
  ## Hosted Mode (Recommended)
17
17
 
18
- The default mode. Connects to a c15t backend for full consent lifecycle management. We recommend using [consent.io](https://consent.io) for a fully managed experience, but you can [self-host](/docs/self-host) as well.
18
+ The default mode. Connects to a c15t backend for full consent lifecycle management. We recommend using [inth.com](https://inth.com) for a fully managed experience, but you can [self-host](/docs/self-host) as well.
19
19
 
20
20
  > ℹ️ **Info:**
21
21
  > mode: 'hosted' is the preferred value. The legacy alias mode: 'c15t' is still supported for backward compatibility.
@@ -8,7 +8,7 @@ A policy pack is an ordered array of policies. Each policy targets a region or c
8
8
 
9
9
  There are three ways to configure policy packs:
10
10
 
11
- 1. **consent.io (recommended)** — use [consent.io](https://consent.io) as your hosted backend. Configure packs visually in the dashboard or via API — no code changes required. Works with any frontend, including static sites.
11
+ 1. **inth.com (recommended)** — use [inth.com](https://inth.com) as your hosted backend. Configure packs visually in the dashboard or via API — no code changes required. Works with any frontend, including static sites.
12
12
  2. **Self-hosted backend** — define packs in code via `policyPacks` and resolve them from real request geo data. Full control over policy logic and storage.
13
13
  3. **Offline fallback** — pass the same policy shapes to the frontend via `offlinePolicy.policyPacks`. Use this mainly for local development, demos, deterministic testing, or resilience when the backend is temporarily unreachable. If you omit `offlinePolicy.policyPacks`, c15t falls back to a synthetic worldwide opt-in banner instead of no-banner mode.
14
14
 
@@ -87,7 +87,7 @@ Information about when and how consent was given
87
87
  |:--|:--|:--|:--|:--:|
88
88
  |time|number|The epoch timestamp of when the consent was recorded|-|✅ Required|
89
89
  |subjectId|string \|undefined|The client-generated subject ID in sub\_xxx format|-|Optional|
90
- |id|string \|undefined|Configuration for the legal links @remarks Legal links can display across different parts of the consent manager such as the consent banner & dialog.|-|Optional|
90
+ |id|string \|undefined|Effective GPC signal used for the request.|-|Optional|
91
91
  |externalId|string \|undefined|The external user ID linked to this subject|-|Optional|
92
92
  |materialPolicyFingerprint|string \|undefined|Material fingerprint of the active policy when this consent was accepted.|-|Optional|
93
93
  |identityProvider|string \|undefined|The identity provider that provided the external ID|-|Optional|
@@ -189,6 +189,7 @@ IAB TCF 2.3 state and actions (null when not configured or not in IAB mode).
189
189
  |setOverrides|Object \|undefined \|null|Sets the overrides for the consent manager. Automatically attempts to fetch the consent manager again with the new overrides.|-|✅ Required|
190
190
  |setLanguage|Object \|undefined \|null|Set the language override for the consent manager. This will override the language detected from the browser and re-fetch the consent banner information.|-|✅ Required|
191
191
  |identifyUser|Object|Identifies the user by setting the external ID.|-|✅ Required|
192
+ |unstable\_acceptPolicyConsent|Object \|undefined|Writes a policy-based consent such as terms and conditions.|-|✅ Required|
192
193
  |setSelectedConsent|(name: AllConsentNames, value: boolean) => void|Updates the selected consent state for a specific consent type.|-|✅ Required|
193
194
  |saveConsents|Object \|undefined|Saves the user's consent preferences.|-|✅ Required|
194
195
  |setConsent|(name: AllConsentNames, value: boolean) => void|Updates the consent state for a specific consent type & automatically save the consent.|-|✅ Required|
@@ -246,6 +247,21 @@ Identifies the user by setting the external ID.
246
247
  |id|string|Usually your own internal ID for the user from your auth provider|-|✅ Required|
247
248
  |identityProvider|string \|undefined|The identity provider of the user. Usually the name of the identity provider e.g. 'clerk', 'auth0', 'custom', etc.|-|Optional|
248
249
 
250
+ #### `unstable_acceptPolicyConsent`
251
+
252
+ Writes a policy-based consent such as terms and conditions.
253
+
254
+ |Property|Type|Description|Default|Required|
255
+ |:--|:--|:--|:--|:--:|
256
+ |type|Object|-|-|✅ Required|
257
+ |domain|string \|undefined|-|-|Optional|
258
+ |givenAt|number \|undefined|-|-|Optional|
259
+ |metadata|Record\<string, unknown> \|undefined|-|-|Optional|
260
+ |preferences|Record\<string, boolean> \|undefined|-|-|Optional|
261
+ |uiSource|string \|undefined|-|-|Optional|
262
+ |externalId|string \|undefined|-|-|Optional|
263
+ |identityProvider|string \|undefined|-|-|Optional|
264
+
249
265
  #### `subscribeToConsentChanges`
250
266
 
251
267
  Subscribes to change-only consent saves.
@@ -344,7 +360,7 @@ function LoginForm() {
344
360
  ```
345
361
 
346
362
  > ℹ️ **Info:**
347
- > identifyUser sends the user data to the c15t backend. It only works in 'c15t' mode — in 'offline' mode the call is a no-op.
363
+ > identifyUser sends the user data to the c15t backend. It works in hosted mode, including the legacy alias mode: 'c15t'. In mode: 'offline', the call is a no-op.
348
364
 
349
365
  ## Key Types
350
366
 
@@ -2,8 +2,8 @@
2
2
  title: IABConsentBanner
3
3
  description: An IAB TCF 2.3 compliant consent banner that displays partner count, purpose summaries, and legitimate interest notices.
4
4
  ---
5
- > **Error:**
6
- > c15t is not yet IAB certified. The IAB TCF components are under active development and should not be used in production. APIs and behavior may change before certification is achieved.
5
+ > ℹ️ **Info:**
6
+ > c15t's IAB TCF support can be used in production. Use Inth for a hosted, IAB TCF-certified CMP setup with a managed CMP ID, or register your own CMP with IAB Europe and configure your own CMP ID.
7
7
 
8
8
  `IABConsentBanner` is a pre-built consent banner that follows the [IAB Transparency & Consent Framework (TCF) 2.3](https://iabeurope.eu/tcf-2-0/) specification. It renders when the consent model is set to `'iab'` and includes required disclosures like partner count, purpose summaries, and legitimate interest notices.
9
9
 
@@ -19,6 +19,7 @@ Use this component instead of `ConsentBanner` when you need IAB TCF compliance f
19
19
 
20
20
  ```tsx
21
21
  import { type ReactNode } from 'react';
22
+ import { iab } from '@c15t/iab';
22
23
  import { ConsentManagerProvider } from '@c15t/react';
23
24
  import { IABConsentBanner, IABConsentDialog } from '@c15t/react/iab';
24
25
 
@@ -28,11 +29,12 @@ export default function ConsentManager({ children }: { children: ReactNode }) {
28
29
  options={{
29
30
  mode: 'hosted',
30
31
  backendURL: 'https://your-instance.c15t.dev',
31
- iab: {
32
- enabled: true,
33
- cmpId: 123,
32
+ iab: iab({
34
33
  vendors: [1, 2, 10, 25],
35
- },
34
+ // cmpId is automatically provided by the backend when using Inth.
35
+ // Only set this if you have your own CMP registration.
36
+ // cmpId: 123,
37
+ }),
36
38
  }}
37
39
  >
38
40
  <IABConsentBanner />
@@ -2,8 +2,8 @@
2
2
  title: IABConsentDialog
3
3
  description: An IAB TCF 2.3 compliant preference center with tabbed purpose and vendor management.
4
4
  ---
5
- > **Error:**
6
- > c15t is not yet IAB certified. The IAB TCF components are under active development and should not be used in production. APIs and behavior may change before certification is achieved.
5
+ > ℹ️ **Info:**
6
+ > c15t's IAB TCF support can be used in production. Use Inth for a hosted, IAB TCF-certified CMP setup with a managed CMP ID, or register your own CMP with IAB Europe and configure your own CMP ID.
7
7
 
8
8
  `IABConsentDialog` is an IAB TCF 2.3 compliant consent dialog that provides a tabbed interface for managing purpose consent and vendor preferences. It includes purpose grouping via stacks, individual purpose/vendor toggles, special purpose and feature disclosures, and legitimate interest handling.
9
9
 
@@ -13,6 +13,7 @@ Pair it with `IABConsentBanner` inside the provider:
13
13
 
14
14
  ```tsx
15
15
  import { type ReactNode } from 'react';
16
+ import { iab } from '@c15t/iab';
16
17
  import { ConsentManagerProvider } from '@c15t/react';
17
18
  import { IABConsentBanner, IABConsentDialog } from '@c15t/react/iab';
18
19
 
@@ -22,11 +23,12 @@ export default function ConsentManager({ children }: { children: ReactNode }) {
22
23
  options={{
23
24
  mode: 'hosted',
24
25
  backendURL: 'https://your-instance.c15t.dev',
25
- iab: {
26
- enabled: true,
27
- cmpId: 123,
26
+ iab: iab({
28
27
  vendors: [1, 2, 10, 25],
29
- },
28
+ // cmpId is automatically provided by the backend when using Inth.
29
+ // Only set this if you have your own CMP registration.
30
+ // cmpId: 123,
31
+ }),
30
32
  }}
31
33
  >
32
34
  <IABConsentBanner />
@@ -15,12 +15,12 @@ When your site participates in the IAB ecosystem (ad exchanges, SSPs, DSPs, DMPs
15
15
 
16
16
  ## CMP Registration
17
17
 
18
- [consent.io](https://consent.io) is pending validation as an IAB Europe-registered CMP for c15t. Once approved, when you use consent.io as your backend, the correct CMP ID will be automatically provided to your client via the `/init` endpoint — no client-side configuration needed.
18
+ [Inth](https://inth.com), c15t's hosted platform, is IAB TCF certified. When you use Inth as your backend with c15t's prebuilt IAB UI, the correct CMP ID is automatically provided to your client via the `/init` endpoint — no client-side configuration needed.
19
19
 
20
- If you self-host the c15t backend and have your own CMP registration with IAB Europe, you can configure your CMP ID on the backend via `advanced.iab.cmpId` or on the client via the `iab.cmpId` option. A valid (non-zero) CMP ID is required for IAB TCF compliance.
20
+ If you self-host the c15t backend or want to operate as your own CMP, register your own CMP with IAB Europe and configure your CMP ID on the backend via `advanced.iab.cmpId` or on the client via the `iab.cmpId` option. Registering your own CMP may also involve IAB Europe fees, so check IAB Europe's current CMP registration terms and pricing before choosing this route. A valid (non-zero) CMP ID is required for IAB TCF compliance.
21
21
 
22
22
  > ℹ️ **Info:**
23
- > If you heavily customize or build your own IAB banner or dialog (rather than using the default IABConsentBanner and IABConsentDialog components), you cannot use consent.io's CMP ID. You must register your own CMP with IAB Europe and use your own CMP ID.
23
+ > If you heavily customize or build your own IAB banner or dialog instead of using the default IABConsentBanner and IABConsentDialog components, you cannot use Inth's CMP ID. You must register your own CMP with IAB Europe and use your own CMP ID.
24
24
 
25
25
  ## How c15t Implements TCF
26
26
 
@@ -45,6 +45,7 @@ If you use the prebuilt styled IAB UI, import the IAB stylesheet alongside the b
45
45
 
46
46
  ```tsx
47
47
  import { type ReactNode } from 'react';
48
+ import { iab } from '@c15t/iab';
48
49
  import { ConsentManagerProvider } from '@c15t/react';
49
50
  import { IABConsentBanner, IABConsentDialog } from '@c15t/react/iab';
50
51
 
@@ -54,13 +55,12 @@ export default function ConsentManager({ children }: { children: ReactNode }) {
54
55
  options={{
55
56
  mode: 'hosted',
56
57
  backendURL: 'https://your-instance.c15t.dev',
57
- iab: {
58
- enabled: true,
58
+ iab: iab({
59
59
  vendors: [1, 2, 10, 25], // IAB vendor IDs you work with
60
- // cmpId is automatically provided by the backend (consent.io).
60
+ // cmpId is automatically provided by the backend (inth.com).
61
61
  // Only set this if you have your own CMP registration with IAB Europe.
62
62
  // cmpId: 123,
63
- },
63
+ }),
64
64
  }}
65
65
  >
66
66
  <IABConsentBanner />
@@ -73,14 +73,13 @@ export default function ConsentManager({ children }: { children: ReactNode }) {
73
73
 
74
74
  ## IAB Configuration Options
75
75
 
76
- The `iab` option on the provider accepts:
76
+ Configure IAB mode with `iab({ ... })` from `@c15t/iab`. The factory enables the addon and injects the runtime module automatically. The user-facing options are:
77
77
 
78
78
  |Option|Type|Description|
79
79
  |--|--|--|
80
- |`enabled`|`boolean`|Enable IAB TCF mode|
81
- |`cmpId`|`number`|CMP ID registered with IAB Europe. Automatically provided by the backend when using consent.io. Only set this if you have your own CMP registration.|
80
+ |`cmpId`|`number`|CMP ID registered with IAB Europe. Automatically provided by the backend when using Inth with the prebuilt IAB UI. Only set this if you have your own CMP registration.|
82
81
  |`vendors`|`number[]`|IAB vendor IDs that your site works with|
83
- |`nonIABVendors`|`NonIABVendor[]`|Custom vendors not in the IAB registry|
82
+ |`customVendors`|`NonIABVendor[]`|Custom vendors not in the IAB registry|
84
83
 
85
84
  ## Key Concepts
86
85
 
@@ -122,4 +121,6 @@ Each vendor in the GVL declares which purposes it uses, whether via consent or l
122
121
  |--|--|
123
122
  |[IABConsentBanner](/docs/frameworks/react/iab/consent-banner)|TCF-compliant banner with partner disclosure|
124
123
  |[IABConsentDialog](/docs/frameworks/react/iab/consent-dialog)|Tabbed preference center for purposes and vendors|
125
- |[useGVLData](/docs/frameworks/react/iab/use-gvl-data)|Hook for building custom IAB UI|
124
+
125
+ > ℹ️ **Info:**
126
+ > For lower-level custom IAB flows, use useHeadlessIABConsentUI() from @c15t/react/iab. useGVLData() is currently internal and is not part of the public package surface.
@@ -1,208 +1,20 @@
1
1
  ---
2
- title: useGVLData
3
- description: Hook to access processed Global Vendor List (GVL) data for building custom IAB TCF UI components.
2
+ title: useGVLData (Internal)
3
+ description: Status note for the internal GVL hook used by the built-in IAB dialog.
4
4
  ---
5
- > ❌ **Error:**
6
- > c15t is not yet IAB certified. The IAB TCF components are under active development and should not be used in production. APIs and behavior may change before certification is achieved.
7
-
8
- `useGVLData()` processes the raw IAB Global Vendor List (GVL) into a UI-friendly format. It handles purpose grouping into stacks, vendor mapping, special purpose/feature extraction, and loading state.
9
-
10
- Use this hook when building a custom IAB TCF UI instead of the pre-built `IABConsentDialog`.
11
-
12
- ```tsx
13
- import { useGVLData } from '@c15t/react/hooks';
14
-
15
- function CustomIABPreferences() {
16
- const { purposes, stacks, standalonePurposes, totalVendors, isLoading } = useGVLData();
17
-
18
- if (isLoading) return <p>Loading vendor data...</p>;
19
-
20
- return (
21
- <div>
22
- <p>{totalVendors} partners</p>
23
- {standalonePurposes.map((purpose) => (
24
- <div key={purpose.id}>
25
- <h3>{purpose.name}</h3>
26
- <p>{purpose.description}</p>
27
- <p>{purpose.vendors.length} vendors</p>
28
- </div>
29
- ))}
30
- </div>
31
- );
32
- }
33
- ```
34
-
35
5
  > ℹ️ **Info:**
36
- > Must be used within a ConsentManagerProvider with IAB mode enabled. Returns empty data if IAB is not configured.
37
-
38
- ## Return Value
39
-
40
- The hook returns a `GVLData` object:
41
-
42
- ### GVLData
43
-
44
- |Property|Type|Description|Default|Required|
45
- |:--|:--|:--|:--|:--:|
46
- |purposes|ProcessedPurpose|-|-|✅ Required|
47
- |specialPurposes|ProcessedPurpose|-|-|✅ Required|
48
- |specialFeatures|ProcessedSpecialFeature|-|-|✅ Required|
49
- |features|ProcessedFeature|-|-|✅ Required|
50
- |stacks|ProcessedStack|-|-|✅ Required|
51
- |standalonePurposes|ProcessedPurpose|-|-|✅ Required|
52
- |totalVendors|number|-|-|✅ Required|
53
- |isLoading|boolean|-|-|✅ Required|
54
-
55
- #### `purposes` ProcessedPurpose
56
-
57
- |Property|Type|Description|Default|Required|
58
- |:--|:--|:--|:--|:--:|
59
- |id|number|-|-|✅ Required|
60
- |name|string|-|-|✅ Required|
61
- |description|string|-|-|✅ Required|
62
- |descriptionLegal|string \|undefined|-|-|Optional|
63
- |illustrations|string\[]|-|-|✅ Required|
64
- |vendors|ProcessedVendor|-|-|✅ Required|
65
- |isSpecialPurpose|boolean \|undefined|-|-|Optional|
66
-
67
- #### `specialPurposes` ProcessedPurpose
68
-
69
- |Property|Type|Description|Default|Required|
70
- |:--|:--|:--|:--|:--:|
71
- |id|number|-|-|✅ Required|
72
- |name|string|-|-|✅ Required|
73
- |description|string|-|-|✅ Required|
74
- |descriptionLegal|string \|undefined|-|-|Optional|
75
- |illustrations|string\[]|-|-|✅ Required|
76
- |vendors|ProcessedVendor|-|-|✅ Required|
77
- |isSpecialPurpose|boolean \|undefined|-|-|Optional|
78
-
79
- #### `specialFeatures` ProcessedSpecialFeature
6
+ > c15t's IAB TCF support can be used in production through Inth or with your own registered CMP ID. useGVLData() is different: it remains an internal hook and is not part of the supported public API.
80
7
 
81
- |Property|Type|Description|Default|Required|
82
- |:--|:--|:--|:--|:--:|
83
- |id|number|-|-|✅ Required|
84
- |name|string|-|-|✅ Required|
85
- |description|string|-|-|✅ Required|
86
- |descriptionLegal|string \|undefined|-|-|Optional|
87
- |illustrations|string\[]|-|-|✅ Required|
88
- |vendors|ProcessedVendor|-|-|✅ Required|
8
+ `useGVLData()` currently powers the built-in `IABConsentDialog`, but it is **not part of the public package surface**.
89
9
 
90
- #### `features` ProcessedFeature
10
+ Older docs showed it as a public hook. That is no longer accurate.
91
11
 
92
- |Property|Type|Description|Default|Required|
93
- |:--|:--|:--|:--|:--:|
94
- |id|number|-|-|✅ Required|
95
- |name|string|-|-|✅ Required|
96
- |description|string|-|-|✅ Required|
97
- |descriptionLegal|string \|undefined|-|-|Optional|
98
- |illustrations|string\[]|-|-|✅ Required|
99
- |vendors|ProcessedVendor|-|-|✅ Required|
12
+ If you need supported customization points today:
100
13
 
101
- #### `stacks` ProcessedStack
14
+ * Use `IABConsentBanner` and `IABConsentDialog` from `@c15t/react/iab` for the supported prebuilt UI
15
+ * Use `useHeadlessIABConsentUI()` from `@c15t/react/iab` when you need lower-level control over banner/dialog state and actions
102
16
 
103
- |Property|Type|Description|Default|Required|
104
- |:--|:--|:--|:--|:--:|
105
- |id|number|-|-|✅ Required|
106
- |name|string|-|-|✅ Required|
107
- |description|string|-|-|✅ Required|
108
- |purposes|ProcessedPurpose|-|-|✅ Required|
109
-
110
- #### `standalonePurposes` ProcessedPurpose
111
-
112
- |Property|Type|Description|Default|Required|
113
- |:--|:--|:--|:--|:--:|
114
- |id|number|-|-|✅ Required|
115
- |name|string|-|-|✅ Required|
116
- |description|string|-|-|✅ Required|
117
- |descriptionLegal|string \|undefined|-|-|Optional|
118
- |illustrations|string\[]|-|-|✅ Required|
119
- |vendors|ProcessedVendor|-|-|✅ Required|
120
- |isSpecialPurpose|boolean \|undefined|-|-|Optional|
121
-
122
- ## Types
123
-
124
- ### ProcessedPurpose
125
-
126
- |Property|Type|Description|Default|Required|
127
- |:--|:--|:--|:--|:--:|
128
- |id|number|-|-|✅ Required|
129
- |name|string|-|-|✅ Required|
130
- |description|string|-|-|✅ Required|
131
- |descriptionLegal|string \|undefined|-|-|Optional|
132
- |illustrations|string\[]|-|-|✅ Required|
133
- |vendors|ProcessedVendor|-|-|✅ Required|
134
- |isSpecialPurpose|boolean \|undefined|-|-|Optional|
135
-
136
- #### `vendors` ProcessedVendor
137
-
138
- |Property|Type|Description|Default|Required|
139
- |:--|:--|:--|:--|:--:|
140
- |id|VendorId|-|-|✅ Required|
141
- |name|string|-|-|✅ Required|
142
- |policyUrl|string|-|-|✅ Required|
143
- |usesNonCookieAccess|boolean|-|-|✅ Required|
144
- |deviceStorageDisclosureUrl|string \|null|-|-|✅ Required|
145
- |usesCookies|boolean|-|-|✅ Required|
146
- |cookieMaxAgeSeconds|number \|null|-|-|✅ Required|
147
- |cookieRefresh|boolean \|undefined|-|-|Optional|
148
- |specialPurposes|number\[]|-|-|✅ Required|
149
- |specialFeatures|number\[]|-|-|✅ Required|
150
- |features|number\[]|-|-|✅ Required|
151
- |purposes|number\[]|-|-|✅ Required|
152
- |legIntPurposes|number\[]|-|-|✅ Required|
153
- |legitimateInterestUrl|string \|null \|undefined|-|-|Optional|
154
- |isCustom|boolean \|undefined|-|-|Optional|
155
- |usesLegitimateInterest|boolean \|undefined|-|-|Optional|
156
- |dataRetention|Object \|undefined|-|-|Optional|
157
- |dataDeclaration|number\[] \|undefined|-|-|Optional|
158
-
159
- ### ProcessedVendor
160
-
161
- |Property|Type|Description|Default|Required|
162
- |:--|:--|:--|:--|:--:|
163
- |id|VendorId|-|-|✅ Required|
164
- |name|string|-|-|✅ Required|
165
- |policyUrl|string|-|-|✅ Required|
166
- |usesNonCookieAccess|boolean|-|-|✅ Required|
167
- |deviceStorageDisclosureUrl|string \|null|-|-|✅ Required|
168
- |usesCookies|boolean|-|-|✅ Required|
169
- |cookieMaxAgeSeconds|number \|null|-|-|✅ Required|
170
- |cookieRefresh|boolean \|undefined|-|-|Optional|
171
- |specialPurposes|number\[]|-|-|✅ Required|
172
- |specialFeatures|number\[]|-|-|✅ Required|
173
- |features|number\[]|-|-|✅ Required|
174
- |purposes|number\[]|-|-|✅ Required|
175
- |legIntPurposes|number\[]|-|-|✅ Required|
176
- |legitimateInterestUrl|string \|null \|undefined|-|-|Optional|
177
- |isCustom|boolean \|undefined|-|-|Optional|
178
- |usesLegitimateInterest|boolean \|undefined|-|-|Optional|
179
- |dataRetention|Object \|undefined|-|-|Optional|
180
- |dataDeclaration|number\[] \|undefined|-|-|Optional|
181
-
182
- #### `dataRetention`
183
-
184
- |Property|Type|Description|Default|Required|
185
- |:--|:--|:--|:--|:--:|
186
- |purposes|Record\<number, number> \|undefined|-|-|Optional|
187
- |specialPurposes|Record\<number, number> \|undefined|-|-|Optional|
188
- |stdRetention|number \|undefined|-|-|Optional|
189
-
190
- ### ProcessedStack
191
-
192
- |Property|Type|Description|Default|Required|
193
- |:--|:--|:--|:--|:--:|
194
- |id|number|-|-|✅ Required|
195
- |name|string|-|-|✅ Required|
196
- |description|string|-|-|✅ Required|
197
- |purposes|ProcessedPurpose|-|-|✅ Required|
198
-
199
- ### ProcessedSpecialFeature
17
+ > ℹ️ **Info:**
18
+ > Until useGVLData() is exported as public API, avoid importing it from deep internal paths. Those paths are not covered by semver guarantees and can change without notice.
200
19
 
201
- |Property|Type|Description|Default|Required|
202
- |:--|:--|:--|:--|:--:|
203
- |id|number|-|-|✅ Required|
204
- |name|string|-|-|✅ Required|
205
- |description|string|-|-|✅ Required|
206
- |descriptionLegal|string \|undefined|-|-|Optional|
207
- |illustrations|string\[]|-|-|✅ Required|
208
- |vendors|ProcessedVendor|-|-|✅ Required|
20
+ When a public GVL-focused hook becomes part of the supported API, this page should document that public surface instead of the internal dialog hook.
@@ -10,7 +10,7 @@ There are two ways c15t can load translations: client-side or server-side.
10
10
 
11
11
  |Server-side|Client-side|
12
12
  |--|--|
13
- |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 [consent.io](https://consent.io) 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.|
13
+ |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.|
14
14
 
15
15
  ## Basic Configuration
16
16
 
@@ -1,10 +1,25 @@
1
1
  ---
2
2
  title: Optimization
3
3
  description: Improve c15t startup performance in React with prefetching, proxy rewrites, and rendering tradeoffs.
4
- lastModified: 2026-03-17
4
+ lastModified: 2026-04-14
5
5
  ---
6
6
  Use this guide when you care about banner visibility speed, route static-ness, and reducing backend round-trip cost.
7
7
 
8
+ ## Start Here
9
+
10
+ Apply the optimizations in this order:
11
+
12
+ |Situation|Use|Why|Tradeoff|
13
+ |--|--|--|--|
14
+ |Any production app using hosted mode|Same-origin `/api/c15t` proxy|Lowers browser startup overhead and keeps the backend origin out of client config|Requires framework or platform proxy setup|
15
+ |Banner speed matters on cold loads|`buildPrefetchScript()`|Starts `/init` before your app hydrates|Still a browser-side fetch, not SSR|
16
+ |Your app navigates client-side|Keep the provider mounted at the app root|Avoids remounting and re-running init work|Requires provider placement discipline|
17
+ |You cannot proxy and must stay cross-origin|`<link rel="preconnect">`|Starts DNS/TLS work earlier|Smaller gain than same-origin proxying|
18
+ |You are using Next.js and want SSR or static-route-specific guidance|Next.js optimization docs|Covers `C15tPrefetch`, `fetchInitialData()`, and rendering tradeoffs|Next-specific|
19
+
20
+ > ℹ️ **Info:**
21
+ > Treat same-origin proxying as the baseline optimization. The others are situational layers you add when startup timing or route behavior justifies them.
22
+
8
23
  ## 1) Prefer Same-Origin Proxy
9
24
 
10
25
  Proxy c15t requests through your app server so the browser calls your own origin instead of a third-party domain.
@@ -23,6 +38,8 @@ Why this helps:
23
38
  * Ad blockers are less likely to block your init endpoint
24
39
  * You can change backend infrastructure without touching client code
25
40
 
41
+ If you can only do one optimization, do this one first.
42
+
26
43
  ## 2) Prefetch Init Data Early
27
44
 
28
45
  Use `buildPrefetchScript()` from the `c15t` core package to start the `/init` request before your app hydrates. Inject the script as early as possible in your HTML `<head>`.
@@ -35,6 +52,12 @@ In production benchmarks with a same-origin rewrite, prefetching strategies show
35
52
  |Browser prefetch|\~1.3x faster|\~2.6x earlier|\~1.25x faster|
36
53
  |Server prefetch|\~2x faster|before page loads|\~1.9x faster|
37
54
 
55
+ Use this when:
56
+
57
+ * The app is client-rendered
58
+ * You want a faster first banner without introducing SSR complexity
59
+ * You control the HTML template or document `<head>`
60
+
38
61
  ### Inline Script Prefetch
39
62
 
40
63
  ```tsx
@@ -88,6 +111,8 @@ Why this helps:
88
111
  * Prevents extra callback churn from remount cycles
89
112
  * Keeps banner/dialog state stable between route transitions
90
113
 
114
+ Mount `ConsentManagerProvider` as high in the tree as possible so route transitions do not recreate it.
115
+
91
116
  ## Animation Performance
92
117
 
93
118
  The default motion tokens are tuned for speed-first product UI:
@@ -104,6 +129,8 @@ To customize motion durations and easing, see [Styling](/docs/frameworks/react/s
104
129
 
105
130
  ## Reduce Network Overhead
106
131
 
132
+ If your browser must call a cross-origin backend URL directly, add `preconnect` so the browser can warm up the connection earlier. This is a fallback optimization when same-origin proxying is not possible.
133
+
107
134
  If you must use a cross-origin backend URL, add preconnect so the browser starts DNS/TLS early:
108
135
 
109
136
  ```tsx
@@ -111,3 +138,10 @@ If you must use a cross-origin backend URL, add preconnect so the browser starts
111
138
  <link rel="preconnect" href="https://your-instance.c15t.dev" crossOrigin="" />
112
139
  </head>
113
140
  ```
141
+
142
+ ## Next.js-Specific SSR And Static Routes
143
+
144
+ This page is intentionally React-generic. If you are using Next.js and need SSR or static-route-specific guidance:
145
+
146
+ * See [Next.js Optimization](/docs/frameworks/next/optimization) for the static-vs-dynamic decision guide
147
+ * See [Next.js Server-Side Data Fetching](/docs/frameworks/next/server-side) for `fetchInitialData()`
@@ -13,7 +13,7 @@ When a backend isn't available — local development, static previews, Storybook
13
13
 
14
14
  ## Hosted Mode (Recommended)
15
15
 
16
- When using consent.io or a self-hosted backend, the provider connects automatically. No policy configuration is needed on the frontend:
16
+ When using inth.com or a self-hosted backend, the provider connects automatically. No policy configuration is needed on the frontend:
17
17
 
18
18
  ```tsx
19
19
  <ConsentManagerProvider
@@ -17,10 +17,10 @@ availableIn:
17
17
 
18
18
  |Package manager|Command|
19
19
  |:--|:--|
20
- |npm|`npx @c15t/cli@rc`|
21
- |pnpm|`pnpm dlx @c15t/cli@rc`|
22
- |yarn|`yarn dlx @c15t/cli@rc`|
23
- |bun|`bunx @c15t/cli@rc`|
20
+ |npm|`npx @c15t/cli`|
21
+ |pnpm|`pnpm dlx @c15t/cli`|
22
+ |yarn|`yarn dlx @c15t/cli`|
23
+ |bun|`bunx @c15t/cli`|
24
24
 
25
25
  ## Manual Installation
26
26
 
@@ -39,7 +39,7 @@ availableIn:
39
39
  @import "@c15t/react/styles.css";
40
40
  ```
41
41
 
42
- Keeping the c15t stylesheet in your global CSS entrypoint makes layer and cascade order explicit. JS/TSX side-effect imports can load in a different order across framework and Tailwind tooling, which makes style regressions harder to debug.
42
+ Keeping the c15t stylesheet in your global CSS entrypoint makes layer and cascade order explicit. JS/TSX side-effect imports can load in a different order across framework and Tailwind tooling, which makes style regressions harder to debug.With Tailwind v4, keep c15t at the end of the top-level @import block so Fumadocs, tw-animate-css, and other preset imports do not override c15t theme tokens.
43
43
 
44
44
  > ℹ️ Info:
45
45
  >
@@ -107,6 +107,9 @@ availableIn:
107
107
 
108
108
  A consent banner appears at the bottom of the pageClicking "Customize" opens a dialog with toggles for each consent categoryAfter accepting or rejecting, the banner dismisses and your choice persists across page reloads
109
109
 
110
+ > ℹ️ **Info:**
111
+ > Want to improve startup performance? See Optimization for the decision guide, prefetch setup, and network tuning.
112
+
110
113
  ## Optional: Add DevTools
111
114
 
112
115
  Install DevTools only if you want a runtime inspector while building and debugging:
@@ -142,10 +145,10 @@ Install c15t agent skills to let AI agents help with styling, i18n, scripts & ot
142
145
 
143
146
  |Package manager|Command|
144
147
  |:--|:--|
145
- |npm|`npx @c15t/cli@rc skills`|
146
- |pnpm|`pnpm dlx @c15t/cli@rc skills`|
147
- |yarn|`yarn dlx @c15t/cli@rc skills`|
148
- |bun|`bunx @c15t/cli@rc skills`|
148
+ |npm|`npx @c15t/cli skills`|
149
+ |pnpm|`pnpm dlx @c15t/cli skills`|
150
+ |yarn|`yarn dlx @c15t/cli skills`|
151
+ |bun|`bunx @c15t/cli skills`|
149
152
 
150
153
  See [AI Agents](/docs/ai-agents) for bundled package docs and agent skills.
151
154
 
@@ -65,7 +65,7 @@ function ThemeToggle() {
65
65
 
66
66
  ## How Dark Mode Works
67
67
 
68
- When dark mode is active, c15t applies the `dark` token values as CSS variable overrides. Only tokens specified in `dark` are overridden - unset tokens fall back to the `colors` values.
68
+ When dark mode is active, c15t applies the `dark` token values as CSS variable overrides. Only tokens specified in `dark` are overridden - unset tokens fall back to the `colors` values. This also applies to `textOnPrimary`: if you omit it, c15t derives a readable foreground from the active `primary` color in that scheme.
69
69
 
70
70
  ```tsx
71
71
  const theme = {
@@ -18,7 +18,7 @@ Every theme token is converted to a `--c15t-*` CSS custom property at runtime. Y
18
18
  |--c15t-border-hover|string \|undefined|\`colors.borderHover\` (default: \`hsl(0, 0%, 85%)\`)|-|Optional|
19
19
  |--c15t-text|string \|undefined|\`colors.text\` (default: \`hsl(0, 0%, 10%)\`)|-|Optional|
20
20
  |--c15t-text-muted|string \|undefined|\`colors.textMuted\` (default: \`hsl(0, 0%, 40%)\`)|-|Optional|
21
- |--c15t-text-on-primary|string \|undefined|\`colors.textOnPrimary\` (default: \`hsl(0, 0%, 100%)\`)|-|Optional|
21
+ |--c15t-text-on-primary|string \|undefined|\`colors.textOnPrimary\` (auto-derived from \`colors.primary\` when omitted)|-|Optional|
22
22
  |--c15t-overlay|string \|undefined|\`colors.overlay\` (default: \`hsla(0, 0%, 0%, 0.5)\`)|-|Optional|
23
23
  |--c15t-switch-track|string \|undefined|\`colors.switchTrack\` (default: \`hsl(0, 0%, 85%)\`)|-|Optional|
24
24
  |--c15t-switch-track-active|string \|undefined|\`colors.switchTrackActive\` (default: \`hsl(228, 100%, 60%)\`)|-|Optional|