@c15t/astro 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 +3 -0
- package/dist/api/handlers.js +9 -2
- package/dist/api/index.js +1 -1
- package/dist/api/manifest-init.js +21 -2
- package/dist/client.js +1 -0
- package/dist/server.js +8 -2
- package/dist-types/api/handlers.d.ts +2 -2
- package/dist-types/api/index.d.ts +4 -4
- package/dist-types/api/manifest-init.d.ts +28 -2
- package/dist-types/client.d.ts +6 -6
- package/dist-types/index.d.ts +8 -8
- package/dist-types/integration.d.ts +1 -1
- package/dist-types/middleware-handler.d.ts +1 -1
- package/dist-types/middleware.d.ts +3 -3
- package/dist-types/mode.d.ts +1 -1
- package/dist-types/server.d.ts +1 -1
- package/dist-types/types.d.ts +14 -1
- package/dist-types/ui/adapter.d.ts +1 -1
- package/dist-types/ui/provider-props.d.ts +1 -1
- package/dist-types/ui/react.d.ts +1 -1
- package/dist-types/ui/svelte.d.ts +1 -1
- package/dist-types/ui/vue.d.ts +1 -1
- package/docs/README.md +3 -0
- package/docs/frameworks/astro/quickstart.md +5 -1
- 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 +9 -9
- package/src/components/islands/panel-surface.tsx +51 -5
package/AGENTS.md
CHANGED
|
@@ -45,14 +45,17 @@ These docs describe v3. Start with Inth hosted setup, identify the framework, ro
|
|
|
45
45
|
- [Ahrefs Analytics](./docs/integrations/ahrefs-analytics.md): Configure Ahrefs Analytics with c15t v3, understand measurement permission and verify loading and revocation.
|
|
46
46
|
- [Amplitude](./docs/integrations/amplitude.md): Configure Amplitude with c15t v3, understand measurement permission and verify loading and revocation.
|
|
47
47
|
- [Custom integrations](./docs/integrations/building-integrations.md): Define loading, initialization and consent-change behavior for a vendor without a helper.
|
|
48
|
+
- [Clear on revocation](./docs/integrations/clear-on-revocation.md): Remove configured first-party cookies and Web Storage keys when their consent category is denied.
|
|
48
49
|
- [Clearbit](./docs/integrations/clearbit.md): Configure Clearbit with c15t v3, understand marketing permission and verify loading and revocation.
|
|
49
50
|
- [Cloudflare Web Analytics](./docs/integrations/cloudflare-web-analytics.md): Configure Cloudflare Web Analytics with c15t v3, understand measurement permission and verify loading and revocation.
|
|
51
|
+
- [Cloudflare Zaraz](./docs/integrations/cloudflare-zaraz.md): Synchronize c15t permissions with Zaraz purposes while Cloudflare manages your tools.
|
|
50
52
|
- [Crisp](./docs/integrations/crisp.md): Configure Crisp with c15t v3, understand functionality permission and verify loading and revocation.
|
|
51
53
|
- [Databuddy](./docs/integrations/databuddy.md): Configure Databuddy's initial and updated consent state with c15t v3.
|
|
52
54
|
- [Fathom Analytics](./docs/integrations/fathom-analytics.md): Configure Fathom Analytics with c15t v3, understand measurement permission and verify loading and revocation.
|
|
53
55
|
- [Google Maps](./docs/integrations/google-maps.md): Prevent a map iframe from mounting before the required permission.
|
|
54
56
|
- [Google Tag](./docs/integrations/google-tag.md): Configure gtag with c15t Consent Mode signals and understand its loading behavior.
|
|
55
57
|
- [Google Tag Manager](./docs/integrations/google-tag-manager.md): Load GTM with c15t consent signals and verify the tags inside your container.
|
|
58
|
+
- [Granular consent](./docs/integrations/granular-consent.md): Let visitors grant a category and still turn one vendor off, without adopting IAB TCF.
|
|
56
59
|
- [Heap](./docs/integrations/heap.md): Configure Heap with c15t v3, understand measurement permission and verify loading and revocation.
|
|
57
60
|
- [Hightouch](./docs/integrations/hightouch.md): Configure Hightouch with c15t v3, understand measurement permission and verify loading and revocation.
|
|
58
61
|
- [Hotjar](./docs/integrations/hotjar.md): Configure Hotjar with c15t v3, understand measurement permission and verify loading and revocation.
|
package/dist/api/handlers.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { serveGvlReference } from "@c15t/core";
|
|
2
2
|
import { MANIFEST_PASSTHROUGH_HEADERS, fetchCachedGvl, fetchCachedManifest, getManifestAge } from "@c15t/core/server";
|
|
3
3
|
import { extractConsentRequestInputs } from "@c15t/schema/types";
|
|
4
|
-
import { loadConsentManifest, resolveManifestInit, resolveManifestSourceFrom } from "./manifest-init.js";
|
|
4
|
+
import { loadConsentManifest, resolveManifestInit, resolveManifestSourceFrom, resolveSessionReportURL } from "./manifest-init.js";
|
|
5
5
|
const INIT_CACHE_CONTROL = 'private, no-store';
|
|
6
6
|
const MANIFEST_ROUTE_SUFFIX = '/manifest';
|
|
7
7
|
const handlers_waitUntilFromLocals = function(revalidation, locals) {
|
|
@@ -42,7 +42,14 @@ const handlers_createConsentRouteHandlers = function(handlerOptions) {
|
|
|
42
42
|
inputs: extractConsentRequestInputs(request.headers, {
|
|
43
43
|
language: handlerOptions.options.i18n?.locale
|
|
44
44
|
}),
|
|
45
|
-
manifest
|
|
45
|
+
manifest,
|
|
46
|
+
report: {
|
|
47
|
+
backendURL: resolveSessionReportURL(handlerOptions.options),
|
|
48
|
+
headers: request.headers,
|
|
49
|
+
method: request.method,
|
|
50
|
+
source: 'route',
|
|
51
|
+
waitUntil: handlers_bindBackgroundRevalidate(handlerOptions, lifetime)
|
|
52
|
+
}
|
|
46
53
|
});
|
|
47
54
|
return Response.json(payload, {
|
|
48
55
|
headers: {
|
package/dist/api/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { createConsentRouteHandlers, resolveManifestSourceURL, waitUntilFromLocals } from "./handlers.js";
|
|
2
|
-
export { loadConsentManifest, resolveManifestInit, resolveManifestSourceFrom } from "./manifest-init.js";
|
|
2
|
+
export { loadConsentManifest, resolveManifestInit, resolveManifestSourceFrom, resolveSessionReportURL } from "./manifest-init.js";
|
|
3
3
|
export { MANIFEST_DEDUPE_TTL_SECONDS, MANIFEST_PASSTHROUGH_HEADERS, clearManifestCache, createManifestRequestURL, fetchCachedManifest, getManifestSMaxAge, getManifestStaleWhileRevalidate } from "@c15t/core/server";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { deferInitGvlToRoute } from "@c15t/core";
|
|
2
|
-
import { fetchCachedManifest } from "@c15t/core/server";
|
|
2
|
+
import { fetchCachedManifest, reportConsentSession, resolveSessionReportBackendURL } from "@c15t/core/server";
|
|
3
3
|
import { consentInputsToOverrides, resolveBackendURL, resolveInitFromManifest } from "@c15t/schema/types";
|
|
4
4
|
import { baseTranslations } from "@c15t/translations/all";
|
|
5
5
|
const MANIFEST_ROUTE_SUFFIX = '/manifest';
|
|
@@ -67,6 +67,13 @@ const manifest_init_defaultFetchGvl = async function(input) {
|
|
|
67
67
|
if (!response.ok) throw new Error(`@c15t/astro: GVL responded ${response.status} ${response.statusText}`);
|
|
68
68
|
return await response.json();
|
|
69
69
|
};
|
|
70
|
+
const manifest_init_resolveSessionReportURL = function(options) {
|
|
71
|
+
const { mode } = options;
|
|
72
|
+
if ('manifest' !== mode.type || false === mode.reportSessions) return;
|
|
73
|
+
return resolveSessionReportBackendURL({
|
|
74
|
+
backendURL: mode.backendURL ?? manifest_init_getEnv('C15T_BACKEND_URL') ?? manifest_init_getEnv('PUBLIC_C15T_BACKEND_URL')
|
|
75
|
+
});
|
|
76
|
+
};
|
|
70
77
|
const manifest_init_resolveManifestInit = async function(input) {
|
|
71
78
|
const { inputs, manifest } = input;
|
|
72
79
|
const payload = resolveInitFromManifest(manifest, {
|
|
@@ -90,6 +97,18 @@ const manifest_init_resolveManifestInit = async function(input) {
|
|
|
90
97
|
payload.gvl = null;
|
|
91
98
|
}
|
|
92
99
|
}
|
|
100
|
+
if (input.report?.backendURL) reportConsentSession({
|
|
101
|
+
adapter: '@c15t/astro',
|
|
102
|
+
backendURL: input.report.backendURL,
|
|
103
|
+
fetch: input.fetch,
|
|
104
|
+
headers: input.report.headers,
|
|
105
|
+
init: payload,
|
|
106
|
+
inputs,
|
|
107
|
+
manifest,
|
|
108
|
+
method: input.report.method,
|
|
109
|
+
source: input.report.source,
|
|
110
|
+
waitUntil: input.report.waitUntil
|
|
111
|
+
});
|
|
93
112
|
payload.resolvedOverrides = consentInputsToOverrides({
|
|
94
113
|
country: inputs.country,
|
|
95
114
|
language: inputs.language,
|
|
@@ -100,4 +119,4 @@ const manifest_init_resolveManifestInit = async function(input) {
|
|
|
100
119
|
};
|
|
101
120
|
return !input.gvlRoute || input.fetch || input.fetchGvl ? payload : deferInitGvlToRoute(payload, input.gvlRoute);
|
|
102
121
|
};
|
|
103
|
-
export { manifest_init_defaultFetchGvl as defaultFetchGvl, manifest_init_loadConsentManifest as loadConsentManifest, manifest_init_resolveManifestInit as resolveManifestInit, manifest_init_resolveManifestSourceFrom as resolveManifestSourceFrom };
|
|
122
|
+
export { manifest_init_defaultFetchGvl as defaultFetchGvl, manifest_init_loadConsentManifest as loadConsentManifest, manifest_init_resolveManifestInit as resolveManifestInit, manifest_init_resolveManifestSourceFrom as resolveManifestSourceFrom, manifest_init_resolveSessionReportURL as resolveSessionReportURL };
|
package/dist/client.js
CHANGED
|
@@ -96,6 +96,7 @@ const client_createClient = function(options, extension = {}) {
|
|
|
96
96
|
...extension.scripts ?? []
|
|
97
97
|
];
|
|
98
98
|
const runtime = createConsentRuntime({
|
|
99
|
+
clearOnRevocation: extension.clearOnRevocation ?? options.clearOnRevocation,
|
|
99
100
|
consentCategories: options.consentCategories,
|
|
100
101
|
createIAB: lazyCreateIAB,
|
|
101
102
|
i18n: options.i18n,
|
package/dist/server.js
CHANGED
|
@@ -5,7 +5,7 @@ import { fetchCachedGvl } from "@c15t/core/server";
|
|
|
5
5
|
import { readProducerPolicyContract } from "@c15t/core/transports";
|
|
6
6
|
import { CONSENT_REQUEST_HEADER_NAMES, consentInputsToOverrides, extractConsentRequestInputs, resolveBackendURL } from "@c15t/schema/types";
|
|
7
7
|
import { baseTranslations } from "@c15t/translations/all";
|
|
8
|
-
import { loadConsentManifest, resolveManifestInit } from "./api/manifest-init.js";
|
|
8
|
+
import { loadConsentManifest, resolveManifestInit, resolveSessionReportURL } from "./api/manifest-init.js";
|
|
9
9
|
import { filterCookieHeader } from "./libs/cookies.js";
|
|
10
10
|
const server_resolveTranslations = function(options, inputs) {
|
|
11
11
|
const detect = options.i18n?.detectLanguage !== false;
|
|
@@ -164,7 +164,13 @@ const server_prefetchManifest = async function(input, mode) {
|
|
|
164
164
|
url: reference.url
|
|
165
165
|
}),
|
|
166
166
|
inputs: input.inputs,
|
|
167
|
-
manifest
|
|
167
|
+
manifest,
|
|
168
|
+
report: {
|
|
169
|
+
backendURL: resolveSessionReportURL(input.options),
|
|
170
|
+
headers: input.headers,
|
|
171
|
+
source: 'render',
|
|
172
|
+
waitUntil: input.onBackgroundRevalidate
|
|
173
|
+
}
|
|
168
174
|
});
|
|
169
175
|
return mergeInitOutputIntoKernelConfig(input.base, !input.fetch && manifest.iab?.gvl ? deferInitGvlToRoute(payload, input.options.endpoints.initPath) : payload, server_forwardHeaders(input.headers, input.base.initialOverrides ?? {}, {
|
|
170
176
|
allowCookie: absoluteTarget ? server_mayForwardCookie(absoluteTarget, input.url) : false,
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* `private, no-store`.
|
|
16
16
|
*/
|
|
17
17
|
import type { ManifestFetch } from '@c15t/core/server';
|
|
18
|
-
import type { C15tResolvedOptions } from '../types';
|
|
19
|
-
import type { FetchGvl } from './manifest-init';
|
|
18
|
+
import type { C15tResolvedOptions } from '../types.js';
|
|
19
|
+
import type { FetchGvl } from './manifest-init.js';
|
|
20
20
|
/**
|
|
21
21
|
* The per-request context a route or the middleware can pass so a
|
|
22
22
|
* background refresh is registered with the platform. Astro adapters that
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* Next.js, Nuxt and SvelteKit layers so no two hosts can disagree about
|
|
6
6
|
* cache lifetimes or revalidation.
|
|
7
7
|
*/
|
|
8
|
-
export { createConsentRouteHandlers, resolveManifestSourceURL, waitUntilFromLocals, } from './handlers';
|
|
9
|
-
export type { ConsentRouteHandlerOptions, RequestLifetime } from './handlers';
|
|
10
|
-
export { loadConsentManifest, resolveManifestInit, resolveManifestSourceFrom, } from './manifest-init';
|
|
11
|
-
export type { FetchGvl, RequestSource, ResolvedInitOutput, } from './manifest-init';
|
|
8
|
+
export { createConsentRouteHandlers, resolveManifestSourceURL, waitUntilFromLocals, } from './handlers.js';
|
|
9
|
+
export type { ConsentRouteHandlerOptions, RequestLifetime } from './handlers.js';
|
|
10
|
+
export { loadConsentManifest, resolveManifestInit, resolveManifestSourceFrom, resolveSessionReportURL, } from './manifest-init.js';
|
|
11
|
+
export type { FetchGvl, RequestSource, ResolvedInitOutput, SessionReportTarget, } from './manifest-init.js';
|
|
12
12
|
export { clearManifestCache, createManifestRequestURL, fetchCachedManifest, getManifestSMaxAge, getManifestStaleWhileRevalidate, MANIFEST_DEDUPE_TTL_SECONDS, MANIFEST_PASSTHROUGH_HEADERS, } from '@c15t/core/server';
|
|
13
13
|
export type { CachedManifestResponse, FetchCachedManifestOptions, ManifestFetch, ManifestSourceConfig, } from '@c15t/core/server';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ManifestFetch } from '@c15t/core/server';
|
|
2
|
-
import type { ConsentManifest, ConsentManifestGVLReference, ConsentRequestHeaderInputs, GlobalVendorList, InitOutput } from '@c15t/schema/types';
|
|
3
|
-
import type { C15tResolvedOptions } from '../types';
|
|
2
|
+
import type { ConsentManifest, ConsentManifestGVLReference, ConsentRequestHeaderInputs, ConsentSessionSource, GlobalVendorList, InitOutput } from '@c15t/schema/types';
|
|
3
|
+
import type { C15tResolvedOptions } from '../types.js';
|
|
4
4
|
/** Fetches the Global Vendor List when the resolved policy is IAB. */
|
|
5
5
|
export type FetchGvl = (input: {
|
|
6
6
|
reference: ConsentManifestGVLReference;
|
|
@@ -56,6 +56,30 @@ export declare const defaultFetchGvl: FetchGvl;
|
|
|
56
56
|
export type ResolvedInitOutput = InitOutput & {
|
|
57
57
|
resolvedOverrides?: Record<string, unknown>;
|
|
58
58
|
};
|
|
59
|
+
/** How a resolution reports itself to the backend's `POST /sessions`. */
|
|
60
|
+
export interface SessionReportTarget {
|
|
61
|
+
/** Where the resolution happened. */
|
|
62
|
+
source: ConsentSessionSource;
|
|
63
|
+
/** The visitor's request headers; only IP chain and user agent travel. */
|
|
64
|
+
headers: Headers;
|
|
65
|
+
/** Absolute backend URL, or `undefined` to send no report. */
|
|
66
|
+
backendURL: string | undefined;
|
|
67
|
+
/** The request's method, when there is one; only a `GET` is reported. */
|
|
68
|
+
method?: string;
|
|
69
|
+
/** Keeps the detached report alive on runtimes that need it. */
|
|
70
|
+
waitUntil?: (task: Promise<void>) => void;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Where a resolution reports sessions, when it can: an absolute backend,
|
|
74
|
+
* read as configured rather than resolved against the request. A relative
|
|
75
|
+
* backend resolved to this site's origin is its own injected route, not a
|
|
76
|
+
* backend, and means no report; nothing is inferred from a manifest URL.
|
|
77
|
+
* `undefined` when reporting is off or nothing absolute is set.
|
|
78
|
+
*
|
|
79
|
+
* @param options - The resolved integration options.
|
|
80
|
+
* @returns The backend base URL, or `undefined`.
|
|
81
|
+
*/
|
|
82
|
+
export declare const resolveSessionReportURL: (options: C15tResolvedOptions) => string | undefined;
|
|
59
83
|
/**
|
|
60
84
|
* Resolve one request's `/init` payload from an already-loaded manifest.
|
|
61
85
|
*
|
|
@@ -70,4 +94,6 @@ export declare const resolveManifestInit: (input: {
|
|
|
70
94
|
/** Same-origin init route that serves versioned public lists. */
|
|
71
95
|
gvlRoute?: string;
|
|
72
96
|
fetchGvl?: FetchGvl;
|
|
97
|
+
/** Session report to send once resolved. Absent means none. */
|
|
98
|
+
report?: SessionReportTarget;
|
|
73
99
|
}) => Promise<ResolvedInitOutput>;
|
package/dist-types/client.d.ts
CHANGED
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import type { ConsentSnapshot, ConsentState, KernelUser, Unsubscribe } from '@c15t/core';
|
|
22
22
|
import type { ConsentRuntime } from '@c15t/core/runtime';
|
|
23
|
-
import type { C15tClientOptionsExtension, C15tResolvedOptions } from './types';
|
|
24
|
-
import type { ConsentDialogKind } from './ui/adapter';
|
|
23
|
+
import type { C15tClientOptionsExtension, C15tResolvedOptions } from './types.js';
|
|
24
|
+
import type { ConsentDialogKind } from './ui/adapter.js';
|
|
25
25
|
/** Attribute the server-rendered banner puts on its action buttons. */
|
|
26
26
|
export declare const ACTION_ATTRIBUTE = "data-c15t-action";
|
|
27
27
|
/** Attribute selecting which dialog a `customize` action opens. */
|
|
@@ -145,8 +145,8 @@ export declare const openDialog: (kind?: ConsentDialogKind, tab?: "purposes" | "
|
|
|
145
145
|
* open the preference centre.
|
|
146
146
|
*/
|
|
147
147
|
export declare const preloadDialog: () => Promise<void>;
|
|
148
|
-
export { activateGatedScripts } from './browser/inline-scripts';
|
|
148
|
+
export { activateGatedScripts } from './browser/inline-scripts.js';
|
|
149
149
|
export type { ConsentRuntime } from '@c15t/core/runtime';
|
|
150
|
-
export type { ConsentDialogKind } from './ui/adapter';
|
|
151
|
-
export { registerDialogAdapter, registerDialogSurface } from './ui/adapter';
|
|
152
|
-
export type { ConsentDialogAdapter, ConsentDialogContext, ConsentDialogHandle, ConsentDialogSurfaceLoader, } from './ui/adapter';
|
|
150
|
+
export type { ConsentDialogKind } from './ui/adapter.js';
|
|
151
|
+
export { registerDialogAdapter, registerDialogSurface } from './ui/adapter.js';
|
|
152
|
+
export type { ConsentDialogAdapter, ConsentDialogContext, ConsentDialogHandle, ConsentDialogSurfaceLoader, } from './ui/adapter.js';
|
package/dist-types/index.d.ts
CHANGED
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
* });
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
|
-
export { c15t, c15t as default, resolveOptions } from './integration';
|
|
23
|
-
export { createConsentMiddleware } from './middleware-handler';
|
|
24
|
-
export type { ConsentMiddlewareOptions } from './middleware-handler';
|
|
25
|
-
export { hostedMode as hosted, manifestMode as manifest, offlineMode as offline, resolveTransportFactory, custom, } from './mode';
|
|
26
|
-
export type { ManifestClientEndpoints } from './mode';
|
|
27
|
-
export type { C15tAstroOptions, C15tClientOptionsExtension, C15tColorScheme, C15tEndpointOptions, C15tHostedDescriptor, C15tI18nOptions, C15tIABOptions, C15tLocals, C15tManifestDescriptor, C15tMiddlewareOptions, C15tModeDescriptor, C15tOfflineDescriptor, C15tResolvedOptions, C15tUIAdapterName, } from './types';
|
|
28
|
-
export type { ConsentDialogAdapter, ConsentDialogContext, ConsentDialogHandle, ConsentDialogKind, ConsentDialogSurfaceLoader, } from './ui/adapter';
|
|
29
|
-
export { registerDialogAdapter, registerDialogSurface } from './ui/adapter';
|
|
22
|
+
export { c15t, c15t as default, resolveOptions } from './integration.js';
|
|
23
|
+
export { createConsentMiddleware } from './middleware-handler.js';
|
|
24
|
+
export type { ConsentMiddlewareOptions } from './middleware-handler.js';
|
|
25
|
+
export { hostedMode as hosted, manifestMode as manifest, offlineMode as offline, resolveTransportFactory, custom, } from './mode.js';
|
|
26
|
+
export type { ManifestClientEndpoints } from './mode.js';
|
|
27
|
+
export type { C15tAstroOptions, C15tClientOptionsExtension, C15tColorScheme, C15tEndpointOptions, C15tHostedDescriptor, C15tI18nOptions, C15tIABOptions, C15tLocals, C15tManifestDescriptor, C15tMiddlewareOptions, C15tModeDescriptor, C15tOfflineDescriptor, C15tResolvedOptions, C15tUIAdapterName, } from './types.js';
|
|
28
|
+
export type { ConsentDialogAdapter, ConsentDialogContext, ConsentDialogHandle, ConsentDialogKind, ConsentDialogSurfaceLoader, } from './ui/adapter.js';
|
|
29
|
+
export { registerDialogAdapter, registerDialogSurface } from './ui/adapter.js';
|
|
30
30
|
export type { ConsentRuntime, ConsentRuntimeOptions } from '@c15t/core/runtime';
|
|
31
31
|
export type { AllConsentNames, ConsentSnapshot, ConsentState, KernelConfig, LegalLinks, PolicyRule, Script, StorageConfig, } from '@c15t/core';
|
|
32
32
|
export { policyRulePresets } from '@c15t/core';
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* options to all of the above.
|
|
15
15
|
*/
|
|
16
16
|
import type { AstroIntegration } from 'astro';
|
|
17
|
-
import type { C15tAstroOptions, C15tResolvedOptions } from './types';
|
|
17
|
+
import type { C15tAstroOptions, C15tResolvedOptions } from './types.js';
|
|
18
18
|
/**
|
|
19
19
|
* Normalize user options into the serializable shape every consumer reads.
|
|
20
20
|
*
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* tests and advanced setups bind it to their own.
|
|
7
7
|
*/
|
|
8
8
|
import type { MiddlewareHandler } from 'astro';
|
|
9
|
-
import type { C15tResolvedOptions } from './types';
|
|
9
|
+
import type { C15tResolvedOptions } from './types.js';
|
|
10
10
|
/** Options for {@link createConsentMiddleware}. */
|
|
11
11
|
export interface ConsentMiddlewareOptions {
|
|
12
12
|
/** Override fetch, mainly for tests. */
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* endpoints and server islands alike — sees `Astro.locals.c15t` already
|
|
6
6
|
* populated. See {@link createConsentMiddleware} for what it does.
|
|
7
7
|
*/
|
|
8
|
-
import type { C15tLocals } from './types';
|
|
8
|
+
import type { C15tLocals } from './types.js';
|
|
9
9
|
declare global {
|
|
10
10
|
namespace App {
|
|
11
11
|
interface Locals {
|
|
@@ -16,5 +16,5 @@ declare global {
|
|
|
16
16
|
}
|
|
17
17
|
export declare const onRequest: import("astro").MiddlewareHandler;
|
|
18
18
|
export default onRequest;
|
|
19
|
-
export { createConsentMiddleware } from './middleware-handler';
|
|
20
|
-
export type { ConsentMiddlewareOptions } from './middleware-handler';
|
|
19
|
+
export { createConsentMiddleware } from './middleware-handler.js';
|
|
20
|
+
export type { ConsentMiddlewareOptions } from './middleware-handler.js';
|
package/dist-types/mode.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { custom } from '@c15t/core';
|
|
10
10
|
import type { ProviderTransportFactory } from '@c15t/core';
|
|
11
|
-
import type { C15tHostedDescriptor, C15tManifestDescriptor, C15tModeDescriptor, C15tOfflineDescriptor } from './types';
|
|
11
|
+
import type { C15tHostedDescriptor, C15tManifestDescriptor, C15tModeDescriptor, C15tOfflineDescriptor } from './types.js';
|
|
12
12
|
/**
|
|
13
13
|
* Talk to a c15t backend over HTTP.
|
|
14
14
|
*
|
package/dist-types/server.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ConsentSnapshot, KernelConfig, KernelTranslations } from '@c15t/core';
|
|
2
2
|
import type { ConsentRequestHeaderInputs } from '@c15t/schema/types';
|
|
3
|
-
import type { C15tColorScheme, C15tLocals, C15tResolvedOptions } from './types';
|
|
3
|
+
import type { C15tColorScheme, C15tLocals, C15tResolvedOptions } from './types.js';
|
|
4
4
|
/** Input for {@link resolveConsentContext}. */
|
|
5
5
|
export interface ResolveConsentContextOptions {
|
|
6
6
|
/** The incoming request headers. */
|
package/dist-types/types.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* all import. Callbacks and other live values belong in the module named
|
|
8
8
|
* by {@link C15tAstroOptions.clientEntrypoint}.
|
|
9
9
|
*/
|
|
10
|
-
import type { AllConsentNames, ConsentSnapshot, ConsentPresentation, KernelConfig, LegalLinks, Script, StorageConfig } from '@c15t/core';
|
|
10
|
+
import type { AllConsentNames, ClearOnRevocationConfig, ConsentSnapshot, ConsentPresentation, KernelConfig, LegalLinks, Script, StorageConfig } from '@c15t/core';
|
|
11
11
|
import type { PolicyRule, PolicyResolution, ConsentManifest, GlobalVendorList } from '@c15t/schema/types';
|
|
12
12
|
import type { Theme } from '@c15t/ui/theme';
|
|
13
13
|
/** Transport selection, in a form that survives serialization. */
|
|
@@ -42,6 +42,15 @@ export interface C15tManifestDescriptor {
|
|
|
42
42
|
backendURL?: string;
|
|
43
43
|
/** Inline manifest. Takes precedence over `manifestURL`. */
|
|
44
44
|
manifest?: ConsentManifest;
|
|
45
|
+
/**
|
|
46
|
+
* Report each init the server resolves, in the middleware and the init
|
|
47
|
+
* route, to the backend's `POST /sessions`, server-to-server and
|
|
48
|
+
* detached from the response, so the backend still counts visitors it
|
|
49
|
+
* never served `/init` to. Set `false` to send none.
|
|
50
|
+
*
|
|
51
|
+
* @default true
|
|
52
|
+
*/
|
|
53
|
+
reportSessions?: boolean;
|
|
45
54
|
}
|
|
46
55
|
/**
|
|
47
56
|
* Which framework renders the on-demand dialog islands.
|
|
@@ -113,6 +122,8 @@ export interface C15tAstroOptions {
|
|
|
113
122
|
consentCategories?: AllConsentNames[];
|
|
114
123
|
/** Consent-gated scripts handed to the core script loader. */
|
|
115
124
|
scripts?: Script[];
|
|
125
|
+
/** Browser data to remove when its consent permission is revoked. */
|
|
126
|
+
clearOnRevocation?: ClearOnRevocationConfig;
|
|
116
127
|
/**
|
|
117
128
|
* IAB TCF configuration. `false` disables it.
|
|
118
129
|
*
|
|
@@ -243,6 +254,8 @@ export interface C15tI18nOptions {
|
|
|
243
254
|
*/
|
|
244
255
|
export interface C15tClientOptionsExtension {
|
|
245
256
|
scripts?: Script[];
|
|
257
|
+
/** Overrides cleanup targets from the integration options. */
|
|
258
|
+
clearOnRevocation?: ClearOnRevocationConfig;
|
|
246
259
|
callbacks?: Record<string, unknown>;
|
|
247
260
|
/** Merged over the serialized theme. */
|
|
248
261
|
theme?: Theme;
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* that is the only place a framework specifier appears.
|
|
16
16
|
*/
|
|
17
17
|
import type { ConsentRuntime } from '@c15t/core/runtime';
|
|
18
|
-
import type { C15tResolvedOptions, C15tUIAdapterName } from '../types';
|
|
18
|
+
import type { C15tResolvedOptions, C15tUIAdapterName } from '../types.js';
|
|
19
19
|
/** Which dialog a caller asked for. */
|
|
20
20
|
export type ConsentDialogKind = 'preferences' | 'iab';
|
|
21
21
|
/** Context handed to an adapter when a dialog opens. */
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* and theme tokens the banner and dialog both read.
|
|
8
8
|
*/
|
|
9
9
|
import type { ConsentRuntime } from '@c15t/core/runtime';
|
|
10
|
-
import type { C15tResolvedOptions } from '../types';
|
|
10
|
+
import type { C15tResolvedOptions } from '../types.js';
|
|
11
11
|
/**
|
|
12
12
|
* The slice of the integration options a dialog island renders with.
|
|
13
13
|
*
|
package/dist-types/ui/react.d.ts
CHANGED
|
@@ -14,6 +14,6 @@
|
|
|
14
14
|
* here: a `.tsx` file can only be compiled by the consuming app's build,
|
|
15
15
|
* and only that build knows whether `@astrojs/react` is present.
|
|
16
16
|
*/
|
|
17
|
-
import type { ConsentDialogAdapter } from './adapter';
|
|
17
|
+
import type { ConsentDialogAdapter } from './adapter.js';
|
|
18
18
|
/** The React 18/19 dialog surface implementation. */
|
|
19
19
|
export declare const reactDialogAdapter: ConsentDialogAdapter;
|
|
@@ -16,6 +16,6 @@
|
|
|
16
16
|
* its `runtime` prop, so there is one kernel per page no matter how many
|
|
17
17
|
* islands, scripts or frameworks read it.
|
|
18
18
|
*/
|
|
19
|
-
import type { ConsentDialogAdapter } from './adapter';
|
|
19
|
+
import type { ConsentDialogAdapter } from './adapter.js';
|
|
20
20
|
/** The Svelte 5 dialog surface implementation. */
|
|
21
21
|
export declare const svelteDialogAdapter: ConsentDialogAdapter;
|
package/dist-types/ui/vue.d.ts
CHANGED
|
@@ -14,6 +14,6 @@
|
|
|
14
14
|
* here: a `.vue` file can only be compiled by the consuming app's build,
|
|
15
15
|
* and only that build knows whether `@astrojs/vue` is present.
|
|
16
16
|
*/
|
|
17
|
-
import type { ConsentDialogAdapter } from './adapter';
|
|
17
|
+
import type { ConsentDialogAdapter } from './adapter.js';
|
|
18
18
|
/** The Vue 3 dialog surface implementation. */
|
|
19
19
|
export declare const vueDialogAdapter: ConsentDialogAdapter;
|
package/docs/README.md
CHANGED
|
@@ -45,14 +45,17 @@ These docs describe v3. Start with Inth hosted setup, identify the framework, ro
|
|
|
45
45
|
- [Ahrefs Analytics](./integrations/ahrefs-analytics.md): Configure Ahrefs Analytics with c15t v3, understand measurement permission and verify loading and revocation.
|
|
46
46
|
- [Amplitude](./integrations/amplitude.md): Configure Amplitude with c15t v3, understand measurement permission and verify loading and revocation.
|
|
47
47
|
- [Custom integrations](./integrations/building-integrations.md): Define loading, initialization and consent-change behavior for a vendor without a helper.
|
|
48
|
+
- [Clear on revocation](./integrations/clear-on-revocation.md): Remove configured first-party cookies and Web Storage keys when their consent category is denied.
|
|
48
49
|
- [Clearbit](./integrations/clearbit.md): Configure Clearbit with c15t v3, understand marketing permission and verify loading and revocation.
|
|
49
50
|
- [Cloudflare Web Analytics](./integrations/cloudflare-web-analytics.md): Configure Cloudflare Web Analytics with c15t v3, understand measurement permission and verify loading and revocation.
|
|
51
|
+
- [Cloudflare Zaraz](./integrations/cloudflare-zaraz.md): Synchronize c15t permissions with Zaraz purposes while Cloudflare manages your tools.
|
|
50
52
|
- [Crisp](./integrations/crisp.md): Configure Crisp with c15t v3, understand functionality permission and verify loading and revocation.
|
|
51
53
|
- [Databuddy](./integrations/databuddy.md): Configure Databuddy's initial and updated consent state with c15t v3.
|
|
52
54
|
- [Fathom Analytics](./integrations/fathom-analytics.md): Configure Fathom Analytics with c15t v3, understand measurement permission and verify loading and revocation.
|
|
53
55
|
- [Google Maps](./integrations/google-maps.md): Prevent a map iframe from mounting before the required permission.
|
|
54
56
|
- [Google Tag](./integrations/google-tag.md): Configure gtag with c15t Consent Mode signals and understand its loading behavior.
|
|
55
57
|
- [Google Tag Manager](./integrations/google-tag-manager.md): Load GTM with c15t consent signals and verify the tags inside your container.
|
|
58
|
+
- [Granular consent](./integrations/granular-consent.md): Let visitors grant a category and still turn one vendor off, without adopting IAB TCF.
|
|
56
59
|
- [Heap](./integrations/heap.md): Configure Heap with c15t v3, understand measurement permission and verify loading and revocation.
|
|
57
60
|
- [Hightouch](./integrations/hightouch.md): Configure Hightouch with c15t v3, understand measurement permission and verify loading and revocation.
|
|
58
61
|
- [Hotjar](./integrations/hotjar.md): Configure Hotjar with c15t v3, understand measurement permission and verify loading and revocation.
|
|
@@ -119,7 +119,11 @@ stale and refresh it in the background. On adapters that expose
|
|
|
119
119
|
`locals.runtime.ctx.waitUntil` (Cloudflare) the refresh is handed to it so it
|
|
120
120
|
is not cut short when the response is sent; nothing is needed from you. For
|
|
121
121
|
another lifetime API, pass `onBackgroundRevalidate` to
|
|
122
|
-
`createConsentRouteHandlers` or `resolveConsentContext`.
|
|
122
|
+
`createConsentRouteHandlers` or `resolveConsentContext`. Session reports go
|
|
123
|
+
through the same hook: after each resolution, in the middleware and the init
|
|
124
|
+
route, the server posts a small report to the backend's `POST /sessions` so
|
|
125
|
+
the backend still counts visitors it never served `/init` to. Set
|
|
126
|
+
`reportSessions: false` on `manifest()` to send none.
|
|
123
127
|
|
|
124
128
|
The framework integration must appear before `c15t()`. For React or Vue, install
|
|
125
129
|
that framework's Astro integration and c15t adapter, register the matching
|
|
@@ -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.
|