@c15t/react 2.0.4 → 2.2.0-canary-20260727202135
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.
- package/AGENTS.md +155 -0
- package/README.md +29 -14
- package/client/components/integrations.js +3 -0
- package/dist/components/consent-banner/atoms/overlay.cjs +1 -1
- package/dist/components/consent-banner/atoms/root.cjs +1 -1
- package/dist/components/consent-banner/components.cjs +1 -1
- package/dist/components/consent-banner/consent-banner.cjs +1 -1
- package/dist/components/consent-banner/error-boundary.cjs +1 -1
- package/dist/components/consent-banner/index.cjs +1 -1
- package/dist/components/consent-banner/policy-actions.cjs +1 -1
- package/dist/components/consent-dialog/atoms/card.cjs +1 -1
- package/dist/components/consent-dialog/atoms/overlay.cjs +1 -1
- package/dist/components/consent-dialog/atoms/root.cjs +1 -1
- package/dist/components/consent-dialog/consent-dialog.cjs +1 -1
- package/dist/components/consent-dialog/index.cjs +1 -1
- package/dist/components/consent-dialog-link/index.cjs +1 -1
- package/dist/components/consent-dialog-trigger/atoms/button.cjs +1 -1
- package/dist/components/consent-dialog-trigger/atoms/button.js +1 -1
- package/dist/components/consent-dialog-trigger/atoms/icon.cjs +1 -1
- package/dist/components/consent-dialog-trigger/atoms/root.cjs +1 -1
- package/dist/components/consent-dialog-trigger/atoms/text.cjs +1 -1
- package/dist/components/consent-dialog-trigger/atoms/toolbar.cjs +1 -0
- package/dist/components/consent-dialog-trigger/atoms/toolbar.js +1 -0
- package/dist/components/consent-dialog-trigger/consent-dialog-trigger-toolbar.cjs +1 -0
- package/dist/components/consent-dialog-trigger/consent-dialog-trigger-toolbar.js +1 -0
- package/dist/components/consent-dialog-trigger/consent-dialog-trigger.cjs +1 -1
- package/dist/components/consent-dialog-trigger/index.cjs +1 -1
- package/dist/components/consent-dialog-trigger/index.js +1 -1
- package/dist/components/consent-dialog-trigger/use-draggable.cjs +1 -1
- package/dist/components/consent-preferences-link/consent-preferences-link.cjs +1 -1
- package/dist/components/consent-preferences-link/index.cjs +1 -1
- package/dist/components/consent-widget/atoms/accordion.cjs +1 -1
- package/dist/components/consent-widget/atoms/button.cjs +1 -1
- package/dist/components/consent-widget/atoms/footer.cjs +1 -1
- package/dist/components/consent-widget/atoms/root.cjs +1 -1
- package/dist/components/consent-widget/consent-widget.cjs +1 -1
- package/dist/components/consent-widget/index.cjs +1 -1
- package/dist/components/consent-widget/policy-actions.cjs +1 -1
- package/dist/components/frame/atoms.cjs +1 -1
- package/dist/components/frame/atoms.js +1 -1
- package/dist/components/frame/frame.cjs +1 -1
- package/dist/components/frame/index.cjs +1 -1
- package/dist/components/iab-consent-banner/atoms/button-group.cjs +1 -1
- package/dist/components/iab-consent-banner/atoms/card.cjs +1 -1
- package/dist/components/iab-consent-banner/atoms/description.cjs +1 -1
- package/dist/components/iab-consent-banner/atoms/footer.cjs +1 -1
- package/dist/components/iab-consent-banner/atoms/header.cjs +1 -1
- package/dist/components/iab-consent-banner/atoms/overlay.cjs +1 -1
- package/dist/components/iab-consent-banner/atoms/root.cjs +1 -1
- package/dist/components/iab-consent-banner/atoms/title.cjs +1 -1
- package/dist/components/iab-consent-banner/iab-consent-banner.cjs +1 -1
- package/dist/components/iab-consent-banner/iab-consent-banner.js +1 -1
- package/dist/components/iab-consent-banner/index.cjs +1 -1
- package/dist/components/iab-consent-dialog/atoms/card.cjs +1 -1
- package/dist/components/iab-consent-dialog/atoms/content.cjs +1 -1
- package/dist/components/iab-consent-dialog/atoms/footer.cjs +1 -1
- package/dist/components/iab-consent-dialog/atoms/header.cjs +1 -1
- package/dist/components/iab-consent-dialog/atoms/overlay.cjs +1 -1
- package/dist/components/iab-consent-dialog/atoms/purpose-item.cjs +1 -1
- package/dist/components/iab-consent-dialog/atoms/root.cjs +1 -1
- package/dist/components/iab-consent-dialog/atoms/stack-item.cjs +1 -1
- package/dist/components/iab-consent-dialog/atoms/tabs.cjs +1 -1
- package/dist/components/iab-consent-dialog/atoms/vendor-list.cjs +1 -1
- package/dist/components/iab-consent-dialog/hooks/use-gvl-data.cjs +1 -1
- package/dist/components/iab-consent-dialog/iab-consent-dialog.cjs +1 -1
- package/dist/components/iab-consent-dialog/index.cjs +1 -1
- package/dist/components/iab-consent-dialog/use-iab-translations.cjs +1 -1
- package/dist/components/integrations/google-map.cjs +1 -0
- package/dist/components/integrations/google-map.js +1 -0
- package/dist/components/integrations/index.cjs +1 -0
- package/dist/components/integrations/index.js +1 -0
- package/dist/components/integrations/shared.cjs +1 -0
- package/dist/components/integrations/shared.js +1 -0
- package/dist/components/integrations/youtube-embed.cjs +1 -0
- package/dist/components/integrations/youtube-embed.js +1 -0
- package/dist/components/shared/libs/recursive-clone-children.cjs +1 -1
- package/dist/components/shared/libs/slot.cjs +1 -1
- package/dist/components/shared/libs/use-controllable-state.cjs +1 -1
- package/dist/components/shared/policy-actions.cjs +1 -1
- package/dist/components/shared/primitives/box.cjs +1 -1
- package/dist/components/shared/primitives/button.cjs +1 -1
- package/dist/components/shared/primitives/button.js +1 -1
- package/dist/components/shared/primitives/legal-links/index.cjs +1 -1
- package/dist/components/shared/primitives/legal-links/index.js +1 -1
- package/dist/components/shared/ui/accordion/accordion.cjs +1 -1
- package/dist/components/shared/ui/accordion/index.cjs +1 -1
- package/dist/components/shared/ui/animated-collapse/animated-collapse.cjs +1 -1
- package/dist/components/shared/ui/animated-collapse/index.cjs +1 -1
- package/dist/components/shared/ui/branding.cjs +1 -1
- package/dist/components/shared/ui/button/button.cjs +1 -1
- package/dist/components/shared/ui/button/index.cjs +1 -1
- package/dist/components/shared/ui/collapsible/collapsible.cjs +1 -1
- package/dist/components/shared/ui/collapsible/index.cjs +1 -1
- package/dist/components/shared/ui/dialog/dialog.cjs +1 -1
- package/dist/components/shared/ui/dialog/index.cjs +1 -1
- package/dist/components/shared/ui/icon.cjs +1 -1
- package/dist/components/shared/ui/logo.cjs +1 -1
- package/dist/components/shared/ui/preference-item/index.cjs +1 -1
- package/dist/components/shared/ui/preference-item/preference-item.cjs +1 -1
- package/dist/components/shared/ui/switch/index.cjs +1 -1
- package/dist/components/shared/ui/switch/switch.cjs +1 -1
- package/dist/components/shared/ui/tabs/index.cjs +1 -1
- package/dist/components/shared/ui/tabs/tabs.cjs +1 -1
- package/dist/context/consent-manager-context.cjs +1 -1
- package/dist/context/consent-tracking-context.cjs +1 -1
- package/dist/context/theme-context.cjs +1 -1
- package/dist/headless.cjs +1 -1
- package/dist/headless.js +1 -1
- package/dist/hooks/index.cjs +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/use-color-scheme.cjs +1 -1
- package/dist/hooks/use-component-config.cjs +1 -1
- package/dist/hooks/use-consent-dialog-trigger.cjs +1 -1
- package/dist/hooks/use-consent-manager.cjs +1 -1
- package/dist/hooks/use-consent-script.cjs +1 -0
- package/dist/hooks/use-consent-script.js +1 -0
- package/dist/hooks/use-focus-trap.cjs +1 -1
- package/dist/hooks/use-headless-consent-ui.cjs +1 -1
- package/dist/hooks/use-headless-iab-consent-ui.cjs +1 -1
- package/dist/hooks/use-reduced-motion.cjs +1 -1
- package/dist/hooks/use-scroll-lock.cjs +1 -1
- package/dist/hooks/use-ssr-status.cjs +1 -1
- package/dist/hooks/use-styles.cjs +1 -1
- package/dist/hooks/use-text-direction.cjs +1 -1
- package/dist/hooks/use-theme.cjs +1 -1
- package/dist/hooks/use-translations.cjs +1 -1
- package/dist/iab.cjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/primitives/accordion.cjs +1 -1
- package/dist/primitives/button.cjs +1 -1
- package/dist/primitives/collapsible.cjs +1 -1
- package/dist/primitives/dialog.cjs +1 -1
- package/dist/primitives/preference-item.cjs +1 -1
- package/dist/primitives/switch.cjs +1 -1
- package/dist/primitives/tabs.cjs +1 -1
- package/dist/primitives.cjs +1 -1
- package/dist/providers/consent-manager-provider.cjs +1 -1
- package/dist/server/fetch-ssr-data.cjs +1 -1
- package/dist/server/fetch-ssr-data.js +1 -1
- package/dist/server/headers.cjs +1 -1
- package/dist/server/headers.js +1 -1
- package/dist/server/index.cjs +1 -1
- package/dist/server/init-cache-key.cjs +1 -1
- package/dist/server/normalize-url.cjs +1 -1
- package/dist/styles.tw3.css +1 -1
- package/dist/types/theme/index.cjs +1 -1
- package/dist/types/theme/style-types.cjs +1 -1
- package/dist/utils/cn.cjs +1 -1
- package/dist/utils/merge-styles.cjs +1 -1
- package/dist/utils/test-helpers.cjs +1 -1
- package/dist/utils/theme-utils.cjs +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/dist-types/components/consent-banner/components.d.ts +2 -2
- package/dist-types/components/consent-banner/policy-actions.d.ts +1 -1
- package/dist-types/components/consent-dialog/atoms/card.d.ts +5 -5
- package/dist-types/components/consent-dialog-trigger/atoms/toolbar.d.ts +22 -0
- package/dist-types/components/consent-dialog-trigger/consent-dialog-trigger-toolbar.d.ts +35 -0
- package/dist-types/components/consent-dialog-trigger/index.d.ts +2 -1
- package/dist-types/components/consent-dialog-trigger/types.d.ts +111 -6
- package/dist-types/components/consent-widget/atoms/accordion.d.ts +4 -4
- package/dist-types/components/consent-widget/consent-widget.d.ts +1 -1
- package/dist-types/components/consent-widget/policy-actions.d.ts +1 -1
- package/dist-types/components/integrations/google-map.d.ts +82 -0
- package/dist-types/components/integrations/index.d.ts +2 -0
- package/dist-types/components/integrations/shared.d.ts +12 -0
- package/dist-types/components/integrations/youtube-embed.d.ts +95 -0
- package/dist-types/components/shared/policy-actions.d.ts +1 -1
- package/dist-types/components/shared/primitives/button.d.ts +36 -2
- package/dist-types/components/shared/primitives/legal-links/index.d.ts +1 -1
- package/dist-types/components/shared/ui/accordion/accordion.d.ts +2 -2
- package/dist-types/components/shared/ui/branding.d.ts +3 -3
- package/dist-types/components/shared/ui/button/button.d.ts +1 -1
- package/dist-types/components/shared/ui/dialog/dialog.d.ts +1 -1
- package/dist-types/components/shared/ui/logo.d.ts +8 -8
- package/dist-types/headless.d.ts +1 -0
- package/dist-types/hooks/index.d.ts +1 -0
- package/dist-types/hooks/use-consent-script.d.ts +80 -0
- package/dist-types/index.d.ts +3 -1
- package/dist-types/providers/consent-manager-provider.d.ts +1 -1
- package/dist-types/server/headers.d.ts +1 -1
- package/dist-types/utils/theme-utils.d.ts +1 -1
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +155 -76
- package/docs/{building-headless-components.md → frameworks/react/building-headless-components.md} +3 -1
- package/docs/{callbacks.md → frameworks/react/callbacks.md} +3 -1
- package/docs/{components → frameworks/react/components}/consent-banner.md +10 -21
- package/docs/{components → frameworks/react/components}/consent-dialog-link.md +8 -5
- package/docs/frameworks/react/components/consent-dialog-trigger.md +202 -0
- package/docs/{components → frameworks/react/components}/consent-dialog.md +7 -15
- package/docs/frameworks/react/components/consent-manager-provider.md +228 -0
- package/docs/{components → frameworks/react/components}/consent-widget.md +8 -6
- package/docs/{components → frameworks/react/components}/dev-tools.md +9 -6
- package/docs/{components → frameworks/react/components}/frame.md +8 -9
- package/docs/{concepts → frameworks/react/concepts}/client-modes.md +4 -2
- package/docs/{concepts → frameworks/react/concepts}/consent-categories.md +1 -0
- package/docs/{concepts → frameworks/react/concepts}/consent-models.md +1 -0
- package/docs/{concepts → frameworks/react/concepts}/cookie-management.md +3 -3
- package/docs/{concepts → frameworks/react/concepts}/glossary.md +1 -0
- package/docs/{concepts → frameworks/react/concepts}/initialization-flow.md +1 -0
- package/docs/{concepts → frameworks/react/concepts}/policy-packs.md +1 -0
- package/docs/{headless.md → frameworks/react/headless.md} +3 -1
- package/docs/{hooks → frameworks/react/hooks}/use-color-scheme.md +1 -0
- package/docs/{hooks → frameworks/react/hooks}/use-consent-manager/checking-consent.md +3 -1
- package/docs/{hooks → frameworks/react/hooks}/use-consent-manager/location-info.md +3 -1
- package/docs/frameworks/react/hooks/use-consent-manager/overview.md +172 -0
- package/docs/{hooks → frameworks/react/hooks}/use-consent-manager/setting-consent.md +3 -1
- package/docs/{hooks → frameworks/react/hooks}/use-draggable.md +3 -1
- package/docs/{hooks → frameworks/react/hooks}/use-focus-trap.md +1 -0
- package/docs/{hooks → frameworks/react/hooks}/use-reduced-motion.md +3 -1
- package/docs/{hooks → frameworks/react/hooks}/use-ssr-status.md +6 -5
- package/docs/{hooks → frameworks/react/hooks}/use-text-direction.md +1 -0
- package/docs/frameworks/react/hooks/use-translations.md +55 -0
- package/docs/{iab → frameworks/react/iab}/consent-banner.md +9 -12
- package/docs/{iab → frameworks/react/iab}/consent-dialog.md +9 -14
- package/docs/{iab → frameworks/react/iab}/overview.md +4 -2
- package/docs/{iab → frameworks/react/iab}/use-gvl-data.md +3 -2
- package/docs/{iframe-blocking.md → frameworks/react/iframe-blocking.md} +8 -9
- package/docs/{internationalization.md → frameworks/react/internationalization.md} +13 -3
- package/docs/{network-blocker.md → frameworks/react/network-blocker.md} +13 -51
- package/docs/{optimization.md → frameworks/react/optimization.md} +3 -2
- package/docs/{policy-packs.md → frameworks/react/policy-packs.md} +3 -1
- package/docs/{quickstart.md → frameworks/react/quickstart.md} +26 -42
- package/docs/frameworks/react/script-loader.md +553 -0
- package/docs/{server-side.md → frameworks/react/server-side.md} +9 -4
- package/docs/{styling → frameworks/react/styling}/classnames.md +3 -1
- package/docs/{styling → frameworks/react/styling}/color-scheme.md +3 -1
- package/docs/frameworks/react/styling/css-variables.md +53 -0
- package/docs/frameworks/react/styling/overview.md +302 -0
- package/docs/frameworks/react/styling/slots.md +94 -0
- package/docs/{styling → frameworks/react/styling}/tailwind.md +3 -1
- package/docs/frameworks/react/styling/tokens.md +156 -0
- package/docs/{troubleshooting.md → frameworks/react/troubleshooting.md} +3 -1
- package/docs/integrations/adobe-analytics.md +160 -0
- package/docs/integrations/ahrefs-analytics.md +157 -0
- package/docs/integrations/amplitude.md +230 -0
- package/docs/integrations/building-integrations.md +15 -181
- package/docs/integrations/clearbit.md +130 -0
- package/docs/integrations/cloudflare-web-analytics.md +126 -0
- package/docs/integrations/crisp.md +140 -0
- package/docs/integrations/databuddy.md +152 -150
- package/docs/integrations/fathom-analytics.md +150 -0
- package/docs/integrations/google-maps.md +263 -0
- package/docs/integrations/google-tag-manager.md +102 -101
- package/docs/integrations/google-tag.md +104 -92
- package/docs/integrations/heap.md +219 -0
- package/docs/integrations/hightouch.md +199 -0
- package/docs/integrations/hotjar.md +143 -0
- package/docs/integrations/intercom.md +144 -0
- package/docs/integrations/linkedin-insights.md +142 -90
- package/docs/integrations/logrocket.md +175 -0
- package/docs/integrations/matomo-analytics.md +171 -0
- package/docs/integrations/meta-pixel.md +379 -309
- package/docs/integrations/microsoft-clarity.md +173 -0
- package/docs/integrations/microsoft-uet.md +135 -91
- package/docs/integrations/mixpanel-analytics.md +130 -0
- package/docs/integrations/overview.md +119 -75
- package/docs/integrations/pirsch.md +142 -0
- package/docs/integrations/plausible-analytics.md +154 -0
- package/docs/integrations/posthog.md +186 -127
- package/docs/integrations/promptwatch.md +121 -0
- package/docs/integrations/reddit-pixel.md +241 -0
- package/docs/integrations/rudderstack.md +271 -0
- package/docs/integrations/rybbit-analytics.md +143 -0
- package/docs/integrations/segment.md +146 -0
- package/docs/integrations/snapchat-pixel.md +163 -0
- package/docs/integrations/tiktok-pixel.md +101 -91
- package/docs/integrations/umami-analytics.md +148 -0
- package/docs/integrations/vercel-analytics.md +141 -0
- package/docs/integrations/x-pixel.md +123 -109
- package/docs/integrations/youtube.md +193 -0
- package/docs/shared/concepts/client-modes.md +103 -0
- package/docs/shared/concepts/consent-categories.md +41 -0
- package/docs/shared/concepts/consent-models.md +72 -0
- package/docs/shared/concepts/cookie-management.md +88 -0
- package/docs/shared/concepts/glossary.md +24 -0
- package/docs/shared/concepts/initialization-flow.md +105 -0
- package/docs/shared/concepts/policy-packs.md +225 -0
- package/docs/shared/react/components/consent-banner.md +242 -0
- package/docs/shared/react/components/consent-dialog-link.md +45 -0
- package/docs/shared/react/components/consent-dialog-trigger.md +185 -0
- package/docs/shared/react/components/consent-dialog.md +119 -0
- package/docs/shared/react/components/consent-manager-provider.md +183 -0
- package/docs/shared/react/components/consent-widget.md +121 -0
- package/docs/shared/react/components/dev-tools.md +81 -0
- package/docs/shared/react/components/frame.md +52 -0
- package/docs/shared/react/guides/building-headless-components.md +110 -0
- package/docs/shared/react/guides/callbacks.md +89 -0
- package/docs/shared/react/guides/headless.md +31 -0
- package/docs/shared/react/guides/iframe-blocking.md +65 -0
- package/docs/shared/react/guides/internationalization.md +123 -0
- package/docs/shared/react/guides/network-blocker.md +72 -0
- package/docs/shared/react/guides/optimization.md +44 -0
- package/docs/shared/react/guides/policy-packs.md +173 -0
- package/docs/shared/react/guides/script-loader.md +309 -0
- package/docs/shared/react/hooks/use-color-scheme.md +31 -0
- package/docs/shared/react/hooks/use-consent-manager/checking-consent.md +95 -0
- package/docs/shared/react/hooks/use-consent-manager/location-info.md +96 -0
- package/docs/shared/react/hooks/use-consent-manager/overview.md +74 -0
- package/docs/shared/react/hooks/use-consent-manager/setting-consent.md +93 -0
- package/docs/shared/react/hooks/use-draggable.md +30 -0
- package/docs/shared/react/hooks/use-focus-trap.md +20 -0
- package/docs/shared/react/hooks/use-reduced-motion.md +33 -0
- package/docs/shared/react/hooks/use-ssr-status.md +16 -0
- package/docs/shared/react/hooks/use-text-direction.md +38 -0
- package/docs/shared/react/hooks/use-translations.md +15 -0
- package/docs/shared/react/iab/consent-banner.md +60 -0
- package/docs/shared/react/iab/consent-dialog.md +76 -0
- package/docs/shared/react/iab/overview.md +80 -0
- package/docs/shared/react/iab/use-gvl-data.md +21 -0
- package/docs/shared/react/styling/classnames.md +93 -0
- package/docs/shared/react/styling/color-scheme.md +35 -0
- package/docs/shared/react/styling/css-variables.md +53 -0
- package/docs/shared/react/styling/overview.md +261 -0
- package/docs/shared/react/styling/slots.md +93 -0
- package/docs/shared/react/styling/stylesheet-entrypoint.md +8 -0
- package/docs/shared/react/styling/tailwind.md +88 -0
- package/docs/shared/react/styling/tokens.md +155 -0
- package/docs/shared/troubleshooting.md +82 -0
- package/package.json +23 -12
- package/readme.json +12 -7
- package/docs/ai-agents.md +0 -111
- package/docs/components/consent-dialog-trigger.md +0 -103
- package/docs/components/consent-manager-provider.md +0 -425
- package/docs/hooks/use-consent-manager/overview.md +0 -420
- package/docs/hooks/use-translations.md +0 -118
- package/docs/script-loader.md +0 -321
- package/docs/styling/css-variables.md +0 -92
- package/docs/styling/overview.md +0 -460
- package/docs/styling/slots.md +0 -128
- package/docs/styling/tokens.md +0 -216
|
@@ -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:
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Policy Packs
|
|
3
|
+
description: Reference page for policy packs.
|
|
4
|
+
group: reference
|
|
5
|
+
---
|
|
6
|
+
Policy packs configure how c15t handles regional consent — which model (opt-in, opt-out, none), which categories, and what UI to show. The backend resolves the right policy automatically based on the visitor's location.
|
|
7
|
+
|
|
8
|
+
**For most apps, you just need a `ConsentManagerProvider` pointing at your backend with presets configured there.** The frontend receives the resolved policy via the `/init` response — no client-side policy config required.
|
|
9
|
+
|
|
10
|
+
When a backend isn't available — local development, static previews, Storybook, automated tests, or as a resilience fallback during a temporary outage — you can pass policies directly to the provider via `offlinePolicy.policyPacks` and c15t resolves them locally.
|
|
11
|
+
|
|
12
|
+
> ℹ️ **Info:**
|
|
13
|
+
> For QA and testing, use the c15t DevTools to simulate different regions and policy responses against your real backend, rather than switching to offline mode.
|
|
14
|
+
|
|
15
|
+
## Hosted Mode (Recommended)
|
|
16
|
+
|
|
17
|
+
When using inth.com or a self-hosted backend, the provider connects automatically. No policy configuration is needed on the frontend:
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
<ConsentManagerProvider
|
|
21
|
+
options={{
|
|
22
|
+
backendURL: 'https://your-instance.c15t.dev',
|
|
23
|
+
}}
|
|
24
|
+
>
|
|
25
|
+
<ConsentBanner />
|
|
26
|
+
<ConsentDialog />
|
|
27
|
+
{children}
|
|
28
|
+
</ConsentManagerProvider>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The backend resolves the correct policy based on the visitor's geo data and returns it in the `/init` response. Configure your presets on the backend side.
|
|
32
|
+
|
|
33
|
+
## Offline Presets (Development and Fallback)
|
|
34
|
+
|
|
35
|
+
Use offline presets mainly for local development, Storybook, deterministic tests, or temporary backend outages:
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { policyPackPresets } from '@c15t/react';
|
|
39
|
+
|
|
40
|
+
offlinePolicy: {
|
|
41
|
+
i18n: {
|
|
42
|
+
defaultProfile: 'default',
|
|
43
|
+
messages: {
|
|
44
|
+
default: {
|
|
45
|
+
translations: {
|
|
46
|
+
en: { cookieBanner: { title: 'Privacy choices' } },
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
eu: {
|
|
50
|
+
fallbackLanguage: 'en',
|
|
51
|
+
translations: {
|
|
52
|
+
en: { cookieBanner: { title: 'EU GDPR Consent' } },
|
|
53
|
+
fr: { cookieBanner: { title: 'Consentement RGPD' } },
|
|
54
|
+
de: { cookieBanner: { title: 'GDPR-Einwilligung' } },
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
policyPacks: [
|
|
60
|
+
{
|
|
61
|
+
...policyPackPresets.europeOptIn(),
|
|
62
|
+
i18n: { messageProfile: 'eu' },
|
|
63
|
+
},
|
|
64
|
+
policyPackPresets.californiaOptOut(),
|
|
65
|
+
policyPackPresets.worldNoBanner(),
|
|
66
|
+
],
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Available presets:
|
|
71
|
+
|
|
72
|
+
|Preset|Model|Matches|
|
|
73
|
+
|--|--|--|
|
|
74
|
+
|`europeOptIn()`|`opt-in`|EEA + UK countries + geo fallback|
|
|
75
|
+
|`europeIab()`|`iab`|EEA + UK countries + geo fallback (TCF 2.3)|
|
|
76
|
+
|`californiaOptOut()`|`opt-out`|US-CA region|
|
|
77
|
+
|`quebecOptIn()`|`opt-in`|CA-QC region|
|
|
78
|
+
|`worldNoBanner()`|`none`|default fallback|
|
|
79
|
+
|
|
80
|
+
## Provider Shape
|
|
81
|
+
|
|
82
|
+
Configure packs through `offlinePolicy.policyPacks`. Add `offlinePolicy.i18n`
|
|
83
|
+
when you want local previews or fallback behavior to mirror hosted policy-profile language behavior:
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
<ConsentManagerProvider
|
|
87
|
+
options={{
|
|
88
|
+
mode: 'offline',
|
|
89
|
+
offlinePolicy: {
|
|
90
|
+
i18n: {
|
|
91
|
+
defaultProfile: 'default',
|
|
92
|
+
messages: {
|
|
93
|
+
default: {
|
|
94
|
+
translations: {
|
|
95
|
+
en: { cookieBanner: { title: 'Privacy choices' } },
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
qc: {
|
|
99
|
+
fallbackLanguage: 'fr',
|
|
100
|
+
translations: {
|
|
101
|
+
en: { cookieBanner: { title: 'Quebec Privacy Settings' } },
|
|
102
|
+
fr: { cookieBanner: { title: 'Paramètres de confidentialité du Québec' } },
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
policyPacks: [
|
|
108
|
+
{
|
|
109
|
+
id: 'qc_opt_in',
|
|
110
|
+
match: { regions: [{ country: 'CA', region: 'QC' }] },
|
|
111
|
+
i18n: { messageProfile: 'qc' },
|
|
112
|
+
consent: { model: 'opt-in', expiryDays: 365 },
|
|
113
|
+
ui: { mode: 'banner' },
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'default',
|
|
117
|
+
match: { isDefault: true },
|
|
118
|
+
consent: { model: 'none' },
|
|
119
|
+
ui: { mode: 'none' },
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
overrides: { country: 'CA', region: 'QC' },
|
|
124
|
+
}}
|
|
125
|
+
>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
With that setup, offline mode resolves language the same way as hosted mode:
|
|
129
|
+
|
|
130
|
+
* the active policy profile defines the allowed language set
|
|
131
|
+
* each profile can define its own `fallbackLanguage`
|
|
132
|
+
* built-in translations only fill missing keys for the selected language
|
|
133
|
+
|
|
134
|
+
## Fallback Behavior
|
|
135
|
+
|
|
136
|
+
|Configuration|Result|
|
|
137
|
+
|--|--|
|
|
138
|
+
|`offlinePolicy.policyPacks` omitted|Synthetic opt-in fallback banner (also used for hosted network fallback)|
|
|
139
|
+
|`offlinePolicy: { policyPacks: [] }`|Explicit no-banner mode|
|
|
140
|
+
|Non-empty pack, no match, no default|Explicit no-banner mode|
|
|
141
|
+
|
|
142
|
+
Omitting the option gives you a safe opt-in default for local development and outage scenarios. Providing it tells c15t you want deterministic preview or fallback behavior exactly as configured.
|
|
143
|
+
|
|
144
|
+
## QA and Debugging
|
|
145
|
+
|
|
146
|
+
The best way to test regional consent behavior is with the [c15t DevTools](/docs/frameworks/react/dev-tools). The DevTools Policy panel lets you simulate different countries, regions, and GPC signals against your real backend — no code changes needed.
|
|
147
|
+
|
|
148
|
+
For deeper inspection:
|
|
149
|
+
|
|
150
|
+
* Read `policy` and `policyDecision` from `useConsentManager()` to see the resolved config
|
|
151
|
+
* Open the DevTools Policy panel to inspect matcher resolution and fingerprints
|
|
152
|
+
* Compare your frontend preview with the backend `/init` response before shipping
|
|
153
|
+
|
|
154
|
+
If you need fully deterministic resolution without a backend during testing or preview work (for example, in automated tests or Storybook), pair `offlinePolicy.policyPacks` with `overrides`:
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
options={{
|
|
158
|
+
mode: 'offline',
|
|
159
|
+
offlinePolicy: {
|
|
160
|
+
policyPacks: [
|
|
161
|
+
policyPackPresets.europeOptIn(),
|
|
162
|
+
policyPackPresets.californiaOptOut(),
|
|
163
|
+
policyPackPresets.worldNoBanner(),
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
overrides: {
|
|
167
|
+
country: 'US',
|
|
168
|
+
region: 'CA',
|
|
169
|
+
language: 'en-US',
|
|
170
|
+
gpc: true, // Simulate Global Privacy Control
|
|
171
|
+
},
|
|
172
|
+
}}
|
|
173
|
+
```
|