@c15t/nextjs 2.2.1 → 3.0.0-alpha.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 (221) hide show
  1. package/AGENTS.md +103 -142
  2. package/README.md +4 -4
  3. package/dist/api.js +1 -0
  4. package/dist/config.js +1 -0
  5. package/dist/devtools.js +2 -0
  6. package/dist/headers.js +1 -0
  7. package/dist/iab/styles.css +1 -1
  8. package/dist/iab/styles.tw3.css +27 -19
  9. package/dist/index.js +1 -1
  10. package/dist/middleware.js +1 -0
  11. package/dist/node-bridge.js +1 -0
  12. package/dist/pages.js +1 -0
  13. package/dist/proxy.js +1 -0
  14. package/dist/root.js +2 -0
  15. package/dist/server.js +1 -0
  16. package/dist/static.js +1 -0
  17. package/dist/styles.css +1 -1
  18. package/dist/styles.tw3.css +67 -29
  19. package/dist/version.js +1 -1
  20. package/dist-types/api.d.ts +88 -0
  21. package/dist-types/config.d.ts +110 -0
  22. package/dist-types/devtools.d.ts +1 -0
  23. package/dist-types/headers.d.ts +4 -0
  24. package/dist-types/index.d.ts +28 -10
  25. package/dist-types/middleware.d.ts +15 -0
  26. package/dist-types/node-bridge.d.ts +57 -0
  27. package/dist-types/pages.d.ts +88 -0
  28. package/dist-types/proxy.d.ts +34 -0
  29. package/dist-types/root.d.ts +92 -0
  30. package/dist-types/server.d.ts +164 -0
  31. package/dist-types/static.d.ts +42 -0
  32. package/dist-types/types.d.ts +5 -36
  33. package/dist-types/version.d.ts +1 -1
  34. package/docs/README.md +103 -142
  35. package/docs/assets/v3/brand-bar.png +0 -0
  36. package/docs/assets/v3/brand-card.png +0 -0
  37. package/docs/assets/v3/choice-wall.png +0 -0
  38. package/docs/assets/v3/mobile-card.png +0 -0
  39. package/docs/assets/v3/preferences.png +0 -0
  40. package/docs/customization/overview.md +45 -0
  41. package/docs/customization/recipes.md +79 -0
  42. package/docs/customization/slots.md +55 -0
  43. package/docs/customization/tokens.md +76 -0
  44. package/docs/customization/translations.md +49 -0
  45. package/docs/frameworks/next/api-reference/data-fetching.md +416 -0
  46. package/docs/frameworks/next/app-router.md +403 -0
  47. package/docs/frameworks/next/client-side.md +118 -0
  48. package/docs/frameworks/next/components/consent-banner.md +251 -211
  49. package/docs/frameworks/next/components/consent-dialog-link.md +96 -35
  50. package/docs/frameworks/next/components/consent-dialog-trigger.md +74 -149
  51. package/docs/frameworks/next/components/consent-dialog.md +189 -134
  52. package/docs/frameworks/next/components/consent-manager-provider.md +68 -318
  53. package/docs/frameworks/next/components/consent-widget.md +172 -114
  54. package/docs/frameworks/next/components/dev-tools.md +199 -40
  55. package/docs/frameworks/next/components/frame.md +137 -42
  56. package/docs/frameworks/next/concepts/consent-categories.md +24 -89
  57. package/docs/frameworks/next/concepts/policy-presets.md +142 -0
  58. package/docs/frameworks/next/content-security-policy.md +189 -0
  59. package/docs/frameworks/next/data-fetching.md +74 -0
  60. package/docs/frameworks/next/geography-headers.md +251 -0
  61. package/docs/frameworks/next/headless.md +95 -185
  62. package/docs/frameworks/next/hooks/use-consent-manager/overview.md +42 -163
  63. package/docs/frameworks/next/iab/overview.md +37 -107
  64. package/docs/frameworks/next/optimization.md +158 -194
  65. package/docs/frameworks/next/pages-router.md +296 -0
  66. package/docs/frameworks/next/quickstart.md +31 -132
  67. package/docs/frameworks/next/script-loader.md +140 -465
  68. package/docs/frameworks/next/server-side.md +97 -130
  69. package/docs/frameworks/next/static-export.md +164 -0
  70. package/docs/frameworks/next/styling/overview.md +174 -248
  71. package/docs/frameworks/next/troubleshooting.md +134 -144
  72. package/docs/guides/consent-state.md +60 -0
  73. package/docs/guides/data-fetching.md +163 -0
  74. package/docs/guides/deployment-modes.md +63 -0
  75. package/docs/guides/troubleshooting.md +68 -0
  76. package/docs/guides/verify-consent.md +62 -0
  77. package/docs/integrations/adobe-analytics.md +239 -105
  78. package/docs/integrations/ahrefs-analytics.md +238 -104
  79. package/docs/integrations/amplitude.md +219 -157
  80. package/docs/integrations/building-integrations.md +32 -224
  81. package/docs/integrations/clear-on-revocation.md +167 -0
  82. package/docs/integrations/clearbit.md +247 -86
  83. package/docs/integrations/cloudflare-web-analytics.md +250 -84
  84. package/docs/integrations/crisp.md +251 -97
  85. package/docs/integrations/databuddy.md +259 -153
  86. package/docs/integrations/fathom-analytics.md +239 -96
  87. package/docs/integrations/google-maps.md +328 -207
  88. package/docs/integrations/google-tag-manager.md +248 -96
  89. package/docs/integrations/google-tag.md +261 -90
  90. package/docs/integrations/heap.md +222 -149
  91. package/docs/integrations/hightouch.md +225 -131
  92. package/docs/integrations/hotjar.md +239 -90
  93. package/docs/integrations/intercom.md +239 -98
  94. package/docs/integrations/linkedin-insights.md +243 -113
  95. package/docs/integrations/logrocket.md +241 -123
  96. package/docs/integrations/matomo-analytics.md +256 -111
  97. package/docs/integrations/meta-pixel.md +197 -324
  98. package/docs/integrations/microsoft-clarity.md +233 -114
  99. package/docs/integrations/microsoft-uet.md +245 -110
  100. package/docs/integrations/mixpanel-analytics.md +252 -87
  101. package/docs/integrations/openai-pixel.md +441 -0
  102. package/docs/integrations/overview.md +95 -133
  103. package/docs/integrations/pirsch.md +249 -96
  104. package/docs/integrations/plausible-analytics.md +241 -100
  105. package/docs/integrations/posthog.md +353 -214
  106. package/docs/integrations/promptwatch.md +251 -81
  107. package/docs/integrations/reddit-pixel.md +226 -173
  108. package/docs/integrations/rudderstack.md +244 -187
  109. package/docs/integrations/rybbit-analytics.md +244 -91
  110. package/docs/integrations/segment.md +238 -92
  111. package/docs/integrations/snapchat-pixel.md +240 -110
  112. package/docs/integrations/tiktok-pixel.md +249 -81
  113. package/docs/integrations/umami-analytics.md +242 -95
  114. package/docs/integrations/vercel-analytics.md +242 -90
  115. package/docs/integrations/x-pixel.md +238 -104
  116. package/docs/integrations/youtube.md +354 -142
  117. package/docs/upgrade-v3.md +334 -0
  118. package/iab/styles.css +1 -1
  119. package/iab/styles.tw3.css +1 -1
  120. package/package.json +106 -65
  121. package/readme.json +3 -3
  122. package/src/iab/styles.css +1 -1
  123. package/src/iab/styles.tw3.css +1 -1
  124. package/src/styles.css +1 -1
  125. package/src/styles.tw3.css +1 -1
  126. package/styles.css +1 -1
  127. package/styles.tw3.css +1 -1
  128. package/client/components/consent-dialog-link.js +0 -3
  129. package/client/components/integrations.js +0 -3
  130. package/dist/components/integrations/index.cjs +0 -1
  131. package/dist/components/integrations/index.js +0 -1
  132. package/dist/headless.cjs +0 -1
  133. package/dist/index.cjs +0 -1
  134. package/dist/libs/browser-initial-data.cjs +0 -1
  135. package/dist/libs/browser-initial-data.js +0 -1
  136. package/dist/libs/initial-data.cjs +0 -1
  137. package/dist/libs/initial-data.js +0 -1
  138. package/dist/types.cjs +0 -1
  139. package/dist/version.cjs +0 -1
  140. package/dist-types/components/integrations/index.d.ts +0 -1
  141. package/dist-types/libs/browser-initial-data.d.ts +0 -9
  142. package/dist-types/libs/initial-data.d.ts +0 -33
  143. package/docs/frameworks/next/building-headless-components.md +0 -379
  144. package/docs/frameworks/next/callbacks.md +0 -186
  145. package/docs/frameworks/next/concepts/client-modes.md +0 -177
  146. package/docs/frameworks/next/concepts/consent-models.md +0 -117
  147. package/docs/frameworks/next/concepts/cookie-management.md +0 -122
  148. package/docs/frameworks/next/concepts/glossary.md +0 -24
  149. package/docs/frameworks/next/concepts/initialization-flow.md +0 -149
  150. package/docs/frameworks/next/concepts/policy-packs.md +0 -230
  151. package/docs/frameworks/next/hooks/use-color-scheme.md +0 -41
  152. package/docs/frameworks/next/hooks/use-consent-manager/checking-consent.md +0 -96
  153. package/docs/frameworks/next/hooks/use-consent-manager/location-info.md +0 -97
  154. package/docs/frameworks/next/hooks/use-consent-manager/setting-consent.md +0 -94
  155. package/docs/frameworks/next/hooks/use-draggable.md +0 -59
  156. package/docs/frameworks/next/hooks/use-focus-trap.md +0 -42
  157. package/docs/frameworks/next/hooks/use-reduced-motion.md +0 -37
  158. package/docs/frameworks/next/hooks/use-ssr-status.md +0 -32
  159. package/docs/frameworks/next/hooks/use-text-direction.md +0 -50
  160. package/docs/frameworks/next/hooks/use-translations.md +0 -55
  161. package/docs/frameworks/next/iab/consent-banner.md +0 -91
  162. package/docs/frameworks/next/iab/consent-dialog.md +0 -129
  163. package/docs/frameworks/next/iab/use-gvl-data.md +0 -21
  164. package/docs/frameworks/next/iframe-blocking.md +0 -106
  165. package/docs/frameworks/next/internationalization.md +0 -207
  166. package/docs/frameworks/next/network-blocker.md +0 -140
  167. package/docs/frameworks/next/policy-packs.md +0 -248
  168. package/docs/frameworks/next/styling/classnames.md +0 -94
  169. package/docs/frameworks/next/styling/color-scheme.md +0 -84
  170. package/docs/frameworks/next/styling/css-variables.md +0 -53
  171. package/docs/frameworks/next/styling/slots.md +0 -94
  172. package/docs/frameworks/next/styling/tailwind.md +0 -137
  173. package/docs/frameworks/next/styling/tokens.md +0 -156
  174. package/docs/shared/concepts/client-modes.md +0 -103
  175. package/docs/shared/concepts/consent-categories.md +0 -41
  176. package/docs/shared/concepts/consent-models.md +0 -72
  177. package/docs/shared/concepts/cookie-management.md +0 -88
  178. package/docs/shared/concepts/glossary.md +0 -24
  179. package/docs/shared/concepts/initialization-flow.md +0 -105
  180. package/docs/shared/concepts/policy-packs.md +0 -225
  181. package/docs/shared/react/components/consent-banner.md +0 -242
  182. package/docs/shared/react/components/consent-dialog-link.md +0 -45
  183. package/docs/shared/react/components/consent-dialog-trigger.md +0 -185
  184. package/docs/shared/react/components/consent-dialog.md +0 -119
  185. package/docs/shared/react/components/consent-manager-provider.md +0 -225
  186. package/docs/shared/react/components/consent-widget.md +0 -121
  187. package/docs/shared/react/components/dev-tools.md +0 -81
  188. package/docs/shared/react/components/frame.md +0 -52
  189. package/docs/shared/react/guides/building-headless-components.md +0 -110
  190. package/docs/shared/react/guides/callbacks.md +0 -89
  191. package/docs/shared/react/guides/headless.md +0 -31
  192. package/docs/shared/react/guides/iframe-blocking.md +0 -65
  193. package/docs/shared/react/guides/internationalization.md +0 -123
  194. package/docs/shared/react/guides/network-blocker.md +0 -72
  195. package/docs/shared/react/guides/optimization.md +0 -44
  196. package/docs/shared/react/guides/policy-packs.md +0 -173
  197. package/docs/shared/react/guides/script-loader.md +0 -311
  198. package/docs/shared/react/hooks/use-color-scheme.md +0 -31
  199. package/docs/shared/react/hooks/use-consent-manager/checking-consent.md +0 -95
  200. package/docs/shared/react/hooks/use-consent-manager/location-info.md +0 -96
  201. package/docs/shared/react/hooks/use-consent-manager/overview.md +0 -74
  202. package/docs/shared/react/hooks/use-consent-manager/setting-consent.md +0 -93
  203. package/docs/shared/react/hooks/use-draggable.md +0 -30
  204. package/docs/shared/react/hooks/use-focus-trap.md +0 -20
  205. package/docs/shared/react/hooks/use-reduced-motion.md +0 -33
  206. package/docs/shared/react/hooks/use-ssr-status.md +0 -16
  207. package/docs/shared/react/hooks/use-text-direction.md +0 -38
  208. package/docs/shared/react/hooks/use-translations.md +0 -15
  209. package/docs/shared/react/iab/consent-banner.md +0 -60
  210. package/docs/shared/react/iab/consent-dialog.md +0 -76
  211. package/docs/shared/react/iab/overview.md +0 -80
  212. package/docs/shared/react/iab/use-gvl-data.md +0 -21
  213. package/docs/shared/react/styling/classnames.md +0 -93
  214. package/docs/shared/react/styling/color-scheme.md +0 -35
  215. package/docs/shared/react/styling/css-variables.md +0 -53
  216. package/docs/shared/react/styling/overview.md +0 -261
  217. package/docs/shared/react/styling/slots.md +0 -93
  218. package/docs/shared/react/styling/stylesheet-entrypoint.md +0 -8
  219. package/docs/shared/react/styling/tailwind.md +0 -88
  220. package/docs/shared/react/styling/tokens.md +0 -155
  221. package/docs/shared/troubleshooting.md +0 -82
