@c15t/react 3.0.0-alpha.0 → 3.0.0-alpha.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.
- package/AGENTS.md +4 -1
- package/dist/aggregate-components.js +1 -1
- package/dist/component-hooks/use-manager.js +1 -1
- package/dist/components/consent-gate/atoms.js +1 -0
- package/dist/components/consent-gate/consent-gate.js +2 -0
- package/dist/components/consent-gate/index.js +2 -0
- package/dist/components/preferences/atoms/accordion.js +1 -1
- package/dist/components/preferences/atoms/vendor-list.js +1 -0
- package/dist/components/preferences/index.js +1 -1
- package/dist/consent-gate.js +2 -0
- package/dist/draft.js +1 -1
- package/dist/external-iab-context.js +1 -1
- package/dist/hooks.js +1 -1
- package/dist/iab/styles.tw3.css +4 -110
- package/dist/index.js +1 -1
- package/dist/provider.js +1 -1
- package/dist/styles.tw3.css +10 -113
- package/dist/utils/deferred-module.js +2 -0
- package/dist/version.js +1 -1
- package/dist-types/aggregate-components.d.ts +2 -2
- package/dist-types/component-hooks/use-headless-iab-consent-ui.d.ts +1 -1
- package/dist-types/component-hooks/use-manager.d.ts +6 -1
- package/dist-types/components/consent-gate/atoms.d.ts +11 -0
- package/dist-types/components/consent-gate/consent-gate.d.ts +2 -0
- package/dist-types/components/consent-gate/index.d.ts +41 -0
- package/dist-types/components/{frame → consent-gate}/types.d.ts +7 -7
- package/dist-types/components/consent-preferences-link/consent-preferences-link.d.ts +1 -1
- package/dist-types/components/consent-preferences-link/index.d.ts +1 -1
- package/dist-types/components/iab-panel/atoms/purpose-item.d.ts +1 -1
- package/dist-types/components/iab-panel/atoms/stack-item.d.ts +1 -1
- package/dist-types/components/iab-panel/atoms/vendor-list.d.ts +1 -1
- package/dist-types/components/iab-panel/iab-panel.d.ts +1 -1
- package/dist-types/components/iab-panel/index.d.ts +24 -24
- package/dist-types/components/iab-prompt/index.d.ts +17 -17
- package/dist-types/components/panel/atoms/card.d.ts +4 -4
- package/dist-types/components/panel/atoms/overlay.d.ts +1 -1
- package/dist-types/components/panel/index.d.ts +7 -7
- package/dist-types/components/panel/panel.d.ts +2 -2
- package/dist-types/components/panel-link/index.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/button.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/icon.d.ts +1 -1
- package/dist-types/components/panel-trigger/atoms/root.d.ts +2 -2
- package/dist-types/components/panel-trigger/atoms/toolbar.d.ts +2 -2
- package/dist-types/components/panel-trigger/index.d.ts +4 -4
- package/dist-types/components/panel-trigger/panel-trigger-toolbar.d.ts +1 -1
- package/dist-types/components/panel-trigger/panel-trigger.d.ts +9 -9
- package/dist-types/components/panel-trigger/types.d.ts +1 -1
- package/dist-types/components/preferences/atoms/accordion.d.ts +6 -4
- package/dist-types/components/preferences/atoms/button.d.ts +1 -1
- package/dist-types/components/preferences/atoms/footer.d.ts +1 -1
- package/dist-types/components/preferences/atoms/root.d.ts +1 -1
- package/dist-types/components/preferences/atoms/vendor-list.d.ts +23 -0
- package/dist-types/components/preferences/index.d.ts +13 -11
- package/dist-types/components/preferences/policy-actions.d.ts +2 -2
- package/dist-types/components/preferences/preferences.d.ts +1 -1
- package/dist-types/components/preferences/types.d.ts +1 -1
- package/dist-types/components/prompt/components.d.ts +3 -3
- package/dist-types/components/prompt/index.d.ts +11 -11
- package/dist-types/components/prompt/policy-actions.d.ts +2 -2
- package/dist-types/components/prompt/prompt.d.ts +1 -1
- package/dist-types/components/shared/policy-actions.d.ts +2 -2
- package/dist-types/components/shared/primitives/box.d.ts +1 -1
- package/dist-types/components/shared/primitives/button.d.ts +2 -2
- package/dist-types/components/shared/primitives/button.types.d.ts +1 -1
- package/dist-types/components/shared/ui/accordion/accordion.d.ts +2 -2
- package/dist-types/components/shared/ui/accordion/index.d.ts +2 -2
- package/dist-types/components/shared/ui/animated-collapse/index.d.ts +2 -2
- package/dist-types/components/shared/ui/branding.d.ts +1 -1
- package/dist-types/components/shared/ui/button/button.d.ts +1 -1
- package/dist-types/components/shared/ui/button/index.d.ts +2 -2
- package/dist-types/components/shared/ui/collapsible/index.d.ts +1 -1
- package/dist-types/components/shared/ui/dialog/index.d.ts +1 -1
- package/dist-types/components/shared/ui/preference-item/index.d.ts +1 -1
- package/dist-types/components/shared/ui/switch/index.d.ts +2 -2
- package/dist-types/components/shared/ui/switch/switch.d.ts +1 -1
- package/dist-types/components/shared/ui/tabs/index.d.ts +1 -1
- package/dist-types/consent-gate.d.ts +1 -0
- package/dist-types/context/index.d.ts +3 -3
- package/dist-types/context/theme-context.d.ts +1 -1
- package/dist-types/draft.d.ts +53 -1
- package/dist-types/headless.d.ts +7 -7
- package/dist-types/hooks/use-headless-iab-consent-ui.d.ts +1 -1
- package/dist-types/hooks/use-iab-manager.d.ts +1 -1
- package/dist-types/hooks/use-theme.d.ts +1 -1
- package/dist-types/hooks.d.ts +28 -1
- package/dist-types/iab.d.ts +5 -5
- package/dist-types/index.d.ts +25 -25
- package/dist-types/module-hooks.d.ts +4 -4
- package/dist-types/panel-link.d.ts +1 -1
- package/dist-types/panel-trigger.d.ts +1 -1
- package/dist-types/panel.d.ts +1 -1
- package/dist-types/preferences.d.ts +1 -1
- package/dist-types/primitives/accordion.d.ts +1 -1
- package/dist-types/primitives/button.d.ts +1 -1
- package/dist-types/primitives/collapsible.d.ts +1 -1
- package/dist-types/primitives/dialog.d.ts +1 -1
- package/dist-types/primitives/preference-item.d.ts +1 -1
- package/dist-types/primitives/switch.d.ts +1 -1
- package/dist-types/primitives/tabs.d.ts +1 -1
- package/dist-types/primitives.d.ts +7 -7
- package/dist-types/prompt.d.ts +1 -1
- package/dist-types/provider.d.ts +27 -5
- package/dist-types/server/fetch-ssr-data.d.ts +1 -1
- package/dist-types/server/index.d.ts +5 -5
- package/dist-types/theme-provider.d.ts +2 -2
- package/dist-types/types/index.d.ts +3 -3
- package/dist-types/types/manager.d.ts +1 -1
- package/dist-types/types/theme/index.d.ts +1 -1
- package/dist-types/ui-config-context.d.ts +1 -1
- package/dist-types/utils/deferred-module.d.ts +11 -0
- package/dist-types/utils/index.d.ts +4 -4
- package/dist-types/utils/merge-slot-props.d.ts +2 -2
- package/dist-types/utils/merge-styles.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 +4 -1
- package/docs/frameworks/react/components/consent-dialog.md +1 -1
- package/docs/frameworks/react/components/{frame.md → consent-gate.md} +27 -27
- package/docs/frameworks/react/components/consent-manager-provider.md +14 -1
- package/docs/frameworks/react/components/consent-widget.md +39 -6
- package/docs/frameworks/react/concepts/consent-categories.md +31 -2
- package/docs/frameworks/react/script-loader.md +8 -0
- package/docs/frameworks/react/styling/overview.md +10 -0
- package/docs/guides/deployment-modes.md +12 -0
- package/docs/integrations/building-integrations.md +5 -0
- package/docs/integrations/clear-on-revocation.md +167 -0
- package/docs/integrations/cloudflare-zaraz.md +399 -0
- package/docs/integrations/google-maps.md +20 -20
- package/docs/integrations/granular-consent.md +208 -0
- package/docs/integrations/overview.md +5 -4
- package/docs/integrations/youtube.md +26 -21
- package/docs/upgrade-v3.md +47 -0
- package/package.json +26 -16
- package/dist/components/frame/atoms.js +0 -1
- package/dist/components/frame/frame.js +0 -2
- package/dist/components/frame/index.js +0 -2
- package/dist/frame.js +0 -2
- package/dist-types/components/frame/atoms.d.ts +0 -11
- package/dist-types/components/frame/frame.d.ts +0 -2
- package/dist-types/components/frame/index.d.ts +0 -24
- package/dist-types/frame.d.ts +0 -1
- package/readme.json +0 -48
- package/src/iab/styles.css +0 -11
- package/src/styles.css +0 -10
- /package/dist/components/{frame → consent-gate}/types.js +0 -0
|
@@ -85,6 +85,28 @@ Privacy Control overrides shows a note under its row: "Your saved choice is
|
|
|
85
85
|
restricted by the current privacy settings." The switch still reflects the
|
|
86
86
|
saved value; the effective permission is off.
|
|
87
87
|
|
|
88
|
+
### Vendors
|
|
89
|
+
|
|
90
|
+
When the provider declares `vendors`, each category's expanded description
|
|
91
|
+
ends with one card per vendor whose category condition names that category,
|
|
92
|
+
styled like a category row: the vendor's name and a switch on the header,
|
|
93
|
+
and its description and privacy policy link behind the card's own expand
|
|
94
|
+
control. Cards start collapsed, so a long list stays one line per vendor,
|
|
95
|
+
and the category list scrolls inside the dialog rather than growing it.
|
|
96
|
+
Vendor switches edit the same draft as the category
|
|
97
|
+
switches and record on Save. Saving with one vendor off denies that vendor
|
|
98
|
+
only; the category stays granted and its other vendors keep loading. While
|
|
99
|
+
the category is off in the draft the vendor switches are disabled, with the
|
|
100
|
+
hint "Turn on this category to choose vendors." A vendor declared
|
|
101
|
+
`disabled`, or one that only falls under `necessary`, is listed without a
|
|
102
|
+
switch. Accept all and Reject all clear every vendor denial, including one
|
|
103
|
+
staged but not yet saved. Under an `iab` policy no vendor rows render.
|
|
104
|
+
Vendors that are only referenced by a script slug, without a name and
|
|
105
|
+
privacy policy URL, still gate loading but are not listed, and so does a
|
|
106
|
+
vendor whose condition negates a category, since no category row can
|
|
107
|
+
host it. See
|
|
108
|
+
[granular consent](../../../integrations/granular-consent.md).
|
|
109
|
+
|
|
88
110
|
### Actions
|
|
89
111
|
|
|
90
112
|
The preference center always renders Reject all, Accept all and Save, with
|
|
@@ -102,8 +124,12 @@ such as `['disclosure']`, renders the widget and Save completes without
|
|
|
102
124
|
writing a consent record.
|
|
103
125
|
|
|
104
126
|
For a fully custom preference center, `useConsentDraft()` returns the same
|
|
105
|
-
draft: `values`, `displayedCategories`, `
|
|
106
|
-
`update`, `acceptAll`, `rejectAll`, `save` and `reset`.
|
|
127
|
+
draft: `values`, `displayedCategories`, `vendors`, `isDirty`, `isStale`,
|
|
128
|
+
`set`, `update`, `setVendor`, `acceptAll`, `rejectAll`, `save` and `reset`.
|
|
129
|
+
A custom vendor control alone takes `useVendorDraft()`, the vendor slice of
|
|
130
|
+
that draft: `vendors`, `setVendor`, `isDirty`, `isStale`, `save` and `reset`.
|
|
131
|
+
`useDeclaredVendors()`, `useVendorChoice()` and `useVendorAllowed(id)` read
|
|
132
|
+
the declared list, the recorded denials and one vendor's effective result.
|
|
107
133
|
|
|
108
134
|
`useConsentDraft` and `ConsentDraftProvider` import from `c15t/react`.
|
|
109
135
|
|
|
@@ -112,7 +138,10 @@ draft: `values`, `displayedCategories`, `isDirty`, `isStale`, `set`,
|
|
|
112
138
|
Each row is a disclosure: a button that expands the category description
|
|
113
139
|
and a switch beside it, so a visitor can read the description without
|
|
114
140
|
changing the choice. Each switch has the category title as its accessible
|
|
115
|
-
name.
|
|
141
|
+
name. A category's vendor cards sit in a `region` named "Vendors" with the
|
|
142
|
+
count; each card's expand button carries `aria-expanded`, each vendor
|
|
143
|
+
switch is named "Allow" followed by the vendor name, and is described by
|
|
144
|
+
the vendor's name element. The policy-change alert uses `role="alert"`, and a restriction note is
|
|
116
145
|
an `output` element linked to its switch through `aria-describedby`. The
|
|
117
146
|
root's `dir` attribute follows the active language.
|
|
118
147
|
|
|
@@ -122,7 +151,8 @@ Every part is available as `ConsentWidget.<Part>`. `Root` provides the
|
|
|
122
151
|
draft and accepts `noStyle`, `disableAnimation` and `uiSource`. `Accordion`
|
|
123
152
|
and `AccordionItems` render the stock rows; `AccordionItem`,
|
|
124
153
|
`AccordionTrigger`, `AccordionTriggerInner`, `AccordionContent`,
|
|
125
|
-
`AccordionArrow` and `Switch` build your own
|
|
154
|
+
`AccordionArrow` and `Switch` build your own; `VendorList` renders one
|
|
155
|
+
category's vendor rows and takes a `category` prop. `PolicyActions` renders the
|
|
126
156
|
resolved actions in `Footer` and `FooterSubGroup` and accepts `renderAction`
|
|
127
157
|
to replace one button; `AcceptAllButton`, `RejectButton`, `SaveButton` and
|
|
128
158
|
`CustomizeButton` are the individual buttons.
|
|
@@ -155,8 +185,11 @@ export function PreferenceCenter() {
|
|
|
155
185
|
Provider component slots for the stock structure are `manager.root`,
|
|
156
186
|
`manager.footer`, `manager.actionGroup`, `accordion.root`,
|
|
157
187
|
`accordion.triggerRow`, `accordion.title`, `accordion.control`,
|
|
158
|
-
`accordion-item.root`, `accordion-item.trigger`, `accordion-item.content
|
|
159
|
-
|
|
188
|
+
`accordion-item.root`, `accordion-item.trigger`, `accordion-item.content`,
|
|
189
|
+
`vendor-list.root`, `vendor-list.trigger`, `vendor-list.content`,
|
|
190
|
+
`vendor-list.item`, `vendor-list.header`,
|
|
191
|
+
`vendor-list.name`, `vendor-list.description`, `vendor-list.link`,
|
|
192
|
+
`vendor-list.control` and `tag.manager`.
|
|
160
193
|
|
|
161
194
|
The compound parts import from `c15t/react` as properties of `ConsentWidget`.
|
|
162
195
|
See [Styling](../styling/overview.md) for slots and tokens.
|
|
@@ -17,8 +17,23 @@ group: frameworks
|
|
|
17
17
|
|
|
18
18
|
`necessary` is always permitted. Assign categories based on what an integration
|
|
19
19
|
does in your application; renaming analytics to necessary does not change its
|
|
20
|
-
purpose.
|
|
21
|
-
|
|
20
|
+
purpose.
|
|
21
|
+
|
|
22
|
+
c15t discovers categories from registered scripts, network rules, React `ConsentGate`
|
|
23
|
+
components, and iframes with `data-category` handled by the iframe blocker.
|
|
24
|
+
The browser client also discovers inert scripts tagged with `data-c15t-category`.
|
|
25
|
+
Compound script and network conditions contribute every category they reference.
|
|
26
|
+
|
|
27
|
+
Discovered categories are added to `consentCategories`, when supplied. The dialog
|
|
28
|
+
always includes Necessary and offers the optional categories in that combined
|
|
29
|
+
set that are also in the resolved policy scope. Choice completion uses the same
|
|
30
|
+
set. If neither configuration nor integrations supply categories, the dialog
|
|
31
|
+
uses the full policy scope.
|
|
32
|
+
|
|
33
|
+
Categories discovered later are added immediately and retained until the provider
|
|
34
|
+
or runtime is recreated. Adding a category can require a new choice; removing a
|
|
35
|
+
script or unmounting a frame does not remove its category or erase consent.
|
|
36
|
+
Discovery does not grant consent or change backend permission restrictions.
|
|
22
37
|
|
|
23
38
|
## Respect policy scope
|
|
24
39
|
|
|
@@ -28,6 +43,20 @@ only some optional categories, set `scopeMode` explicitly. An omitted scope,
|
|
|
28
43
|
`['*']`, or a list containing only `necessary` expands to the default optional
|
|
29
44
|
categories; a necessary-only list is not a shortcut for disabling all tracking.
|
|
30
45
|
|
|
46
|
+
For example, a backend rule with `categories: ['necessary']` and scripts assigned
|
|
47
|
+
to `marketing` and `measurement` displays Necessary, Marketing, and Analytics,
|
|
48
|
+
even without `consentCategories`. Accept All records both optional choices and
|
|
49
|
+
keeps the banner dismissed after reload. An explicit list of
|
|
50
|
+
`['necessary', 'measurement']` with no other integrations displays Necessary and
|
|
51
|
+
Analytics.
|
|
52
|
+
|
|
53
|
+
Hidden optional categories do not need a choice to dismiss the banner. Their
|
|
54
|
+
permissions still follow the backend policy, so hidden opt-in categories remain
|
|
55
|
+
denied without a valid grant. React providers enable DOM iframe blocking and
|
|
56
|
+
discovery by default; set `iframeBlocker: false` to disable it, or
|
|
57
|
+
`iframeBlocker: { disableAutomaticBlocking: true }` to scan manually with
|
|
58
|
+
`useIframeBlocker({ disableAutomaticBlocking: true }).processAllIframes()`.
|
|
59
|
+
|
|
31
60
|
Use effective permissions to gate work and explicit choices to inspect what the
|
|
32
61
|
visitor confirmed. Read [consent state](../../../guides/consent-state.md) for that
|
|
33
62
|
distinction and [migration](../../../upgrade-v3.md) for v3 policy configuration.
|
|
@@ -53,3 +53,11 @@ Use [custom integrations](../../integrations/building-integrations.md) for an
|
|
|
53
53
|
unlisted vendor and [verification](../../guides/verify-consent.md) for the network
|
|
54
54
|
checks. Google helpers have a separate
|
|
55
55
|
[Consent Mode contract](../../integrations/google-tag-manager.md).
|
|
56
|
+
|
|
57
|
+
## Clear stored tracking data
|
|
58
|
+
|
|
59
|
+
Script gating does not remove cookies or Web Storage entries that a script
|
|
60
|
+
already wrote. Add `clearOnRevocation` to `ConsentProvider.options` to remove
|
|
61
|
+
declared data when its category is denied. See
|
|
62
|
+
[clear on revocation](../../integrations/clear-on-revocation.md) for configuration
|
|
63
|
+
and browser limits.
|
|
@@ -37,6 +37,16 @@ Colors, radii, shadows, typography, and motion come from `--c15t-*` custom
|
|
|
37
37
|
properties. Set them on the provider through `theme`, or override the
|
|
38
38
|
variables directly in your CSS.
|
|
39
39
|
|
|
40
|
+
React and Next.js render the theme stylesheet in the server HTML before
|
|
41
|
+
the banner. Pass the same theme on the server and the first client render
|
|
42
|
+
so your custom tokens apply before hydration. The provider's `nonce`
|
|
43
|
+
option also applies to this stylesheet for Content Security Policy.
|
|
44
|
+
|
|
45
|
+
`colorScheme: 'dark'` applies dark tokens in the server HTML.
|
|
46
|
+
`colorScheme: 'system'` uses a CSS media query to follow the visitor's
|
|
47
|
+
preference before hydration. If your app manages dark mode through a
|
|
48
|
+
root class instead, include that class in the server HTML too.
|
|
49
|
+
|
|
40
50
|
```tsx
|
|
41
51
|
import { ConsentProvider, defineTheme } from 'c15t/react';
|
|
42
52
|
|
|
@@ -30,6 +30,18 @@ in your application while consent writes still go to Inth. Regular backend
|
|
|
30
30
|
browser setup. See [data fetching and transports](./data-fetching.md) for
|
|
31
31
|
the comparison, including custom transports and offline mode.
|
|
32
32
|
|
|
33
|
+
Manifest resolution removes the per-visitor `/init` request, and with it the
|
|
34
|
+
backend's only count of visitors. The server adapters replace it with a session
|
|
35
|
+
report: after each resolution, on a server-rendered page or the same-origin
|
|
36
|
+
init route, the host posts a small report to the backend's `POST /sessions`,
|
|
37
|
+
server-to-server and detached from the response. The browser makes no request
|
|
38
|
+
and the report stores no identity; the visitor's IP and user agent travel as
|
|
39
|
+
forwarded headers under the backend's usual IP handling. Each report is one
|
|
40
|
+
resolution; a page view can produce a `render` and a `route` report, and the
|
|
41
|
+
consuming side groups them into sessions by address and user agent within a
|
|
42
|
+
window. Static output resolves in the browser and sends none. Set `reportSessions: false` on an adapter to turn
|
|
43
|
+
it off.
|
|
44
|
+
|
|
33
45
|
## Match initialization to your application output
|
|
34
46
|
|
|
35
47
|
| Application output | Initial state | Required setup |
|
|
@@ -31,6 +31,11 @@ Replace the example URL and implement the vendor's initialization. This is a
|
|
|
31
31
|
loader template, not a functioning analytics SDK. The script stays blocked
|
|
32
32
|
while measurement permission is denied.
|
|
33
33
|
|
|
34
|
+
Add `vendor: 'example-analytics'` and declare the vendor in the runtime's
|
|
35
|
+
`vendors` option or in the backend manifest when visitors should be able to
|
|
36
|
+
turn this vendor off inside a granted category. See
|
|
37
|
+
[granular consent](./granular-consent.md).
|
|
38
|
+
|
|
34
39
|
## Define revocation deliberately
|
|
35
40
|
|
|
36
41
|
`onConsentChange` receives current permission information. Use it to update the
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Clear on revocation
|
|
3
|
+
description: Remove configured first-party cookies and Web Storage keys when
|
|
4
|
+
their consent category is denied.
|
|
5
|
+
group: integrations
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Configure cleanup
|
|
9
|
+
|
|
10
|
+
Add `clearOnRevocation` to your provider or runtime options. Declare only the
|
|
11
|
+
data owned by each optional category:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { hosted, type ClearOnRevocationConfig } from 'c15t';
|
|
15
|
+
import { createConsentRuntime } from 'c15t/runtime';
|
|
16
|
+
|
|
17
|
+
const clearOnRevocation = {
|
|
18
|
+
measurement: {
|
|
19
|
+
cookies: ['_ga', '_ga_*'],
|
|
20
|
+
localStorage: ['analytics:*'],
|
|
21
|
+
},
|
|
22
|
+
marketing: {
|
|
23
|
+
cookies: ['_fbp'],
|
|
24
|
+
sessionStorage: ['campaign-id'],
|
|
25
|
+
},
|
|
26
|
+
} satisfies ClearOnRevocationConfig;
|
|
27
|
+
|
|
28
|
+
const runtime = createConsentRuntime({
|
|
29
|
+
mode: hosted({ url: '/api/c15t' }),
|
|
30
|
+
clearOnRevocation,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Start in the browser after mount. The endpoint must serve your c15t backend.
|
|
34
|
+
runtime.start();
|
|
35
|
+
|
|
36
|
+
// Call runtime.dispose() when the app no longer needs consent management.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For React, pass the same configuration through `ConsentProvider.options`:
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import type { ReactNode } from 'react';
|
|
43
|
+
import { ConsentProvider, hosted } from 'c15t/react';
|
|
44
|
+
|
|
45
|
+
const mode = hosted({ url: '/api/c15t' });
|
|
46
|
+
|
|
47
|
+
export function Consent({ children }: { children: ReactNode }) {
|
|
48
|
+
return (
|
|
49
|
+
<ConsentProvider
|
|
50
|
+
options={{
|
|
51
|
+
mode,
|
|
52
|
+
clearOnRevocation: {
|
|
53
|
+
measurement: { cookies: ['_ga', '_ga_*'] },
|
|
54
|
+
},
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
57
|
+
{children}
|
|
58
|
+
</ConsentProvider>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The same option is available in Next.js and TanStack Start `ConsentRoot` props, Vue and
|
|
64
|
+
Nuxt configuration, Svelte providers, and Astro integration options. Solid and
|
|
65
|
+
other headless integrations can use `createConsentRuntime` as shown above.
|
|
66
|
+
Every adapter uses the same cleanup module.
|
|
67
|
+
|
|
68
|
+
Omitting `clearOnRevocation` leaves cleanup disabled. The provider option is
|
|
69
|
+
initial-only. Remount the provider to replace its cleanup configuration. For
|
|
70
|
+
a shared runtime, configure the runtime owner rather than a borrowing provider.
|
|
71
|
+
|
|
72
|
+
## Matching names and cookie scopes
|
|
73
|
+
|
|
74
|
+
Use an exact string or a nonempty prefix followed by `*`. `_ga_*` matches
|
|
75
|
+
`_ga_ABC123`; it does not match `_ga`. Regular expressions, wildcards in other
|
|
76
|
+
positions, and a bare `*` are unsupported. Web Storage keys may contain spaces,
|
|
77
|
+
Unicode, and punctuation. Cookie names use their raw spelling, without URL
|
|
78
|
+
decoding.
|
|
79
|
+
|
|
80
|
+
Cookies can share a name while having different domains or paths. Cleanup
|
|
81
|
+
tries the current host and its parent domains, and the current path and its
|
|
82
|
+
ancestors. To target a specific scope, use an object:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const clearOnRevocation = {
|
|
86
|
+
measurement: {
|
|
87
|
+
cookies: [
|
|
88
|
+
{ name: 'analytics-id', domain: 'example.com', path: '/' },
|
|
89
|
+
{ name: 'checkout-metrics', domain: '', path: '/checkout' },
|
|
90
|
+
{ name: 'partitioned-metrics', partitioned: true },
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
An empty `domain` means host-only. Explicit domains and paths replace the
|
|
97
|
+
automatic attempts for that field. Exact names can be deleted at a configured
|
|
98
|
+
path even when the current page cannot read that cookie. Prefix matching can
|
|
99
|
+
only discover cookie names visible to the current page, so use an exact name
|
|
100
|
+
for a cookie on another path.
|
|
101
|
+
|
|
102
|
+
Partitioned cookies require `partitioned: true`; ordinary targets remove
|
|
103
|
+
unpartitioned cookies. Cookie deletion preserves the browser's `__Secure-`
|
|
104
|
+
and `__Host-` prefix requirements. c15t protects its own consent, notice,
|
|
105
|
+
privacy, pending-save, and IAB consent records in cookies and localStorage,
|
|
106
|
+
including configured custom storage keys, even if your patterns match them.
|
|
107
|
+
c15t does not store consent in sessionStorage, so targeted entries there are
|
|
108
|
+
removed even when their names match consent storage keys.
|
|
109
|
+
|
|
110
|
+
## When cleanup runs
|
|
111
|
+
|
|
112
|
+
The runtime attaches cleanup after persistence and the script loader. Cleanup
|
|
113
|
+
waits while the policy is pending. On the first settled snapshot, it removes
|
|
114
|
+
configured data for every denied category. This includes a new opt-in visitor
|
|
115
|
+
who has not made a choice and a returning visitor whose permission expired.
|
|
116
|
+
|
|
117
|
+
After that first pass, cleanup runs when a category changes from allowed to
|
|
118
|
+
denied. Saving a refusal, expiry, a policy change, Global Privacy Control,
|
|
119
|
+
or synchronized records can cause that transition. Under an opt-out policy,
|
|
120
|
+
an expired grant that remains effectively allowed does not trigger deletion.
|
|
121
|
+
The `necessary` category cannot be configured for cleanup.
|
|
122
|
+
|
|
123
|
+
Cleanup keeps waiting if a failed initial request leaves the policy pending.
|
|
124
|
+
If a previously settled policy falls back to denial after an initialization
|
|
125
|
+
failure, cleanup removes its configured data. A later successful retry cannot
|
|
126
|
+
restore deleted data.
|
|
127
|
+
|
|
128
|
+
Runtime construction, server rendering, draft checkbox edits, opening the
|
|
129
|
+
dialog, and disposal do not clear data. Cleanup does not poll storage or repeat
|
|
130
|
+
on unrelated UI updates.
|
|
131
|
+
|
|
132
|
+
## Use an existing kernel
|
|
133
|
+
|
|
134
|
+
For a manually assembled integration, attach the module in the browser after
|
|
135
|
+
persistence hydration and script-loader setup:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { createClearOnRevocation } from 'c15t/modules/clear-on-revocation';
|
|
139
|
+
|
|
140
|
+
const cleanup = createClearOnRevocation({
|
|
141
|
+
kernel,
|
|
142
|
+
config: { measurement: { cookies: ['_ga', '_ga_*'] } },
|
|
143
|
+
storageConfig,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Stop observing consent when this integration is torn down.
|
|
147
|
+
cleanup.dispose();
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Here `kernel` is your existing consent kernel. Pass the same `storageConfig`
|
|
151
|
+
used by persistence so cleanup protects custom record keys. Attaching the
|
|
152
|
+
module can immediately clear denied categories if the policy is already
|
|
153
|
+
settled. Do not also attach it when your provider or runtime owns cleanup.
|
|
154
|
+
|
|
155
|
+
## Browser limits
|
|
156
|
+
|
|
157
|
+
Cleanup can remove JavaScript-accessible first-party cookies and keys in the
|
|
158
|
+
current origin's `localStorage` and `sessionStorage`. It cannot remove
|
|
159
|
+
`HttpOnly` cookies or another origin's data. Keep `HttpOnly` protections and
|
|
160
|
+
use your server to expire cookies that require server access. Cookie deletion
|
|
161
|
+
must match the cookie's scope. See the
|
|
162
|
+
[browser cookie documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies).
|
|
163
|
+
|
|
164
|
+
Browser restrictions can prevent reads or deletions. Cleanup failures do not
|
|
165
|
+
block consent updates. A running SDK may write data again after a sweep, so
|
|
166
|
+
keep script gating and the integration's consent-change or teardown behavior
|
|
167
|
+
configured. Deleting a script element cannot undo JavaScript it already ran.
|