@c15t/react 3.0.0-alpha.10 → 3.0.0-alpha.11
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 +1 -0
- package/dist/aggregate-components.js +1 -1
- package/dist/chunk-warming.js +1 -1
- package/dist/components/consent-gate/atoms.js +1 -1
- package/dist/components/iab-panel/atoms/root.js +1 -1
- package/dist/components/iab-panel/iab-panel.js +1 -1
- package/dist/components/iab-prompt/atoms/root.js +1 -1
- package/dist/components/iab-prompt/iab-prompt.js +1 -1
- package/dist/components/panel/atoms/root.js +1 -1
- package/dist/components/panel-trigger/atoms/root.js +1 -1
- package/dist/components/panel-trigger/panel-trigger.js +1 -1
- package/dist/components/panel-trigger/toolbar-loader.js +2 -0
- package/dist/components/preferences/atoms/root.js +1 -1
- package/dist/components/prompt/atoms/root.js +1 -1
- package/dist/components/shared/surface-styles.js +1 -1
- package/dist/devtools.js +1 -1
- package/dist/iab-dialog-deferred.js +2 -0
- package/dist/iab.js +1 -1
- package/dist/utils/deferred-module.js +1 -1
- package/dist/version.js +1 -1
- package/dist-types/chunk-warming.d.ts +8 -11
- package/dist-types/components/panel-trigger/toolbar-loader.d.ts +34 -0
- package/dist-types/components/shared/surface-styles.d.ts +26 -2
- package/dist-types/iab-dialog-deferred.d.ts +36 -0
- package/dist-types/iab.d.ts +2 -1
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +1 -0
- package/docs/concepts/choose-your-setup.md +5 -2
- package/docs/concepts/data-fetching.md +24 -10
- package/docs/concepts/modes.md +9 -6
- package/docs/frameworks/react/components/consent-banner.md +3 -3
- package/docs/frameworks/react/components/consent-dialog.md +3 -3
- package/docs/frameworks/react/components/consent-provider.md +12 -9
- package/docs/frameworks/react/components.md +3 -3
- package/docs/frameworks/react/content-security-policy.md +8 -2
- package/docs/frameworks/react/iab.md +19 -0
- package/docs/frameworks/react/quickstart.md +25 -79
- package/docs/frameworks/react/rendering.md +161 -139
- package/docs/frameworks/react/scripts.md +3 -3
- package/docs/frameworks/react/troubleshooting.md +17 -16
- package/docs/frameworks/react/upgrade-v3.md +5 -4
- package/docs/guides/banner-experiments.md +16 -0
- package/docs/integrations/overview.md +1 -0
- package/docs/integrations/vercel-speed-insights.md +306 -0
- package/package.json +7 -7
|
@@ -23,15 +23,168 @@ read the visitor's cookie and location on the server, so the banner can be in
|
|
|
23
23
|
the first HTML. [Choose your setup](../../concepts/choose-your-setup.md#server-rendering-or-browser-rendering)
|
|
24
24
|
explains the difference in general terms.
|
|
25
25
|
|
|
26
|
-
##
|
|
26
|
+
## Client-rendered apps
|
|
27
27
|
|
|
28
28
|
The [quickstart](./quickstart.md) and `examples/react` in
|
|
29
|
-
the c15t repository use
|
|
29
|
+
the c15t repository use `hosted()` from `c15t/react`. It reads the backend URL
|
|
30
|
+
`consentManifest` read from `VITE_C15T_BACKEND_URL` or
|
|
31
|
+
`VITE_INTH_PROJECT_URL`; without the plugin, pass `hosted({ backendURL })`.
|
|
32
|
+
Policy edits apply on the next page load, without a rebuild. The page loads
|
|
33
|
+
like this:
|
|
34
|
+
|
|
35
|
+
1. The page loads with no consent state. Every optional category is denied.
|
|
36
|
+
2. The browser requests `GET /init` from your backend URL. A
|
|
37
|
+
[script in `index.html`](#send-init-before-the-app-loads) sends it while
|
|
38
|
+
the JavaScript downloads. The backend picks the visitor's policy from their
|
|
39
|
+
location. With an `experiment`, pass it to the plugin as
|
|
40
|
+
`initPrefetch: { experiment }` so the early request carries the visitor's
|
|
41
|
+
arm. Without that, the provider sends its own `/init` when it mounts.
|
|
42
|
+
3. The provider applies the policy and any stored choice. It shows the banner
|
|
43
|
+
if the policy asks for one, and loads the scripts the visitor allowed.
|
|
44
|
+
|
|
45
|
+
Until step 3 finishes, gated scripts and `ConsentGate` embeds stay blocked. If
|
|
46
|
+
the backend request fails, they stay blocked and no banner shows.
|
|
47
|
+
|
|
48
|
+
### Send `/init` before the app loads
|
|
49
|
+
|
|
50
|
+
`consentManifest()` adds a small inline script to the `<head>` of
|
|
51
|
+
`index.html`. It sends `/init` while the browser downloads your JavaScript,
|
|
52
|
+
and `hosted()` uses that response instead of sending its own. The banner
|
|
53
|
+
usually shows 50 to 250 ms sooner. There is nothing to configure.
|
|
54
|
+
|
|
55
|
+
The early request can't read your app's options, so in a few setups it won't
|
|
56
|
+
match and the app sends a second `/init`. Pass `initPrefetch: false` when the
|
|
57
|
+
app uses `offline()` or gives `hosted()` its own `backendURL`, `fetch`,
|
|
58
|
+
`initURL` or `headers`. With its own `fetch`, `hosted()` sends `/init` through
|
|
59
|
+
it and ignores the early response. If it sets `credentials`, `overrides`, `storageKey`, an
|
|
60
|
+
`experiment`, or `journey: false`, pass the same values as
|
|
61
|
+
`initPrefetch: { credentials, experiment, journey, overrides, storageKey }`.
|
|
62
|
+
With `journey: 'tab'`, passing it too makes a tab's first `/init` report the
|
|
63
|
+
`'tab'` scope instead of `'page'`. It doesn't save a request.
|
|
64
|
+
Pass `experiment` only when c15t assigns the arm. If a feature flag picks
|
|
65
|
+
it, leave it out, or the script sends an arm the visitor may never see.
|
|
66
|
+
The dev server adds the script even to a `manifest()` app, which then sends
|
|
67
|
+
one `/init` per page load that it doesn't use. A production build leaves it
|
|
68
|
+
out.
|
|
69
|
+
|
|
70
|
+
## React Router, Remix and other server-rendered apps
|
|
71
|
+
|
|
72
|
+
React Router framework mode, Remix and similar frameworks have no c15t adapter.
|
|
73
|
+
Use the quickstart's `Consent` component and render it in your root component,
|
|
74
|
+
around the outlet. In React Router framework mode that is `app/root.tsx`.
|
|
75
|
+
|
|
76
|
+
`ConsentProvider` renders on the server without touching browser APIs, and the
|
|
77
|
+
browser takes over after hydration:
|
|
78
|
+
|
|
79
|
+
* The server HTML contains your page but no banner and no consent state.
|
|
80
|
+
* After hydration the browser calls `/init`, then shows the banner if the
|
|
81
|
+
policy asks for one.
|
|
82
|
+
* The server render and the first browser render agree, so hydration does not
|
|
83
|
+
warn or change a stored choice.
|
|
84
|
+
|
|
85
|
+
The Vite setup needs no change. The banner renders in the browser and brings
|
|
86
|
+
its own `<style>` element, so there is no stylesheet to import.
|
|
87
|
+
|
|
88
|
+
These frameworks render their own HTML, so the Vite plugin can't add the
|
|
89
|
+
early `/init` script. Put `buildPrefetchScript({ backendURL })` from `c15t` in
|
|
90
|
+
a `<script>` in the root `<head>` instead, unless your loader supplies
|
|
91
|
+
`initialData` as described below. The two are alternatives: with
|
|
92
|
+
`initialData` the provider never reads the script's response.
|
|
93
|
+
|
|
94
|
+
### Skip the browser's first init request
|
|
95
|
+
|
|
96
|
+
This is optional. `fetchSSRData` from `c15t/react/server` calls the backend's
|
|
97
|
+
`/init` from your server loader, forwarding the visitor's location and
|
|
98
|
+
language headers. Pass the result to the browser, wrap it in a promise and give
|
|
99
|
+
it to `hosted({ backendURL, initialData })`. The provider's first init then uses that
|
|
100
|
+
response instead of a network request.
|
|
101
|
+
|
|
102
|
+
Know its limits before you add it:
|
|
103
|
+
|
|
104
|
+
* It saves the browser's round trip to the backend. It does not put the banner
|
|
105
|
+
in the server HTML; the banner still mounts after hydration.
|
|
106
|
+
* Every page view makes a server-to-server `/init` request. Do not cache the
|
|
107
|
+
loader response, because it contains one visitor's policy.
|
|
108
|
+
* It returns `undefined` when the request has no location or language headers,
|
|
109
|
+
and the browser then requests `/init` as usual.
|
|
110
|
+
* `mode` is read once, when the provider mounts. Create the `hosted()` mode once
|
|
111
|
+
in the browser rather than on every render.
|
|
112
|
+
* A relative `backendURL` resolves against the request's `host` header, over
|
|
113
|
+
`https` for a domain name and over `http` for `localhost`, an IP address or
|
|
114
|
+
a single-label host. `fetchSSRData` ignores `x-forwarded-host`,
|
|
115
|
+
`x-forwarded-proto` and `forwarded`, and does not send them to the backend.
|
|
116
|
+
Behind a proxy that overwrites those headers, pass
|
|
117
|
+
`trustForwardedHeaders: true` to use them.
|
|
118
|
+
* If your server answers requests for any `Host` header, such as a Node server
|
|
119
|
+
exposed directly or a proxy that forwards `Host` from its default virtual
|
|
120
|
+
host, pass `fetchSSRData` an absolute `backendURL`. A relative one resolves
|
|
121
|
+
against whatever `Host` the request sent.
|
|
122
|
+
|
|
123
|
+
### Render the banner in the server HTML
|
|
124
|
+
|
|
125
|
+
c15t has no framework-neutral helper for this. `ConsentProvider` accepts a
|
|
126
|
+
server-resolved `prefetch` state, but the Next.js and TanStack Start adapters
|
|
127
|
+
build that state from the request's cookie, headers and a cached policy
|
|
128
|
+
manifest. Building it by hand ties your app to internal shapes. If the banner
|
|
129
|
+
must be part of the first paint, use one of those adapters. Otherwise keep the
|
|
130
|
+
browser path.
|
|
131
|
+
|
|
132
|
+
## Static and prerendered pages
|
|
133
|
+
|
|
134
|
+
A prerendered page is the same HTML for every visitor, so it cannot contain one
|
|
135
|
+
visitor's consent. Use the quickstart's setup. `/init` requests and consent
|
|
136
|
+
saves go to the backend URL directly, so the static host needs no server
|
|
137
|
+
route. Add the site's
|
|
138
|
+
origin to the trusted origins in your Inth project.
|
|
139
|
+
|
|
140
|
+
Do not cache a response that contains a visitor's consent in a CDN or a shared
|
|
141
|
+
page cache. [Data fetching](../../concepts/data-fetching.md) covers what is safe to
|
|
142
|
+
cache.
|
|
143
|
+
|
|
144
|
+
## Where the browser sends requests
|
|
145
|
+
|
|
146
|
+
With `hosted()`, the browser calls two backend endpoints:
|
|
147
|
+
|
|
148
|
+
| Request | When |
|
|
149
|
+
| --------------------- | ------------------------------------------ |
|
|
150
|
+
| `GET {url}/init` | Once per page load, to resolve the policy |
|
|
151
|
+
| `POST {url}/subjects` | When the visitor accepts, rejects or saves |
|
|
152
|
+
|
|
153
|
+
These requests go to the backend's origin, so it must list your site as a
|
|
154
|
+
trusted origin.
|
|
155
|
+
[Data fetching](../../concepts/data-fetching.md) compares this with proxies and
|
|
156
|
+
custom transports.
|
|
157
|
+
|
|
158
|
+
## Check the rendering path
|
|
159
|
+
|
|
160
|
+
1. Open the page in a private window and view the page source. In a
|
|
161
|
+
server-rendered app the HTML contains your content and no element with
|
|
162
|
+
`data-testid="consent-banner-root"`.
|
|
163
|
+
2. In DevTools Network, confirm one `/init` request runs, unless you supply
|
|
164
|
+
`initialData`.
|
|
165
|
+
3. The banner appears once the policy resolves. Vendor requests stay absent
|
|
166
|
+
until you allow their category.
|
|
167
|
+
|
|
168
|
+
## Bundle the policy at build time
|
|
169
|
+
|
|
170
|
+
`manifest()` resolves the policy in the browser from a snapshot the build
|
|
171
|
+
downloaded. It saves the `/init` request only in these cases:
|
|
172
|
+
|
|
173
|
+
* The policy has no location rules, or every location gets the same banner.
|
|
174
|
+
* The page already knows the visitor's location, for example from an edge
|
|
175
|
+
worker, and passes it as `inputs`.
|
|
176
|
+
* You run a same-origin `geoURL` route that returns the location.
|
|
177
|
+
|
|
178
|
+
Otherwise the browser still calls `/init` on a first visit and uses the
|
|
179
|
+
backend's answer, so the bundle adds bytes without saving a request.
|
|
180
|
+
`consentManifest` warns during the build when that happens. The resolver adds
|
|
181
|
+
about 3 KB gzipped to the bundle, and policy edits need a rebuild. The browser
|
|
182
|
+
sends no `/init`, so the backend doesn't count visitors it resolves this way.
|
|
30
183
|
|
|
31
184
|
The build fetches your public policy once and bundles it, so the server never
|
|
32
185
|
fetches it at runtime.
|
|
33
186
|
|
|
34
|
-
|
|
187
|
+
Keep `consentManifest` in your Vite plugin list:
|
|
35
188
|
|
|
36
189
|
```ts title="vite.config.ts (plugins option)"
|
|
37
190
|
import { consentManifest } from 'c15t/build';
|
|
@@ -68,20 +221,16 @@ When the build has no snapshot, as in `vite dev` after a failed fetch,
|
|
|
68
221
|
`${backendURL}/manifest` instead.
|
|
69
222
|
|
|
70
223
|
When the required country or region is missing, the transport calls backend
|
|
71
|
-
`/init` and uses its resolved policy and translations.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
that request while it first renders, before the page mounts, unless the visitor
|
|
76
|
-
has a stored choice.
|
|
224
|
+
`/init` and uses its resolved policy and translations. That response can use
|
|
225
|
+
newer backend policy than the build snapshot. `ConsentProvider` sends that
|
|
226
|
+
request while it first renders, before the page mounts, unless the visitor has
|
|
227
|
+
a stored choice.
|
|
77
228
|
|
|
78
229
|
The browser cannot guess the banner from the snapshot alone when locations
|
|
79
230
|
differ. With a European opt-in rule and no banner elsewhere, a banner shown
|
|
80
231
|
before `/init` answers would vanish for most of the world. The exception is a
|
|
81
232
|
policy whose country and region rules all show the same banner, with a default
|
|
82
|
-
rule that covers everywhere else: the browser resolves it at once.
|
|
83
|
-
round trip for location-specific rules, pass the country your CDN or edge
|
|
84
|
-
already knows through `inputs`.
|
|
233
|
+
rule that covers everywhere else: the browser resolves it at once.
|
|
85
234
|
|
|
86
235
|
Policy and resolver code are part of the browser bundle.
|
|
87
236
|
|
|
@@ -134,130 +283,3 @@ The plugin can't see the options your app passes to `manifest()`. When the
|
|
|
134
283
|
app passes `source: 'runtime'` or `manifestURL`, set
|
|
135
284
|
`consentManifest({ source: 'runtime' })` too. The build then downloads no
|
|
136
285
|
manifest, so it doesn't fail when the backend's `/manifest` is down.
|
|
137
|
-
|
|
138
|
-
For policy updates without a rebuild, use `hosted({ backendURL })` from `c15t/react`
|
|
139
|
-
as the mode and omit the build plugin. That setup resolves policy through the
|
|
140
|
-
backend `/init` on each page load.
|
|
141
|
-
|
|
142
|
-
## Client-rendered apps
|
|
143
|
-
|
|
144
|
-
The recommended [quickstart](./quickstart.md) bundles the
|
|
145
|
-
manifest and resolves it in the browser. See [build-time manifests](#bundle-the-manifest-during-vite-builds).
|
|
146
|
-
|
|
147
|
-
For policy updates without rebuilding, use `hosted()` from `c15t/react` as
|
|
148
|
-
the mode. It reads the backend URL `consentManifest` read from
|
|
149
|
-
`VITE_C15T_BACKEND_URL` or `VITE_INTH_PROJECT_URL`; without the plugin, pass
|
|
150
|
-
`hosted({ backendURL })`.
|
|
151
|
-
That runtime path works as follows:
|
|
152
|
-
|
|
153
|
-
1. The page loads with no consent state. Every optional category is denied.
|
|
154
|
-
2. `ConsentProvider` requests `GET /init` from your backend URL while it first
|
|
155
|
-
renders, before the page paints. The backend picks the visitor's policy
|
|
156
|
-
from their location. With an `experiment`, the request waits until the
|
|
157
|
-
provider mounts, because it carries the visitor's arm.
|
|
158
|
-
3. The provider applies the policy and any stored choice. It shows the banner
|
|
159
|
-
if the policy asks for one, and loads the scripts the visitor allowed.
|
|
160
|
-
|
|
161
|
-
Until step 3 finishes, gated scripts and `ConsentGate` embeds stay blocked. If
|
|
162
|
-
the backend request fails, they stay blocked and no banner shows.
|
|
163
|
-
|
|
164
|
-
## React Router, Remix and other server-rendered apps
|
|
165
|
-
|
|
166
|
-
React Router framework mode, Remix and similar frameworks have no c15t adapter.
|
|
167
|
-
Use the quickstart's `Consent` component and render it in your root component,
|
|
168
|
-
around the outlet. In React Router framework mode that is `app/root.tsx`.
|
|
169
|
-
|
|
170
|
-
`ConsentProvider` renders on the server without touching browser APIs, and the
|
|
171
|
-
browser takes over after hydration:
|
|
172
|
-
|
|
173
|
-
* The server HTML contains your page but no banner and no consent state.
|
|
174
|
-
* After hydration the browser resolves the bundled manifest, then shows the
|
|
175
|
-
banner if the policy asks for one. When the banner depends on a country or
|
|
176
|
-
region the browser does not know, it calls `/init` and uses the backend's
|
|
177
|
-
current policy and translations, which can differ from the build snapshot.
|
|
178
|
-
With `hosted()`, it always calls `/init`.
|
|
179
|
-
* The server render and the first browser render agree, so hydration does not
|
|
180
|
-
warn or change a stored choice.
|
|
181
|
-
|
|
182
|
-
The Vite setup needs no change. The banner renders in the browser and brings
|
|
183
|
-
its own `<style>` element, so there is no stylesheet to import.
|
|
184
|
-
|
|
185
|
-
### Skip the browser's first init request
|
|
186
|
-
|
|
187
|
-
This is optional. `fetchSSRData` from `c15t/react/server` calls the backend's
|
|
188
|
-
`/init` from your server loader, forwarding the visitor's location and
|
|
189
|
-
language headers. Pass the result to the browser, wrap it in a promise and give
|
|
190
|
-
it to `hosted({ backendURL, initialData })`. The provider's first init then uses that
|
|
191
|
-
response instead of a network request.
|
|
192
|
-
|
|
193
|
-
Know its limits before you add it:
|
|
194
|
-
|
|
195
|
-
* It saves the browser's round trip to the backend. It does not put the banner
|
|
196
|
-
in the server HTML; the banner still mounts after hydration.
|
|
197
|
-
* Every page view makes a server-to-server `/init` request. Do not cache the
|
|
198
|
-
loader response, because it contains one visitor's policy.
|
|
199
|
-
* It returns `undefined` when the request has no location or language headers,
|
|
200
|
-
and the browser then requests `/init` as usual.
|
|
201
|
-
* `mode` is read once, when the provider mounts. Create the `hosted()` mode once
|
|
202
|
-
in the browser rather than on every render.
|
|
203
|
-
* A relative `backendURL` resolves against the request's `host` header, over
|
|
204
|
-
`https` for a domain name and over `http` for `localhost`, an IP address or
|
|
205
|
-
a single-label host. `fetchSSRData` ignores `x-forwarded-host`,
|
|
206
|
-
`x-forwarded-proto` and `forwarded`, and does not send them to the backend.
|
|
207
|
-
Behind a proxy that overwrites those headers, pass
|
|
208
|
-
`trustForwardedHeaders: true` to use them.
|
|
209
|
-
* If your server answers requests for any `Host` header, such as a Node server
|
|
210
|
-
exposed directly or a proxy that forwards `Host` from its default virtual
|
|
211
|
-
host, pass `fetchSSRData` an absolute `backendURL`. A relative one resolves
|
|
212
|
-
against whatever `Host` the request sent.
|
|
213
|
-
|
|
214
|
-
### Render the banner in the server HTML
|
|
215
|
-
|
|
216
|
-
c15t has no framework-neutral helper for this. `ConsentProvider` accepts a
|
|
217
|
-
server-resolved `prefetch` state, but the Next.js and TanStack Start adapters
|
|
218
|
-
build that state from the request's cookie, headers and a cached policy
|
|
219
|
-
manifest. Building it by hand ties your app to internal shapes. If the banner
|
|
220
|
-
must be part of the first paint, use one of those adapters. Otherwise keep the
|
|
221
|
-
browser path.
|
|
222
|
-
|
|
223
|
-
## Static and prerendered pages
|
|
224
|
-
|
|
225
|
-
A prerendered page is the same HTML for every visitor, so it cannot contain one
|
|
226
|
-
visitor's consent. Use the quickstart's build-time snapshot. Consent saves and
|
|
227
|
-
any `/init` requests go to the backend URL directly, so the static host
|
|
228
|
-
needs no server route. Add the site's
|
|
229
|
-
origin to the trusted origins in your Inth project.
|
|
230
|
-
|
|
231
|
-
Do not cache a response that contains a visitor's consent in a CDN or a shared
|
|
232
|
-
page cache. [Data fetching](../../concepts/data-fetching.md) covers what is safe to
|
|
233
|
-
cache.
|
|
234
|
-
|
|
235
|
-
## Where the browser sends requests
|
|
236
|
-
|
|
237
|
-
With `hosted()`, the browser calls two backend endpoints:
|
|
238
|
-
|
|
239
|
-
| Request | When |
|
|
240
|
-
| --------------------- | ------------------------------------------ |
|
|
241
|
-
| `GET {url}/init` | Once per page load, to resolve the policy |
|
|
242
|
-
| `POST {url}/subjects` | When the visitor accepts, rejects or saves |
|
|
243
|
-
|
|
244
|
-
With a bundled manifest, `manifest()` sends the same
|
|
245
|
-
`/subjects` request, and requests `/init` only when the policy depends on a
|
|
246
|
-
country or region the browser does not know.
|
|
247
|
-
|
|
248
|
-
These requests go to the backend's origin, so it must list your site as a
|
|
249
|
-
trusted origin.
|
|
250
|
-
[Data fetching](../../concepts/data-fetching.md) compares this with proxies and
|
|
251
|
-
custom transports.
|
|
252
|
-
|
|
253
|
-
## Check the rendering path
|
|
254
|
-
|
|
255
|
-
1. Open the page in a private window and view the page source. In a
|
|
256
|
-
server-rendered app the HTML contains your content and no element with
|
|
257
|
-
`data-testid="consent-banner-root"`.
|
|
258
|
-
2. In DevTools Network, confirm there is no `/manifest` request with a
|
|
259
|
-
build-time snapshot. A regional policy may still need an `/init` request
|
|
260
|
-
to resolve consent when geography is missing. With `hosted()`, one `/init`
|
|
261
|
-
request runs unless you supply `initialData`.
|
|
262
|
-
3. The banner appears once the policy resolves. Vendor requests stay absent
|
|
263
|
-
until you allow their category.
|
|
@@ -20,13 +20,13 @@ import {
|
|
|
20
20
|
ConsentDialog,
|
|
21
21
|
ConsentDialogLink,
|
|
22
22
|
ConsentProvider,
|
|
23
|
-
|
|
23
|
+
hosted,
|
|
24
24
|
} from 'c15t/react';
|
|
25
25
|
import type { ReactNode } from 'react';
|
|
26
26
|
|
|
27
27
|
const options = {
|
|
28
|
-
//
|
|
29
|
-
mode:
|
|
28
|
+
// Asks VITE_C15T_BACKEND_URL for each visitor's policy.
|
|
29
|
+
mode: hosted(),
|
|
30
30
|
scripts: [
|
|
31
31
|
posthog({
|
|
32
32
|
id: 'phc_your_project_key',
|
|
@@ -5,6 +5,23 @@ description: Fix a missing banner, early vendor requests, unstyled components
|
|
|
5
5
|
group: frameworks
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
## There is no banner
|
|
9
|
+
|
|
10
|
+
**Check.** In DevTools Network, find the `GET` request to `/init` on your
|
|
11
|
+
backend URL. With `hosted()`, the browser sends it while the provider first
|
|
12
|
+
renders. With a bundled `manifest()`, the browser makes no request before the
|
|
13
|
+
banner unless the policy depends on a country or region it does not know.
|
|
14
|
+
|
|
15
|
+
| What you see | Cause | Fix |
|
|
16
|
+
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
17
|
+
| No request and no banner | `ConsentProvider` is not mounted, an error stopped `src/consent.tsx` from rendering, or the bundled policy asks for no banner | Check the console for errors, render one provider at the app root as in the [quickstart](./quickstart.md), and inspect the active policy with the component below |
|
|
18
|
+
| `/init` fails with a CORS error | Your site's origin is not trusted | Add the exact origin, including port in development, to the trusted origins in your Inth project |
|
|
19
|
+
| `/init` returns 200 | The policy for this visitor asks for no banner, or a stored choice is still valid | Inspect the active policy with the component below, or clear site data |
|
|
20
|
+
|
|
21
|
+
A policy with `prompt: 'none'` shows no banner by design, and so does a
|
|
22
|
+
returning visitor with a valid stored choice. [Policies](../../concepts/policies.md)
|
|
23
|
+
explains why a region may not show one.
|
|
24
|
+
|
|
8
25
|
## Why does the build fail to download the manifest?
|
|
9
26
|
|
|
10
27
|
**Check.** `vite build` stops with an error from `consentManifest` that
|
|
@@ -59,22 +76,6 @@ requests `${backendURL}/manifest` on page load.
|
|
|
59
76
|
Fix the cause, then restart `vite dev` or rebuild. The plugin fetches once
|
|
60
77
|
when Vite starts.
|
|
61
78
|
|
|
62
|
-
## There is no banner
|
|
63
|
-
|
|
64
|
-
**Check.** In DevTools Network, find the `GET` request to `/init` on your
|
|
65
|
-
backend URL. With the bundled manifest, the browser makes no request before
|
|
66
|
-
the banner unless the policy depends on a country or region it does not know.
|
|
67
|
-
|
|
68
|
-
| What you see | Cause | Fix |
|
|
69
|
-
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
70
|
-
| No request and no banner | `ConsentProvider` is not mounted, an error stopped `src/consent.tsx` from rendering, or the bundled policy asks for no banner | Check the console for errors, render one provider at the app root as in the [quickstart](./quickstart.md), and inspect the active policy with the component below |
|
|
71
|
-
| `/init` fails with a CORS error | Your site's origin is not trusted | Add the exact origin, including port in development, to the trusted origins in your Inth project |
|
|
72
|
-
| `/init` returns 200 | The policy for this visitor asks for no banner, or a stored choice is still valid | Inspect the active policy with the component below, or clear site data |
|
|
73
|
-
|
|
74
|
-
A policy with `prompt: 'none'` shows no banner by design, and so does a
|
|
75
|
-
returning visitor with a valid stored choice. [Policies](../../concepts/policies.md)
|
|
76
|
-
explains why a region may not show one.
|
|
77
|
-
|
|
78
79
|
## The page throws that no IABProvider is mounted
|
|
79
80
|
|
|
80
81
|
The visitor's policy uses the `iab` model and the backend sent its vendor
|
|
@@ -255,10 +255,11 @@ projects use URLs such as `https://your-project.inth.app`. The
|
|
|
255
255
|
[React quickstart](./quickstart.md) shows the full provider,
|
|
256
256
|
and [data fetching](../../concepts/data-fetching.md) covers custom transports.
|
|
257
257
|
|
|
258
|
-
|
|
259
|
-
`c15t/build`
|
|
260
|
-
|
|
261
|
-
|
|
258
|
+
The quickstart keeps `hosted()` and adds `consentManifest()` from
|
|
259
|
+
`c15t/build` to `vite.config.ts`. `hosted()` then reads the backend URL from
|
|
260
|
+
`VITE_C15T_BACKEND_URL`, so it needs no arguments. v3 also adds `manifest()`,
|
|
261
|
+
which bundles the policy when Vite builds. It skips `/init` only when the
|
|
262
|
+
policy has no location rules or the page knows the visitor's location. See
|
|
262
263
|
[consent modes](../../concepts/modes.md).
|
|
263
264
|
|
|
264
265
|
Offline mode keeps choices in the browser and records nothing on a server. Not
|
|
@@ -397,6 +397,22 @@ arm re-assigns only the visitors who were in it. For a clean analysis, change
|
|
|
397
397
|
Built-in assignment is not available in Astro; see
|
|
398
398
|
[Astro](#astro).
|
|
399
399
|
|
|
400
|
+
A Vite app's early `/init` script, from `consentManifest()`, picks the arm
|
|
401
|
+
the same way when you pass it the experiment, and the app then runs that
|
|
402
|
+
arm. Import the same object into `vite.config.ts`:
|
|
403
|
+
|
|
404
|
+
```ts title="vite.config.ts"
|
|
405
|
+
consentManifest({ initPrefetch: { experiment: bannerExperiment } });
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Without it, the app sends its own `/init` for visitors who have not chosen
|
|
409
|
+
yet. The same goes for `consentPrefetchHead` in TanStack Start and
|
|
410
|
+
`buildPrefetchScript` elsewhere, which take the same `experiment` option.
|
|
411
|
+
|
|
412
|
+
When a feature flag picks the arm, leave `experiment` out of
|
|
413
|
+
`initPrefetch`. The script would pick its own arm and send it to the
|
|
414
|
+
backend, and the app would then send a second `/init` with the flag's arm.
|
|
415
|
+
|
|
400
416
|
## Acknowledge presentation diagnostics
|
|
401
417
|
|
|
402
418
|
Each arm is resolved under the visitor's policy the same way `presentation`
|
|
@@ -75,6 +75,7 @@ kernel to control its DOM lifecycle. Embeds do not require `@c15t/integrations`.
|
|
|
75
75
|
| [Rybbit Analytics](./rybbit-analytics.md) | `rybbitAnalytics` | `measurement` | Waits for effective permission |
|
|
76
76
|
| [Umami Analytics](./umami-analytics.md) | `umamiAnalytics` | `measurement` | Waits for effective permission |
|
|
77
77
|
| [Vercel Analytics](./vercel-analytics.md) | `vercelAnalytics` | `measurement` | Waits for effective permission |
|
|
78
|
+
| [Vercel Speed Insights](./vercel-speed-insights.md) | `vercelSpeedInsights` | `measurement` | Waits for effective permission; drops reports after revocation |
|
|
78
79
|
|
|
79
80
|
## Chat and support
|
|
80
81
|
|