@@ -1,185 +1,64 @@
1
1
  ---
2
- title: useConsentManager
3
- description: The primary hook for accessing consent state and actions. Returns
4
- the full consent store including all state properties and action methods.
2
+ title: Hooks
3
+ description: Gate features and save consent choices in Next.js Client Components
4
+ with the focused hooks exported from c15t/next.
5
5
  group: frameworks
6
6
  ---
7
- `useConsentManager()` is the primary hook for interacting with the consent system. It returns the complete consent store state and all action methods.
8
7
 
9
- ```tsx
10
- import { useConsentManager } from '@c15t/nextjs';
8
+ ## Read only the state you need
11
9
 
12
- function MyComponent() {
13
- const {
14
- consents,
15
- model,
16
- has,
17
- saveConsents,
18
- // ... all state and actions
19
- } = useConsentManager();
20
- }
21
- ```
22
-
23
- > ⚠️ **Warning:**
24
- > Must be used within a ConsentManagerProvider. Throws an error if used outside the provider.
25
-
26
- ## State Properties
27
-
28
- |Property|Value|
29
- |:--|:--|
30
- |Type Name|\`StoreRuntimeState\`|
31
- |Source Path|\`./packages/core/src/store/type.ts\`|
32
-
33
- \*ExtractedTypeTable: Could not extract "StoreRuntimeState" from "./packages/core/src/store/type.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
34
-
35
- ## Action Methods
36
-
37
- |Property|Value|
38
- |:--|:--|
39
- |Type Name|\`StoreActions\`|
40
- |Source Path|\`./packages/core/src/store/type.ts\`|
41
-
42
- \*ExtractedTypeTable: Could not extract "StoreActions" from "./packages/core/src/store/type.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
43
-
44
- ## User Identification
45
-
46
- You can link a consent subject to your own internal user ID or a non-secret anonymous visitor ID. c15t stores the identifier in the subject row's `externalId` field. Consent records remain associated with that subject through `subjectId`, so your backend can find the subject and its related consent records by external ID for GDPR Article 15 exports.
47
-
48
- ### 1. Providing the Current User ID
49
-
50
- When using Clerk, prefer the Clerk `userId` whenever the visitor is signed in. Before sign-in, you can fall back to a non-secret visitor ID stored in a first-party cookie:
51
-
52
- > ⚠️ **Warning:**
53
- > ConsentManagerProvider runs on the client. Values passed through options.user are therefore available to client-side JavaScript, even when they were read from an HttpOnly cookie on the server. Pass only a non-secret identifier, such as a Clerk userId or an opaque visitor ID. Never pass a Clerk session token or a value returned by getToken().
54
- >
55
- > ℹ️ **Info:**
56
- > Clerk's auth() helper requires clerkMiddleware() to be configured. This example also uses the asynchronous cookies() API from Next.js 15+. For Next.js 14 and earlier, use const cookieStore = cookies(); without await. Keep the layout asynchronous because Clerk's auth() is asynchronous.
57
-
58
- ```tsx
59
- // app/layout.tsx
60
- import { ClerkProvider } from '@clerk/nextjs';
61
- import { auth } from '@clerk/nextjs/server';
62
- import { ConsentManagerProvider } from '@c15t/nextjs';
63
- import { cookies } from 'next/headers';
64
- import { ClerkConsentSync } from './clerk-consent-sync';
65
-
66
- export default async function RootLayout({ children }: { children: React.ReactNode }) {
67
- const { userId } = await auth();
68
- const cookieStore = await cookies();
69
- const visitorId = cookieStore.get('consent_visitor_id')?.value;
70
- const consentUser = userId
71
- ? { id: userId, identityProvider: 'clerk' }
72
- : visitorId
73
- ? { id: visitorId, identityProvider: 'anonymous-visitor' }
74
- : undefined;
75
-
76
- return (
77
- <html lang="en">
78
- <body>
79
- <ClerkProvider>
80
- <ConsentManagerProvider
81
- options={{
82
- mode: 'hosted',
83
- backendURL: '/api/c15t',
84
- consentCategories: ['necessary', 'measurement', 'marketing'],
85
- user: consentUser,
86
- }}
87
- >
88
- <ClerkConsentSync />
89
- {children}
90
- </ConsentManagerProvider>
91
- </ClerkProvider>
92
- </body>
93
- </html>
94
- );
95
- }
96
- ```
97
-
98
- ### 2. Synchronizing Clerk Sign-ins
99
-
100
- Clerk can complete a sign-in without reloading the page. Add a client component inside `ConsentManagerProvider` to update the current consent subject as soon as Clerk exposes the authenticated `userId`:
10
+ Every hook reads the runtime from the `ConsentRoot` set up in your
11
+ [App Router](../../app-router.md) or
12
+ [Pages Router](../../pages-router.md) guide, so call them from a
13
+ Client Component rendered inside that root and import them from
14
+ `c15t/next`.
101
15
 
102
- ```tsx
103
- // app/clerk-consent-sync.tsx
16
+ ```tsx title="components/optional-feature.tsx"
104
17
  'use client';
105
18
 
106
- import { useAuth } from '@clerk/nextjs';
107
- import { useConsentManager } from '@c15t/nextjs';
108
- import { useEffect } from 'react';
109
-
110
- export function ClerkConsentSync() {
111
- const { isLoaded, isSignedIn, userId } = useAuth();
112
- const { identifyUser } = useConsentManager();
113
-
114
- useEffect(() => {
115
- if (!isLoaded || !isSignedIn || !userId) {
116
- return;
117
- }
19
+ import { useConsent } from 'c15t/next';
118
20
 
119
- void identifyUser({
120
- id: userId,
121
- identityProvider: 'clerk',
122
- }).then(() => {
123
- // Prevent the old anonymous ID from replacing the Clerk ID after sign-out.
124
- document.cookie =
125
- 'consent_visitor_id=; Max-Age=0; Path=/; SameSite=Lax';
126
- });
127
- }, [identifyUser, isLoaded, isSignedIn, userId]);
128
-
129
- return null;
21
+ export function OptionalFeature() {
22
+ const allowed = useConsent('marketing');
23
+ return allowed ? <div>Optional marketing content</div> : null;
130
24
  }
131
25
  ```
