@c15t/nextjs 2.2.0 → 3.0.0-alpha.0
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 +102 -142
- package/README.md +4 -4
- package/dist/api.js +1 -0
- package/dist/config.js +1 -0
- package/dist/devtools.js +2 -0
- package/dist/headers.js +1 -0
- package/dist/iab/styles.css +1 -1
- package/dist/iab/styles.tw3.css +133 -19
- package/dist/index.js +1 -1
- package/dist/middleware.js +1 -0
- package/dist/node-bridge.js +1 -0
- package/dist/pages.js +1 -0
- package/dist/proxy.js +1 -0
- package/dist/root.js +2 -0
- package/dist/server.js +1 -0
- package/dist/static.js +1 -0
- package/dist/styles.css +1 -1
- package/dist/styles.tw3.css +173 -29
- package/dist/version.js +1 -1
- package/dist-types/api.d.ts +88 -0
- package/dist-types/config.d.ts +110 -0
- package/dist-types/devtools.d.ts +1 -0
- package/dist-types/headers.d.ts +4 -0
- package/dist-types/index.d.ts +28 -10
- package/dist-types/middleware.d.ts +15 -0
- package/dist-types/node-bridge.d.ts +57 -0
- package/dist-types/pages.d.ts +88 -0
- package/dist-types/proxy.d.ts +34 -0
- package/dist-types/root.d.ts +86 -0
- package/dist-types/server.d.ts +164 -0
- package/dist-types/static.d.ts +42 -0
- package/dist-types/types.d.ts +5 -36
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +102 -142
- package/docs/assets/v3/brand-bar.png +0 -0
- package/docs/assets/v3/brand-card.png +0 -0
- package/docs/assets/v3/choice-wall.png +0 -0
- package/docs/assets/v3/mobile-card.png +0 -0
- package/docs/assets/v3/preferences.png +0 -0
- package/docs/customization/overview.md +45 -0
- package/docs/customization/recipes.md +79 -0
- package/docs/customization/slots.md +55 -0
- package/docs/customization/tokens.md +76 -0
- package/docs/customization/translations.md +49 -0
- package/docs/frameworks/next/api-reference/data-fetching.md +416 -0
- package/docs/frameworks/next/app-router.md +403 -0
- package/docs/frameworks/next/client-side.md +118 -0
- package/docs/frameworks/next/components/consent-banner.md +251 -211
- package/docs/frameworks/next/components/consent-dialog-link.md +96 -35
- package/docs/frameworks/next/components/consent-dialog-trigger.md +74 -149
- package/docs/frameworks/next/components/consent-dialog.md +189 -134
- package/docs/frameworks/next/components/consent-manager-provider.md +60 -318
- package/docs/frameworks/next/components/consent-widget.md +172 -114
- package/docs/frameworks/next/components/dev-tools.md +199 -40
- package/docs/frameworks/next/components/frame.md +137 -42
- package/docs/frameworks/next/concepts/consent-categories.md +24 -89
- package/docs/frameworks/next/concepts/policy-presets.md +142 -0
- package/docs/frameworks/next/content-security-policy.md +189 -0
- package/docs/frameworks/next/data-fetching.md +74 -0
- package/docs/frameworks/next/geography-headers.md +251 -0
- package/docs/frameworks/next/headless.md +95 -185
- package/docs/frameworks/next/hooks/use-consent-manager/overview.md +42 -163
- package/docs/frameworks/next/iab/overview.md +37 -107
- package/docs/frameworks/next/optimization.md +158 -194
- package/docs/frameworks/next/pages-router.md +296 -0
- package/docs/frameworks/next/quickstart.md +31 -132
- package/docs/frameworks/next/script-loader.md +134 -467
- package/docs/frameworks/next/server-side.md +97 -130
- package/docs/frameworks/next/static-export.md +164 -0
- package/docs/frameworks/next/styling/overview.md +166 -250
- package/docs/frameworks/next/troubleshooting.md +134 -144
- package/docs/guides/consent-state.md +60 -0
- package/docs/guides/data-fetching.md +163 -0
- package/docs/guides/deployment-modes.md +63 -0
- package/docs/guides/troubleshooting.md +68 -0
- package/docs/guides/verify-consent.md +62 -0
- package/docs/integrations/adobe-analytics.md +239 -105
- package/docs/integrations/ahrefs-analytics.md +238 -104
- package/docs/integrations/amplitude.md +219 -157
- package/docs/integrations/building-integrations.md +32 -224
- package/docs/integrations/clearbit.md +247 -86
- package/docs/integrations/cloudflare-web-analytics.md +250 -84
- package/docs/integrations/crisp.md +251 -97
- package/docs/integrations/databuddy.md +259 -153
- package/docs/integrations/fathom-analytics.md +239 -96
- package/docs/integrations/google-maps.md +328 -207
- package/docs/integrations/google-tag-manager.md +248 -96
- package/docs/integrations/google-tag.md +261 -90
- package/docs/integrations/heap.md +222 -149
- package/docs/integrations/hightouch.md +225 -131
- package/docs/integrations/hotjar.md +239 -90
- package/docs/integrations/intercom.md +239 -98
- package/docs/integrations/linkedin-insights.md +243 -113
- package/docs/integrations/logrocket.md +241 -123
- package/docs/integrations/matomo-analytics.md +256 -111
- package/docs/integrations/meta-pixel.md +197 -324
- package/docs/integrations/microsoft-clarity.md +233 -114
- package/docs/integrations/microsoft-uet.md +245 -110
- package/docs/integrations/mixpanel-analytics.md +252 -87
- package/docs/integrations/openai-pixel.md +441 -0
- package/docs/integrations/overview.md +95 -133
- package/docs/integrations/pirsch.md +249 -96
- package/docs/integrations/plausible-analytics.md +241 -100
- package/docs/integrations/posthog.md +353 -214
- package/docs/integrations/promptwatch.md +251 -81
- package/docs/integrations/reddit-pixel.md +226 -173
- package/docs/integrations/rudderstack.md +244 -187
- package/docs/integrations/rybbit-analytics.md +244 -91
- package/docs/integrations/segment.md +238 -92
- package/docs/integrations/snapchat-pixel.md +240 -110
- package/docs/integrations/tiktok-pixel.md +249 -81
- package/docs/integrations/umami-analytics.md +242 -95
- package/docs/integrations/vercel-analytics.md +242 -90
- package/docs/integrations/x-pixel.md +238 -104
- package/docs/integrations/youtube.md +354 -142
- package/docs/upgrade-v3.md +334 -0
- package/iab/styles.css +1 -1
- package/iab/styles.tw3.css +1 -1
- package/package.json +106 -65
- package/readme.json +3 -3
- package/src/iab/styles.css +1 -1
- package/src/iab/styles.tw3.css +1 -1
- package/src/styles.css +1 -1
- package/src/styles.tw3.css +1 -1
- package/styles.css +1 -1
- package/styles.tw3.css +1 -1
- package/client/components/consent-dialog-link.js +0 -3
- package/client/components/integrations.js +0 -3
- package/dist/components/integrations/index.cjs +0 -1
- package/dist/components/integrations/index.js +0 -1
- package/dist/headless.cjs +0 -1
- package/dist/index.cjs +0 -1
- package/dist/libs/browser-initial-data.cjs +0 -1
- package/dist/libs/browser-initial-data.js +0 -1
- package/dist/libs/initial-data.cjs +0 -1
- package/dist/libs/initial-data.js +0 -1
- package/dist/types.cjs +0 -1
- package/dist/version.cjs +0 -1
- package/dist-types/components/integrations/index.d.ts +0 -1
- package/dist-types/libs/browser-initial-data.d.ts +0 -9
- package/dist-types/libs/initial-data.d.ts +0 -33
- package/docs/frameworks/next/building-headless-components.md +0 -379
- package/docs/frameworks/next/callbacks.md +0 -186
- package/docs/frameworks/next/concepts/client-modes.md +0 -177
- package/docs/frameworks/next/concepts/consent-models.md +0 -117
- package/docs/frameworks/next/concepts/cookie-management.md +0 -122
- package/docs/frameworks/next/concepts/glossary.md +0 -24
- package/docs/frameworks/next/concepts/initialization-flow.md +0 -149
- package/docs/frameworks/next/concepts/policy-packs.md +0 -230
- package/docs/frameworks/next/hooks/use-color-scheme.md +0 -41
- package/docs/frameworks/next/hooks/use-consent-manager/checking-consent.md +0 -96
- package/docs/frameworks/next/hooks/use-consent-manager/location-info.md +0 -97
- package/docs/frameworks/next/hooks/use-consent-manager/setting-consent.md +0 -94
- package/docs/frameworks/next/hooks/use-draggable.md +0 -59
- package/docs/frameworks/next/hooks/use-focus-trap.md +0 -42
- package/docs/frameworks/next/hooks/use-reduced-motion.md +0 -37
- package/docs/frameworks/next/hooks/use-ssr-status.md +0 -32
- package/docs/frameworks/next/hooks/use-text-direction.md +0 -50
- package/docs/frameworks/next/hooks/use-translations.md +0 -55
- package/docs/frameworks/next/iab/consent-banner.md +0 -91
- package/docs/frameworks/next/iab/consent-dialog.md +0 -129
- package/docs/frameworks/next/iab/use-gvl-data.md +0 -21
- package/docs/frameworks/next/iframe-blocking.md +0 -106
- package/docs/frameworks/next/internationalization.md +0 -207
- package/docs/frameworks/next/network-blocker.md +0 -140
- package/docs/frameworks/next/policy-packs.md +0 -248
- package/docs/frameworks/next/styling/classnames.md +0 -94
- package/docs/frameworks/next/styling/color-scheme.md +0 -84
- package/docs/frameworks/next/styling/css-variables.md +0 -53
- package/docs/frameworks/next/styling/slots.md +0 -94
- package/docs/frameworks/next/styling/tailwind.md +0 -137
- package/docs/frameworks/next/styling/tokens.md +0 -156
- package/docs/shared/concepts/client-modes.md +0 -103
- package/docs/shared/concepts/consent-categories.md +0 -41
- package/docs/shared/concepts/consent-models.md +0 -72
- package/docs/shared/concepts/cookie-management.md +0 -88
- package/docs/shared/concepts/glossary.md +0 -24
- package/docs/shared/concepts/initialization-flow.md +0 -105
- package/docs/shared/concepts/policy-packs.md +0 -225
- package/docs/shared/react/components/consent-banner.md +0 -242
- package/docs/shared/react/components/consent-dialog-link.md +0 -45
- package/docs/shared/react/components/consent-dialog-trigger.md +0 -185
- package/docs/shared/react/components/consent-dialog.md +0 -119
- package/docs/shared/react/components/consent-manager-provider.md +0 -225
- package/docs/shared/react/components/consent-widget.md +0 -121
- package/docs/shared/react/components/dev-tools.md +0 -81
- package/docs/shared/react/components/frame.md +0 -52
- package/docs/shared/react/guides/building-headless-components.md +0 -110
- package/docs/shared/react/guides/callbacks.md +0 -89
- package/docs/shared/react/guides/headless.md +0 -31
- package/docs/shared/react/guides/iframe-blocking.md +0 -65
- package/docs/shared/react/guides/internationalization.md +0 -123
- package/docs/shared/react/guides/network-blocker.md +0 -72
- package/docs/shared/react/guides/optimization.md +0 -44
- package/docs/shared/react/guides/policy-packs.md +0 -173
- package/docs/shared/react/guides/script-loader.md +0 -311
- package/docs/shared/react/hooks/use-color-scheme.md +0 -31
- package/docs/shared/react/hooks/use-consent-manager/checking-consent.md +0 -95
- package/docs/shared/react/hooks/use-consent-manager/location-info.md +0 -96
- package/docs/shared/react/hooks/use-consent-manager/overview.md +0 -74
- package/docs/shared/react/hooks/use-consent-manager/setting-consent.md +0 -93
- package/docs/shared/react/hooks/use-draggable.md +0 -30
- package/docs/shared/react/hooks/use-focus-trap.md +0 -20
- package/docs/shared/react/hooks/use-reduced-motion.md +0 -33
- package/docs/shared/react/hooks/use-ssr-status.md +0 -16
- package/docs/shared/react/hooks/use-text-direction.md +0 -38
- package/docs/shared/react/hooks/use-translations.md +0 -15
- package/docs/shared/react/iab/consent-banner.md +0 -60
- package/docs/shared/react/iab/consent-dialog.md +0 -76
- package/docs/shared/react/iab/overview.md +0 -80
- package/docs/shared/react/iab/use-gvl-data.md +0 -21
- package/docs/shared/react/styling/classnames.md +0 -93
- package/docs/shared/react/styling/color-scheme.md +0 -35
- package/docs/shared/react/styling/css-variables.md +0 -53
- package/docs/shared/react/styling/overview.md +0 -261
- package/docs/shared/react/styling/slots.md +0 -93
- package/docs/shared/react/styling/stylesheet-entrypoint.md +0 -8
- package/docs/shared/react/styling/tailwind.md +0 -88
- package/docs/shared/react/styling/tokens.md +0 -155
- package/docs/shared/troubleshooting.md +0 -82
|
@@ -1,235 +1,199 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Optimization
|
|
3
|
-
description:
|
|
4
|
-
|
|
3
|
+
description: Reuse cached policy data and optionally reduce browser connection
|
|
4
|
+
overhead without changing consent behavior.
|
|
5
5
|
group: frameworks
|
|
6
6
|
---
|
|
7
|
-
Use this guide when you care about banner visibility speed, route static-ness, and reducing backend round-trip cost.
|
|
8
7
|
|
|
9
|
-
##
|
|
8
|
+
## Reuse cached policy data
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
The [App Router](./app-router.md) and
|
|
11
|
+
[Pages Router](./pages-router.md) guides use cached manifests
|
|
12
|
+
with Inth. A manifest contains public policy configuration that your app server
|
|
13
|
+
can reuse across requests. Each visitor's consent is still resolved separately.
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|Dynamic route, or you want the fastest first banner|`fetchInitialData()`|Starts `/init` on the server and streams the result into the provider|
|
|
18
|
-
|You want the simplest setup|Client-only init|No extra moving parts, but the banner appears later on cold loads|
|
|
15
|
+
A warm cache avoids repeated backend policy resolution. It does not eliminate
|
|
16
|
+
all requests. Your app may read its local manifest route, cold caches fetch
|
|
17
|
+
upstream data, and consent choices still reach Inth. IAB policies can also need
|
|
18
|
+
a Global Vendor List fetch.
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
> ℹ️ **Info:**
|
|
24
|
-
> Prefetched or SSR data is reused only when the request context still matches at runtime. That includes the backend URL, credentials, overrides, and the browser's ambient GPC signal.
|
|
20
|
+
Server prefetch supplies the initial policy to the browser. For browser
|
|
21
|
+
initialization that needs request geography, you can add an
|
|
22
|
+
[optional local init route](./api-reference/data-fetching.md#do-i-need-the-local-init-route).
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
## Compare manifests with backend initialization
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|Server prefetch|\~2x faster|before page loads|\~1.9x faster|
|
|
26
|
+
A warm manifest cache can reduce initialization latency by avoiding an upstream
|
|
27
|
+
backend request. The saving depends on backend latency, cache hits and where
|
|
28
|
+
consent resolution sits in rendering. It is not a fixed speedup for the whole
|
|
29
|
+
page.
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
| Fetching path | Work during initialization |
|
|
32
|
+
| ----------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
33
|
+
| Regular backend `/init` | Wait for the backend to resolve consent and return the result. |
|
|
34
|
+
| Cold manifest cache | Fetch public policy from the backend, cache it and resolve consent locally. |
|
|
35
|
+
| Warm manifest cache | Reuse cached policy and resolve consent locally; local route requests and rendering still take time. |
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
### How much faster is a warm manifest?
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
In a local SSR benchmark with **150 ms of simulated backend latency**, a warm
|
|
40
|
+
manifest reduced median time to first byte from **157.6 ms to 7.4 ms** across
|
|
41
|
+
10 new-visitor samples per setup. Both setups waited for consent before rendering.
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return [
|
|
44
|
-
{
|
|
45
|
-
source: '/api/c15t/:path*',
|
|
46
|
-
destination: `${process.env.NEXT_PUBLIC_C15T_URL}/:path*`,
|
|
47
|
-
},
|
|
48
|
-
];
|
|
49
|
-
},
|
|
50
|
-
};
|
|
43
|
+
The warm cache skipped the upstream policy fetch. A cold cache still needs that
|
|
44
|
+
fetch, so the benefit depends on your backend latency and cache hit rate.
|
|
51
45
|
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
See the [benchmark results](https://github.com/c15t/c15t/tree/ccfe906682ba06cef7b56a16cc8fd10728df77d3/benchmarks/reports/next-manifest-2026-09-10)
|
|
47
|
+
for the measurements and test conditions.
|
|
54
48
|
|
|
55
|
-
|
|
49
|
+
## Keep browser consent requests on your origin
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
A Next.js rewrite is an optional optimization. It can avoid a separate browser
|
|
52
|
+
DNS lookup and TLS connection to the consent backend when that connection would
|
|
53
|
+
otherwise be needed. Manifests and server rendering work without it.
|
|
60
54
|
|
|
61
|
-
|
|
55
|
+
The app server still connects to Inth, and the rewrite adds a proxy hop. Measure
|
|
56
|
+
your deployment to check the effect on latency. Vendor scripts, pixels and
|
|
57
|
+
iframes keep their own URLs; this rewrite only forwards c15t HTTP requests.
|
|
58
|
+
The same setup works with a self-hosted c15t backend.
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
* Ad blockers are less likely to block your init endpoint
|
|
65
|
-
* You can change backend infrastructure without touching client code
|
|
60
|
+
### Add the backend rewrite
|
|
66
61
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
> ⚠️ **Warning:**
|
|
71
|
-
> Use rewrites for browser-side calls (ConsentManagerProvider, C15tPrefetch). For server-side fetchInitialData(), prefer a direct backend URL (for example https\://your-project.inth.app) to avoid an extra server proxy hop.
|
|
62
|
+
Set `C15T_BACKEND_URL` to the absolute endpoint supplied by your Inth project.
|
|
63
|
+
The endpoint is public configuration. Merge this fallback into your existing
|
|
64
|
+
Next.js configuration:
|
|
72
65
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
Start with a same-origin rewrite and the default client-side provider. Add one of the preloading strategies below only when the route behavior or performance target calls for it.
|
|
76
|
-
|
|
77
|
-
### Client-Only Init
|
|
78
|
-
|
|
79
|
-
Keep the default provider setup when you want the least complexity. This works on both static and dynamic routes, but the banner only appears after the client runtime starts and the initial `/init` request completes.
|
|
80
|
-
|
|
81
|
-
### Dynamic Routes: Fetch On The Server And Stream
|
|
82
|
-
|
|
83
|
-
Use `fetchInitialData()` when the route is already dynamic, or when you are willing to make it dynamic in exchange for the fastest first banner.
|
|
66
|
+
```ts title="next.config.ts"
|
|
67
|
+
import type { NextConfig } from 'next';
|
|
84
68
|
|
|
85
|
-
|
|
69
|
+
const upstreamURL = process.env.C15T_BACKEND_URL?.replace(/\/$/, '');
|
|
70
|
+
if (!upstreamURL) throw new Error('Set C15T_BACKEND_URL to the absolute Inth endpoint');
|
|
86
71
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
72
|
+
export default {
|
|
73
|
+
async rewrites() {
|
|
74
|
+
return {
|
|
75
|
+
fallback: [{
|
|
76
|
+
source: '/api/c15t/:path*',
|
|
77
|
+
destination: `${upstreamURL}/:path*`,
|
|
78
|
+
}],
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
} satisfies NextConfig;
|
|
82
|
+
```
|
|
90
83
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
});
|
|
84
|
+
Next.js serves the local manifest handler first. Other consent requests, such
|
|
85
|
+
as `/api/c15t/subjects`, reach Inth through the rewrite. An optional local init
|
|
86
|
+
handler also takes precedence over this fallback.
|
|
95
87
|
|
|
96
|
-
|
|
97
|
-
<html lang="en">
|
|
98
|
-
<body>
|
|
99
|
-
<ConsentManager ssrData={ssrData}>{children}</ConsentManager>
|
|
100
|
-
</body>
|
|
101
|
-
</html>
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
```
|
|
88
|
+
### Use the local prefix in browser configuration
|
|
105
89
|
|
|
106
|
-
|
|
107
|
-
'
|
|
108
|
-
|
|
109
|
-
import { type ReactNode } from 'react';
|
|
110
|
-
import {
|
|
111
|
-
ConsentManagerProvider,
|
|
112
|
-
ConsentBanner,
|
|
113
|
-
ConsentDialog,
|
|
114
|
-
type InitialDataPromise,
|
|
115
|
-
} from '@c15t/nextjs';
|
|
116
|
-
|
|
117
|
-
export default function ConsentManager({
|
|
118
|
-
children,
|
|
119
|
-
ssrData,
|
|
120
|
-
}: {
|
|
121
|
-
children: ReactNode;
|
|
122
|
-
ssrData?: InitialDataPromise;
|
|
123
|
-
}) {
|
|
124
|
-
return (
|
|
125
|
-
<ConsentManagerProvider
|
|
126
|
-
options={{
|
|
127
|
-
mode: 'hosted',
|
|
128
|
-
backendURL: '/api/c15t',
|
|
129
|
-
ssrData,
|
|
130
|
-
}}
|
|
131
|
-
>
|
|
132
|
-
<ConsentBanner />
|
|
133
|
-
<ConsentDialog />
|
|
134
|
-
{children}
|
|
135
|
-
</ConsentManagerProvider>
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
```
|
|
90
|
+
In the manifest setup from your router guide, change only `backendURL` to
|
|
91
|
+
`'/api/c15t'`. The shared configuration then looks like this:
|
|
139
92
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
>
|
|
143
|
-
> ℹ️ **Info:**
|
|
144
|
-
> For fetchInitialData(), prefer a direct backend URL such as https\://your-project.inth.app instead of a rewrite to avoid an extra server-side proxy hop. See Server-Side Data Fetching for the full flow.
|
|
145
|
-
|
|
146
|
-
### Static Routes: Start Fetch Early In The Browser
|
|
147
|
-
|
|
148
|
-
Use `C15tPrefetch` when the route needs to stay static but you still want the `/init` request to start before hydration. Matching prefetched data is consumed automatically by the runtime during first store initialization.
|
|
149
|
-
|
|
150
|
-
```tsx title="app/layout.tsx"
|
|
151
|
-
import { C15tPrefetch } from '@c15t/nextjs';
|
|
152
|
-
import { ConsentManager } from '@/components/consent-manager';
|
|
153
|
-
|
|
154
|
-
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
155
|
-
return (
|
|
156
|
-
<html lang="en">
|
|
157
|
-
<head>
|
|
158
|
-
<C15tPrefetch
|
|
159
|
-
backendURL="/api/c15t"
|
|
160
|
-
overrides={{ country: 'DE', region: 'BE', language: 'de' }}
|
|
161
|
-
/>
|
|
162
|
-
</head>
|
|
163
|
-
<body>
|
|
164
|
-
<ConsentManager>{children}</ConsentManager>
|
|
165
|
-
</body>
|
|
166
|
-
</html>
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
```
|
|
93
|
+
```ts title="c15t.config.ts"
|
|
94
|
+
import { defineConsentConfig } from 'c15t/next';
|
|
170
95
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
ConsentManagerProvider,
|
|
176
|
-
ConsentBanner,
|
|
177
|
-
ConsentDialog,
|
|
178
|
-
} from '@c15t/nextjs';
|
|
179
|
-
|
|
180
|
-
export default function ConsentManagerClient({ children }: { children: React.ReactNode }) {
|
|
181
|
-
return (
|
|
182
|
-
<ConsentManagerProvider
|
|
183
|
-
options={{
|
|
184
|
-
mode: 'hosted',
|
|
185
|
-
backendURL: '/api/c15t',
|
|
186
|
-
overrides: { country: 'DE', region: 'BE', language: 'de' },
|
|
187
|
-
}}
|
|
188
|
-
>
|
|
189
|
-
<ConsentBanner />
|
|
190
|
-
<ConsentDialog />
|
|
191
|
-
{children}
|
|
192
|
-
</ConsentManagerProvider>
|
|
193
|
-
);
|
|
194
|
-
}
|
|
96
|
+
export const consentConfig = defineConsentConfig({
|
|
97
|
+
backendURL: '/api/c15t',
|
|
98
|
+
manifestURL: '/api/c15t/manifest',
|
|
99
|
+
});
|
|
195
100
|
```
|
|
196
101
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
> ℹ️ **Info:**
|
|
201
|
-
> If the request context changes between prefetch time and runtime, c15t falls back to a normal client /init. A common example is overrides.gpc conflicting with the browser's ambient GPC signal.
|
|
202
|
-
|
|
203
|
-
## Keep The Provider Mounted Across Navigation
|
|
102
|
+
The manifest URLs remain explicit in the current API. A configuration with only
|
|
103
|
+
`backendURL` uses regular backend `/init` and can also use this rewrite. That
|
|
104
|
+
setup must not have a local manifest init handler intercepting `/api/c15t/init`.
|
|
204
105
|
|
|
205
|
-
|
|
106
|
+
Keep using `consentConfig` for `resolveConsent` and `ConsentRoot`. Omit a
|
|
107
|
+
separate `ConsentRoot` `backendURL` prop because it overrides the shared value.
|
|
206
108
|
|
|
207
|
-
|
|
109
|
+
### Keep route handlers pointed upstream
|
|
208
110
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
* Keeps banner/dialog state stable between route transitions
|
|
111
|
+
The ready-made App Router handlers read the absolute upstream URL from
|
|
112
|
+
`C15T_BACKEND_URL`. Keep these exports from the router guide:
|
|
212
113
|
|
|
213
|
-
|
|
114
|
+
```ts title="app/api/c15t/manifest/route.ts"
|
|
115
|
+
export { manifestGET as GET } from 'c15t/next/api';
|
|
116
|
+
```
|
|
214
117
|
|
|
215
|
-
|
|
118
|
+
```ts title="app/api/c15t/init/route.ts"
|
|
119
|
+
export { GET } from 'c15t/next/api';
|
|
120
|
+
```
|
|
216
121
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
122
|
+
Pages Router uses `createPagesApiHandlers()` with the same environment
|
|
123
|
+
configuration. Export `.manifest` and `.init` from the respective API files as
|
|
124
|
+
shown in the [Pages Router guide](./pages-router.md).
|
|
125
|
+
|
|
126
|
+
If you configure handlers with `createNextConsentRouteHandlers({ backendURL })`,
|
|
127
|
+
pass the absolute upstream URL. Passing the browser's local `consentConfig`
|
|
128
|
+
would make the manifest handler fetch itself. An explicit `C15T_MANIFEST_URL`
|
|
129
|
+
must also point upstream.
|
|
130
|
+
|
|
131
|
+
### Check rewrite precedence
|
|
132
|
+
|
|
133
|
+
An array-form rewrite or `afterFiles` runs after concrete routes; `fallback`
|
|
134
|
+
runs after all application routes. A matching `beforeFiles` rewrite or
|
|
135
|
+
middleware/proxy rewrite can intercept the local handlers instead. See
|
|
136
|
+
[Next.js rewrite order](https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites).
|
|
137
|
+
|
|
138
|
+
Use `/api/c15t/:path*` for the backend prefix. A bare `/api/c15t` source does not
|
|
139
|
+
match nested endpoints. If a self-hosted backend catch-all already handles that
|
|
140
|
+
prefix, it serves the remaining endpoints instead of the fallback rewrite.
|
|
141
|
+
Keep the manifest resolver's upstream URL separate to avoid a request loop.
|
|
142
|
+
|
|
143
|
+
A full [static export](./static-export.md) has no Next.js
|
|
144
|
+
rewrites or API handlers. Use a hosting-level proxy or direct public Inth URL.
|
|
145
|
+
|
|
146
|
+
## Configure manifest cache refresh
|
|
147
|
+
|
|
148
|
+
`createNextConsentRouteHandlers` uses the Next.js Data Cache plus an in-process
|
|
149
|
+
manifest cache. The in-process cache also covers Pages Router runtimes without
|
|
150
|
+
the Data Cache. It supports ETag revalidation and respects upstream cache
|
|
151
|
+
headers, including responses marked private.
|
|
152
|
+
|
|
153
|
+
Once the upstream `s-maxage` has passed, the in-process cache keeps serving the
|
|
154
|
+
cached manifest for as long as the upstream `stale-while-revalidate` allows
|
|
155
|
+
(an explicit `s-maxage` is required for that window to apply),
|
|
156
|
+
and refreshes it in the background. Requests do not wait for that refresh, and
|
|
157
|
+
a refresh that fails or times out leaves the cached manifest in place, so a
|
|
158
|
+
slow or unavailable backend does not delay rendering on a server that has
|
|
159
|
+
already loaded the manifest. Inth sends `s-maxage=300` and a 24 hour
|
|
160
|
+
`stale-while-revalidate` by default; lower the second value on a self-hosted
|
|
161
|
+
backend if a policy change must reach servers sooner after an outage. A server
|
|
162
|
+
with an empty cache still waits for the first upstream response.
|
|
163
|
+
|
|
164
|
+
The background refresh is detached from the request. On runtimes that stop
|
|
165
|
+
work once a response is sent, register it with the platform so it can finish.
|
|
166
|
+
Pass `onBackgroundRevalidate` to the handler factory; it is called inside the
|
|
167
|
+
handler with the refresh promise, which never rejects:
|
|
168
|
+
|
|
169
|
+
```ts title="app/api/c15t/manifest/route.ts"
|
|
170
|
+
import { createNextConsentRouteHandlers } from 'c15t/next/api';
|
|
171
|
+
import { after } from 'next/server';
|
|
172
|
+
|
|
173
|
+
export const { manifestGET: GET } = createNextConsentRouteHandlers({
|
|
174
|
+
onBackgroundRevalidate: (refresh) => after(() => refresh),
|
|
175
|
+
});
|
|
176
|
+
```
|
|
222
177
|
|
|
223
|
-
|
|
178
|
+
The same option applies to the init handler's `GET`. `after` is stable from
|
|
179
|
+
Next 15.1; on Next 15.0 import `unstable_after` instead. Other hosts pass the
|
|
180
|
+
promise to their equivalent, such as `waitUntil` on Vercel or Cloudflare.
|
|
181
|
+
Without it the response still returns at once; only the refresh may be cut
|
|
182
|
+
short, in which case the next request starts another.
|
|
224
183
|
|
|
225
|
-
|
|
184
|
+
## Avoid repeating startup work
|
|
226
185
|
|
|
227
|
-
|
|
186
|
+
Keep one boundary in the App Router root layout or Pages Router `_app.tsx`.
|
|
187
|
+
Remounting it during navigation creates another runtime and repeats startup
|
|
188
|
+
work. Keep the stylesheet and consent UI in that shared root too.
|
|
228
189
|
|
|
229
|
-
|
|
190
|
+
Choose when to resolve consent according to your page. Use
|
|
191
|
+
[server rendering](./server-side.md) for resolved initial HTML
|
|
192
|
+
or streaming, and [client-side initialization](./client-side.md)
|
|
193
|
+
when the browser should prepare consent.
|
|
230
194
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
195
|
+
Measure cold entry, a warm manifest cache and client navigation separately.
|
|
196
|
+
Check server requests as well as the browser Network panel. Confirm that
|
|
197
|
+
consent saves reach the backend and policy updates appear after the configured
|
|
198
|
+
refresh window. If you add a rewrite, also confirm browser consent requests
|
|
199
|
+
use your origin.
|