132
26
 
133
- `identifyUser()` replaces the subject's current `externalId`; it does not retain the anonymous ID as an alias. Once a visitor is linked to Clerk, stop supplying the former visitor ID. The example clears its client-readable cookie only after `identifyUser()` succeeds so a later render cannot change the subject back to the anonymous ID.
134
-
135
- > ℹ️ **Info:**
136
- > Backend subject identification requires hosted mode (mode: 'hosted'). In offline mode, identifyUser() cannot update a backend subject. Identifiers supplied through options.user can still be held in client state and persisted with locally stored consent, so do not place sensitive values there.
137
-
138
- ## Key Types
139
-
140
- ### ConsentState
27
+ Call hooks inside the consent provider. `useConsent` reads effective permission,
28
+ which can be true under an opt-out policy without a recorded grant.
141
29
 
142
- A record mapping consent category names to their boolean values:
30
+ | Need | Hook |
31
+ | --------------------------------- | ------------------------------------------ |
32
+ | One category's current permission | `useConsent(category)` |
33
+ | All current permissions | `useConsents()` |
34
+ | Recorded per-category choices | `useExplicitChoice()` |
35
+ | Whether a prompt is required | `usePromptRequirement()` |
36
+ | Active policy and resolution | `usePolicyRule()`, `usePolicyResolution()` |
37
+ | Save an explicit choice | `useSaveConsents()` |
38
+ | Open or close a consent surface | `useSetActiveUI()` |
39
+ | Acknowledge a notice | `useDismissNotice()` |
143
40
 
144
- ```ts
145
- type ConsentState = Record<AllConsentNames, boolean>;
146
- // Example: { necessary: true, measurement: true, marketing: false }
147
- ```
148
-
149
- ### ConsentInfo
150
-
151
- Metadata about when and how consent was recorded:
41
+ ## Save from a visitor action
152
42
 
153
- ```ts
154
- interface ConsentInfo {
155
- time: number; // Epoch timestamp when consent was recorded
156
- subjectId?: string; // Client-generated subject ID (sub_xxx format)
157
- externalId?: string; // External user ID linked via identifyUser()
158
- identityProvider?: string; // Identity provider (e.g. 'clerk', 'auth0')
159
- }
160
- ```
43
+ Place this Client Component inside your existing consent boundary.
161
44
 
162
- ### LocationInfo
45
+ ```tsx title="components/reject-button.tsx"
46
+ 'use client';
163
47
 
164
- Detected geographic location from the c15t backend:
48
+ import { useSaveConsents } from 'c15t/next';
165
49
 
166
- ```ts
167
- interface LocationInfo {
168
- countryCode: string; // ISO 3166-1 alpha-2 (e.g. 'DE')
169
- regionCode: string; // Region/state code (e.g. 'BY')
170
- jurisdiction: string; // Applicable jurisdiction (e.g. 'GDPR', 'CCPA')
50
+ export function RejectButton() {
51
+ const save = useSaveConsents();
52
+ return <button type="button" onClick={() => void save('none')}>Reject optional</button>;
171
53
  }
172
54
  ```
173
55
 
174
- ### Model
175
-
176
- The active consent model:
177
-
178
- ```ts
179
- type Model = 'opt-in' | 'opt-out' | 'iab' | null;
180
- ```
56
+ This is an isolated action example, not a complete policy-aware banner. Use the
57
+ stock UI or headless surface actions for a complete prompt. Do not call save on
58
+ mount to persist a state derived from permissions.
181
59
 
182
- * `'opt-in'` — Explicit consent required before tracking (GDPR)
183
- * `'opt-out'` — Tracking allowed by default, user can opt out (CCPA)
184
- * `'iab'` — IAB TCF 2.3 compliance mode
185
- * `null` — No jurisdiction detected yet
60
+ `useConsentManager` remains available for the combined UI API, including draft
61
+ management. Prefer focused hooks for simple feature gates and use the headless
62
+ UI hook when implementing a complete custom prompt. Read
63
+ [consent state](../../../../guides/consent-state.md) before treating a callback as evidence
64
+ of a choice.
@@ -1,128 +1,58 @@
1
1
  ---
2
- title: IAB TCF 2.3
3
- description: Implement IAB Transparency & Consent Framework 2.3 compliance for
4
- programmatic advertising in EU/EEA jurisdictions.
2
+ title: IAB TCF
3
+ description: Mount the IAB TCF banner and dialog inside a Next.js ConsentRoot
4
+ and configure the CMP ID, policy and vendor data.
5
5
  group: frameworks
6
6
  ---
7
- ## What is IAB TCF?
8
7
 
9
- The [IAB Transparency & Consent Framework (TCF)](https://iabeurope.eu/tcf-2-0/) is a standardized protocol for communicating user consent choices to ad tech vendors in the programmatic advertising ecosystem. TCF 2.3 is the current version and is widely adopted across the EU/EEA.
8
+ ## Prepare the IAB configuration
10
9
 
11
- When your site participates in the IAB ecosystem (ad exchanges, SSPs, DSPs, DMPs), you need to:
10
+ Use the IAB integration when your application needs the Transparency and Consent
11
+ Framework. Configure an IAB policy, the correct CMP identity and vendor data for
12
+ your deployment. A demo CMP ID is not a production configuration.
12
13
 
13
- * Disclose which vendors process user data and for what purposes
14
- * Collect granular consent for each IAB-defined purpose
15
- * Generate a **TC String** — a standardized encoding of consent choices that ad tech vendors can read
16
- * Expose the `__tcfapi` CMP stub for vendor scripts to query consent status
14
+ Install `@c15t/iab` alongside your framework adapter, then mount the IAB
15
+ components inside an existing consent provider connected to Inth.
17
16
 
18
- ## CMP Registration
17
+ Next.js uses the React IAB components. There is no `c15t/next/iab` JavaScript
18
+ entry point, so import the components from `c15t/react/iab` and render this
19
+ Client Component inside the `ConsentRoot` from your
20
+ [App Router](../app-router.md) or
21
+ [Pages Router](../pages-router.md) setup. Import
22
+ `c15t/next/iab/styles.css` at your global stylesheet entry.
19
23
 
20
- [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.
24
+ ```tsx title="components/iab-consent.tsx"
25
+ 'use client';
21
26
 
22
- 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.
27
+ import { IABProvider, IABConsentBanner, IABConsentDialog } from 'c15t/react/iab';
23
28
 
24
- > ⚠️ **Warning:**
25
- > 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.
26
-
27
- ## How c15t Implements TCF
28
-
29
- c15t provides a complete IAB TCF 2.3 CMP (Consent Management Platform) implementation:
30
-
31
- 1. **Global Vendor List (GVL)** — Automatically fetched from the c15t backend. Contains the official IAB vendor registry with purposes, features, and stacks.
32
- 2. **IABConsentBanner** — A pre-built banner showing partner count, purpose summaries, and legitimate interest notices.
33
- 3. **IABConsentDialog** — A tabbed preference center for granular purpose and vendor consent management.
34
- 4. **TC String generation** — Consent choices are encoded into the standard TC String format.
35
- 5. **`__tcfapi` stub** — The standard CMP API is exposed on `window` so vendor scripts can query consent.
36
-
37
- If you use the prebuilt styled IAB UI, add your framework's `iab/styles.css` entrypoint alongside the base c15t stylesheet. IAB CSS is published separately so apps that do not render IAB surfaces do not ship those component rules.
38
-
39
- ## Quick Setup
40
-
41
- If you use the prebuilt styled IAB UI, import the IAB stylesheet alongside the base stylesheet in your global CSS entrypoint:
42
-
43
- ```css title="src/app/globals.css"
44
- @import "@c15t/nextjs/styles.css";
45
- @import "@c15t/nextjs/iab/styles.css";
46
- ```
47
-
48
- ```tsx
49
- import { type ReactNode } from 'react';
50
- import { iab } from '@c15t/iab';
51
- import { ConsentManagerProvider } from '@c15t/nextjs';
52
- import { IABConsentBanner, IABConsentDialog } from '@c15t/react/iab';
53
-
54
- export default function ConsentManager({ children }: { children: ReactNode }) {
29
+ export function IABConsent({ cmpId }: { cmpId: number }) {
55
30
  return (
56
- <ConsentManagerProvider
57
- options={{
58
- mode: 'hosted',
59
- backendURL: '/api/c15t',
60
- iab: iab({
61
- vendors: [1, 2, 10, 25], // IAB vendor IDs you work with
62
- // cmpId is automatically provided by the backend (inth.com).
63
- // Only set this if you have your own CMP registration with IAB Europe.
64
- // cmpId: 123,
65
- }),
66
- }}
67
- >
31
+ <IABProvider cmpId={cmpId}>
68
32
  <IABConsentBanner />
69
- <IABConsentDialog showTrigger />
70
- {children}
71
- </ConsentManagerProvider>
33
+ <IABConsentDialog />
34
+ </IABProvider>
72
35
  );
73
36
  }
74
37
  ```
75
38
 
76
- ## IAB Configuration Options
77
-
78
- Configure IAB mode with `iab({ ... })` from `@c15t/iab`. The factory enables the addon and injects the runtime module automatically. The user-facing options are:
79
-
80
- |Option|Type|Description|
81
- |--|--|--|
82
- |`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.|
83
- |`vendors`|`number[]`|IAB vendor IDs that your site works with|
84
- |`customVendors`|`NonIABVendor[]`|Custom vendors not in the IAB registry|
85
-
86
- ## Key Concepts
87
-
88
- ### Purposes
89
-
90
- IAB defines 11 standard purposes for data processing (e.g., "Store and/or access information on a device", "Select basic ads", "Measure ad performance"). Each purpose can be consented to individually.
91
-
92
- ### Stacks
93
-
94
- Purposes are grouped into **stacks** by the GVL for a simplified UI presentation. For example, "Advertising based on limited data" might group purposes 2, 7, and 10 together.
95
-
96
- ### Special Features
97
-
98
- Features like precise geolocation or device scanning that require explicit opt-in beyond standard consent.
99
-
100
- ### Legitimate Interest
101
-
102
- Some purposes can be processed under legitimate interest rather than consent. Users can object to legitimate interest processing per-vendor.
103
-
104
- ### Vendors
105
-
106
- Each vendor in the GVL declares which purposes it uses, whether via consent or legitimate interest. The preference center lets users toggle consent per-vendor.
39
+ Supply the CMP ID from your deployment's IAB configuration. Keep a persistent
40
+ preferences entry point through the surrounding consent provider.
107
41
 
108
- ## Standard vs IAB Components
42
+ ## Resolve the policy before rendering
109
43
 
110
- |Feature|ConsentBanner / ConsentDialog|IABConsentBanner / IABConsentDialog|
111
- |--|--|--|
112
- |Consent model|opt-in / opt-out|IAB TCF 2.3|
113
- |Granularity|Category-level (measurement, marketing, etc.)|Purpose-level + vendor-level|
114
- |Vendor management|No|Yes (full GVL integration)|
115
- |TC String|No|Yes|
116
- |`__tcfapi`|No|Yes|
117
- |Legitimate interest|No|Yes|
118
- |Use when|General GDPR/CCPA compliance|Programmatic advertising in EU/EEA|
44
+ IAB components remain hidden until an applicable policy resolves. Forcing a
45
+ dialog open does not create a policy or vendor list. Inspect resolution and the
46
+ Global Vendor List response before changing rendering conditions.
119
47
 
120
- ## Components
48
+ IAB presentation follows `presentation.prompt.blocking` and
49
+ `presentation.preferences.blocking`. A blocking dialog needs focus management,
50
+ scroll locking and a backdrop together. See [migration](../../../upgrade-v3.md) for
51
+ legacy option behavior.
121
52
 
122
- |Component|Description|
123
- |--|--|
124
- |[IABConsentBanner](/docs/frameworks/next/iab/consent-banner)|TCF-compliant banner with partner disclosure|
125
- |[IABConsentDialog](/docs/frameworks/next/iab/consent-dialog)|Tabbed preference center for purposes and vendors|
53
+ ## Verify vendor and purpose choices
126
54
 
127
- > ℹ️ **Info:**
128
- > 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.
55
+ Test category choices alongside vendor, purpose, legitimate-interest and special
56
+ feature controls used by your integration. Confirm the TC String and `__tcfapi`
57
+ reflect the saved state, and verify the vendor's actual requests. A category-only
58
+ banner test does not establish that the IAB flow works.