@c15t/react 3.0.0-alpha.4 → 3.0.0-alpha.5
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 +2 -1
- package/dist/component-hooks/use-headless-consent-ui.js +1 -1
- package/dist/component-hooks/use-headless-iab-consent-ui.js +1 -1
- package/dist/components/preferences/atoms/accordion.js +1 -1
- package/dist/components/shared/primitives/button.js +1 -1
- package/dist/draft-context.js +2 -0
- package/dist/draft.js +1 -1
- package/dist/external-iab-context.js +1 -1
- package/dist/gpp.js +2 -0
- package/dist/hooks/use-color-scheme.js +1 -1
- package/dist/hooks.js +1 -1
- package/dist/index-parts/consent-banner.js +1 -0
- package/dist/index-parts/consent-dialog-link.js +1 -0
- package/dist/index-parts/consent-dialog-trigger.js +1 -0
- package/dist/index-parts/consent-dialog.js +1 -0
- package/dist/index-parts/consent-gate.js +1 -0
- package/dist/index-parts/core.js +1 -0
- package/dist/index-parts/draft.js +1 -0
- package/dist/index-parts/hooks.js +1 -0
- package/dist/index-parts/module-hooks.js +1 -0
- package/dist/index-parts/provider.js +1 -0
- package/dist/index-parts/theme.js +1 -0
- package/dist/index-parts/translations.js +1 -0
- package/dist/index.js +1 -1
- package/dist/kernel-selector.js +1 -1
- package/dist/module-hooks/iframe-blocker.js +1 -1
- package/dist/provider.js +1 -1
- package/dist/version.js +1 -1
- package/dist-types/draft-context.d.ts +31 -0
- package/dist-types/draft.d.ts +13 -36
- package/dist-types/gpp.d.ts +27 -0
- package/dist-types/hooks.d.ts +3 -0
- package/dist-types/index-parts/consent-banner.d.ts +7 -0
- package/dist-types/index-parts/consent-dialog-link.d.ts +7 -0
- package/dist-types/index-parts/consent-dialog-trigger.d.ts +7 -0
- package/dist-types/index-parts/consent-dialog.d.ts +7 -0
- package/dist-types/index-parts/consent-gate.d.ts +7 -0
- package/dist-types/index-parts/core.d.ts +8 -0
- package/dist-types/index-parts/draft.d.ts +7 -0
- package/dist-types/index-parts/hooks.d.ts +7 -0
- package/dist-types/index-parts/module-hooks.d.ts +7 -0
- package/dist-types/index-parts/provider.d.ts +7 -0
- package/dist-types/index-parts/theme.d.ts +8 -0
- package/dist-types/index-parts/translations.d.ts +7 -0
- package/dist-types/index.d.ts +14 -15
- package/dist-types/kernel-selector.d.ts +0 -8
- package/dist-types/module-hooks/iframe-blocker.d.ts +12 -7
- package/dist-types/provider.d.ts +36 -13
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +2 -1
- package/docs/concepts/consent-state.md +19 -5
- package/docs/customization/translations.md +1 -2
- package/docs/frameworks/react/components/consent-provider.md +6 -2
- package/docs/frameworks/react/components/dev-tools.md +1 -1
- package/docs/frameworks/react/gpp.md +163 -0
- package/docs/integrations/posthog.md +99 -11
- package/docs/upgrade-v3.md +22 -1
- package/package.json +12 -7
- package/dist/ui-save.js +0 -1
- package/dist-types/ui-save.d.ts +0 -25
package/dist-types/index.d.ts
CHANGED
|
@@ -32,31 +32,30 @@
|
|
|
32
32
|
* module wiring around a single per-mount kernel.
|
|
33
33
|
*/
|
|
34
34
|
export type { ConsentKernel, ConsentSnapshot, ConsentState, HostedTransportOptions, InitContext, InitResponse, InitResult, KernelConfig, KernelEvent, KernelOverrides, KernelTransport, KernelUser, Listener, HostedModeOptions, ProviderTransportContext, ProviderTransportFactory, ProviderTransportKind, SavePayload, SaveResult, Unsubscribe, } from '@c15t/core';
|
|
35
|
-
export { createConsentKernel, custom, hosted } from '@c15t/core';
|
|
36
35
|
export type { OfflineModeOptions } from './transports/offline.js';
|
|
37
|
-
export { offline } from './transports/offline.js';
|
|
38
|
-
export { ConsentDialog, ConsentWidget } from './aggregate-components.js';
|
|
39
36
|
export type { ConsentBannerButton, ConsentBannerLayout, ConsentBannerProps, ConsentBannerRight, ConsentBannerRightLinkProps, ConsentBannerRightsProps, ConsentBannerSurface, } from './components/prompt/index.js';
|
|
40
|
-
export { ConsentBanner, type ConsentBannerCompoundComponent, useConsentBannerSurface, } from './components/prompt/index.js';
|
|
41
37
|
export type { ConsentDialogCompoundComponent, ConsentDialogProps, } from './components/panel/index.js';
|
|
42
38
|
export type { ConsentDialogLinkProps } from './components/panel-link/index.js';
|
|
43
|
-
export { ConsentDialogLink } from './components/panel-link/index.js';
|
|
44
39
|
export type { ConsentDialogTriggerProps, ConsentDialogTriggerToolbarAction, ConsentDialogTriggerToolbarPreferences, ConsentDialogTriggerToolbarProps, TriggerOrientation, } from './components/panel-trigger/index.js';
|
|
45
|
-
export { ConsentDialogTrigger, ConsentDialogTriggerToolbar, } from './components/panel-trigger/index.js';
|
|
46
40
|
export type { ConsentWidgetCompoundComponent, ConsentWidgetProps, } from './components/preferences/index.js';
|
|
47
41
|
export type { ConsentGateProps, FrameProps } from './components/consent-gate/index.js';
|
|
48
|
-
export { ConsentGate, Frame } from './components/consent-gate/index.js';
|
|
49
42
|
export type { ConsentDraftHandle, ConsentDraftProviderProps, VendorDraftHandle, } from './draft.js';
|
|
50
|
-
export { ConsentDraftProvider, useConsentDraft, useVendorDraft } from './draft.js';
|
|
51
|
-
export { useTranslations } from './component-hooks/use-translations.js';
|
|
52
|
-
export { useActiveUI, useBranding, useConsent, useConsents, useExperiment, useHasConsentPolicy, useHasConsentPreferences, useHasConsentUI, useIABEnabled, useIABSnapshot, useIdentify, useInit, useLocation, useModel, useOverrides, usePromptPresentation, usePolicyCategories, usePreferencesPresentation, useResolvedPresentation, useResolvedTheme, usePolicyScopeMode, usePurposeConsent, useRegisterConsentCategories, useSaveConsents, useSetActiveUI, useSetLanguage, useSetOverrides, useSnapshot, useSpecialFeatureOptIn, useSubscribeToConsentChanges, useTCString, useUser, useDeclaredVendors, useVendorAllowed, useVendorChoice, useVendorConsent, } from './hooks.js';
|
|
53
43
|
export type { UseIframeBlockerOptions, UseNetworkBlockerOptions, UsePersistenceOptions, UseScriptLoaderOptions, } from './module-hooks.js';
|
|
54
|
-
export { useIframeBlocker, useNetworkBlocker, usePersistence, useScriptLoader, } from './module-hooks.js';
|
|
55
44
|
export type { ConsentProviderOptions, ConsentProviderCallbacks, ConsentProviderPrefetch, ConsentProviderProps, ExternalRuntimeProviderOptions, ExternalRuntimeProviderProps, OwnedRuntimeProviderProps, } from './provider.js';
|
|
56
|
-
export { ConsentProvider } from './provider.js';
|
|
57
|
-
export { ConsentTheme } from './consent-theme.js';
|
|
58
45
|
export type { ConsentThemeProps } from './consent-theme.js';
|
|
46
|
+
export type { Theme } from './types/theme/index.js';
|
|
47
|
+
export type { ConsentBannerCompoundComponent } from './components/prompt/index.js';
|
|
59
48
|
export type { ReactUIOptions } from './types/manager.js';
|
|
60
|
-
export { defineTheme, type Theme } from './types/theme/index.js';
|
|
61
|
-
export { useExplicitChoice, useEffectivePermissions, usePromptRequirement, useNoticeDismissal, usePrivacySignals, usePolicyResolution, usePolicyRule, useRestrictions, useDismissNotice, } from './hooks.js';
|
|
62
49
|
export type { ConsentPresentation, PromptPresentation, PreferencesPresentation, PresentationAction, PromptPosition, PromptVariant, ResolvedConsentPresentation, } from '@c15t/core';
|
|
50
|
+
export * from './index-parts/core.js';
|
|
51
|
+
export * from './index-parts/consent-dialog.js';
|
|
52
|
+
export * from './index-parts/consent-banner.js';
|
|
53
|
+
export * from './index-parts/consent-dialog-link.js';
|
|
54
|
+
export * from './index-parts/consent-dialog-trigger.js';
|
|
55
|
+
export * from './index-parts/consent-gate.js';
|
|
56
|
+
export * from './index-parts/draft.js';
|
|
57
|
+
export * from './index-parts/translations.js';
|
|
58
|
+
export * from './index-parts/module-hooks.js';
|
|
59
|
+
export * from './index-parts/provider.js';
|
|
60
|
+
export * from './index-parts/theme.js';
|
|
61
|
+
export * from './index-parts/hooks.js';
|
|
@@ -56,11 +56,3 @@ export declare const useCategoryAllowed: (category: AllConsentNames) => boolean;
|
|
|
56
56
|
* @internal
|
|
57
57
|
*/
|
|
58
58
|
export declare const useTranslationLanguage: () => string;
|
|
59
|
-
/**
|
|
60
|
-
* Categories the preference surface lists: `necessary` plus the recorded
|
|
61
|
-
* choice scope, or the policy scope when no choice scope applies.
|
|
62
|
-
*
|
|
63
|
-
* @returns A list whose identity changes only when the scope does.
|
|
64
|
-
* @internal
|
|
65
|
-
*/
|
|
66
|
-
export declare const useDisplayedCategories: () => readonly AllConsentNames[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ConsentKernel } from '@c15t/core';
|
|
2
|
-
import type { IframeBlockerHandle } from '@c15t/core/modules/iframe-blocker';
|
|
2
|
+
import type { IframeBlockerHandle, IframeBlockerOptions } from '@c15t/core/modules/iframe-blocker';
|
|
3
3
|
export interface UseIframeBlockerOptions {
|
|
4
4
|
disableAutomaticBlocking?: boolean;
|
|
5
5
|
}
|
|
@@ -21,13 +21,18 @@ export declare const useIframeBlocker: (options?: UseIframeBlockerOptions) => If
|
|
|
21
21
|
*/
|
|
22
22
|
export declare const watchGatedIframes: (kernel: ConsentKernel, onFound: () => void) => () => void;
|
|
23
23
|
/**
|
|
24
|
-
* The provider's
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* The provider's iframe blocker. Loads the blocker module when the first
|
|
25
|
+
* gated iframe (`data-category` or `data-vendor`) is on the page instead of
|
|
26
|
+
* on every mount, so pages without one never download it. Until then it
|
|
27
|
+
* pauses gated frames that arrive with a `src` consent does not allow.
|
|
27
28
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
29
|
+
* Passed to the provider runtime as its `createIframeBlocker` module.
|
|
30
|
+
*
|
|
31
|
+
* @param options - The kernel and blocker options. With
|
|
32
|
+
* `disableAutomaticBlocking` the module loads at once.
|
|
33
|
+
* @returns A handle; `processAllIframes()` reaches the blocker once it has
|
|
34
|
+
* loaded.
|
|
30
35
|
* @internal
|
|
31
36
|
*/
|
|
32
|
-
export declare const
|
|
37
|
+
export declare const createIframeBlockerOnDemand: ({ disableAutomaticBlocking, kernel, }: IframeBlockerOptions) => IframeBlockerHandle;
|
|
33
38
|
export type { IframeBlockerHandle };
|
package/dist-types/provider.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { AllConsentNames, ClearOnRevocationConfig, ConsentExperiment,
|
|
1
|
+
import type { AllConsentNames, Callbacks, ClearOnRevocationConfig, ConsentExperiment, ConsentPresentation, ExperimentState, I18nConfig, KernelConfig, KernelOverrides, KernelUser, LegalLinks, ProviderTransportFactory, StorageConfig, User, Vendor } from '@c15t/core';
|
|
2
2
|
import type { Script } from '@c15t/core/modules/script-loader';
|
|
3
|
-
import type { ConsentControlOptions
|
|
3
|
+
import type { ConsentControlOptions } from '@c15t/core/runtime';
|
|
4
|
+
import type { ConsentRuntime, ResolveStreamedInit } from '@c15t/core/runtime/provider';
|
|
4
5
|
import type { ReactNode } from 'react';
|
|
5
6
|
import type { DialogPreload } from './chunk-warming.js';
|
|
6
7
|
import type { UseNetworkBlockerOptions, UsePersistenceOptions, UseScriptLoaderOptions } from './module-hooks.js';
|
|
@@ -56,6 +57,12 @@ export interface ConsentProviderOptions extends ConsentControlOptions, Pick<Reac
|
|
|
56
57
|
* ```
|
|
57
58
|
*/
|
|
58
59
|
mode: ProviderTransportFactory;
|
|
60
|
+
/**
|
|
61
|
+
* Where the visitor's choice is stored. Read once, like `persistence`:
|
|
62
|
+
* the stored records and the data clearing that protects them stay at
|
|
63
|
+
* the location the provider mounted with. Outside production, a change
|
|
64
|
+
* logs a warning; remount the provider to move storage.
|
|
65
|
+
*/
|
|
59
66
|
storageConfig?: StorageConfig;
|
|
60
67
|
user?: User | KernelUser;
|
|
61
68
|
overrides?: KernelOverrides;
|
|
@@ -123,6 +130,10 @@ export interface ConsentProviderOptions extends ConsentControlOptions, Pick<Reac
|
|
|
123
130
|
* is paused.
|
|
124
131
|
*/
|
|
125
132
|
iframeBlocker?: UseIframeBlockerOptions | false;
|
|
133
|
+
/**
|
|
134
|
+
* Store the visitor's choice in a cookie and localStorage. On by default.
|
|
135
|
+
* Read once, when the provider mounts; see `storageConfig`.
|
|
136
|
+
*/
|
|
126
137
|
persistence?: boolean | UsePersistenceOptions;
|
|
127
138
|
i18n?: Partial<I18nConfig>;
|
|
128
139
|
/** Categories to offer alongside discovered integration categories, within policy scope. */
|
|
@@ -150,6 +161,16 @@ export interface ConsentProviderOptions extends ConsentControlOptions, Pick<Reac
|
|
|
150
161
|
* @internal
|
|
151
162
|
*/
|
|
152
163
|
__debugPkg?: string;
|
|
164
|
+
/**
|
|
165
|
+
* The code that applies a `prefetch` promise, from
|
|
166
|
+
* `@c15t/core/runtime/streamed-init`. Without it the provider loads that
|
|
167
|
+
* code once `prefetch` is a promise, so an app that never streams one
|
|
168
|
+
* doesn't download it. A framework root whose state is usually streamed
|
|
169
|
+
* (`ConsentRoot`) passes it, so the state applies as soon as it arrives
|
|
170
|
+
* instead of after one more request. Read once, at mount.
|
|
171
|
+
* @internal
|
|
172
|
+
*/
|
|
173
|
+
__resolveStreamedInit?: ResolveStreamedInit;
|
|
153
174
|
}
|
|
154
175
|
/**
|
|
155
176
|
* Options accepted when an external runtime supplies the kernel.
|
|
@@ -187,19 +208,21 @@ export type ConsentProviderProps = OwnedRuntimeProviderProps | ExternalRuntimePr
|
|
|
187
208
|
/**
|
|
188
209
|
* v3 ConsentProvider.
|
|
189
210
|
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
211
|
+
* Builds one consent runtime (`createConsentProviderRuntime`) per mounted
|
|
212
|
+
* provider and renders its kernel: the kernel goes into context, and
|
|
213
|
+
* selector hooks subscribe to it through `useSyncExternalStore`. New
|
|
214
|
+
* options reach the runtime through `update()`, which applies only what
|
|
215
|
+
* changed; `mode`, `i18n`, `experiment`, `prefetch`, `persistence`,
|
|
216
|
+
* `storageConfig` and `clearOnRevocation` are read once. While `enabled` is
|
|
217
|
+
* `false` the runtime renders a separate permissive kernel, so toggling it
|
|
218
|
+
* keeps the visitor's records.
|
|
196
219
|
*
|
|
197
220
|
* Pass `runtime` to render a runtime someone else created. The provider
|
|
198
|
-
* then borrows its kernel and
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
221
|
+
* then borrows its kernel and starts nothing — no second `init()`, no
|
|
222
|
+
* second persistence handle, no second `window.c15t` — and does not
|
|
223
|
+
* dispose it on unmount. Handing it a different runtime switches the tree
|
|
224
|
+
* to that runtime's kernel; switching between a borrowed runtime and a
|
|
225
|
+
* provider-built one still needs a remount.
|
|
203
226
|
*
|
|
204
227
|
* @example
|
|
205
228
|
* ```tsx
|
package/dist-types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "3.0.0-alpha.
|
|
1
|
+
export declare const version = "3.0.0-alpha.5";
|
package/docs/README.md
CHANGED
|
@@ -38,6 +38,7 @@ These docs describe c15t v3. Find your app's row in Choose your setup, then foll
|
|
|
38
38
|
- [Content Security Policy](./frameworks/react/content-security-policy.md): Run c15t in a React app under a Content Security Policy, allow the consent backend and vendor hosts, and pass a nonce to ConsentProvider and ConsentTheme.
|
|
39
39
|
- [Customize](./frameworks/react/customize.md): Change the colors, fonts, layout, button styles and copy of the c15t banner and dialog in a React app with the stylesheet, theme tokens, provider options and slots.
|
|
40
40
|
- [Embeds](./frameworks/react/embeds.md): Keep YouTube videos, maps and other iframes out of a React page until their consent category is allowed, with ConsentGate or the iframe blocker in ConsentProvider.
|
|
41
|
+
- [IAB GPP](./frameworks/react/gpp.md): Add the IAB Global Privacy Platform API (__gpp) to a React app with ConsentGPP from @c15t/react/gpp, so ad tech can read US state opt-outs and the TCF EU consent string.
|
|
41
42
|
- [Headless](./frameworks/react/headless.md): Build a custom consent banner in React with the c15t/react/headless hooks inside your ConsentProvider.
|
|
42
43
|
- [Hooks](./frameworks/react/hooks.md): Gate features and save consent choices in React components with the focused hooks exported from c15t/react.
|
|
43
44
|
- [IAB TCF](./frameworks/react/iab.md): Mount the IAB TCF banner and dialog inside a React ConsentProvider and configure the CMP ID, policy and vendor data.
|
|
@@ -111,7 +112,7 @@ These docs describe c15t v3. Find your app's row in Choose your setup, then foll
|
|
|
111
112
|
- [Pinterest Tag](./integrations/pinterest-tag.md): Load the Pinterest Tag only after marketing consent with the c15t pinterestTag helper, guard pintrk event calls, and check it in DevTools.
|
|
112
113
|
- [Pirsch](./integrations/pirsch.md): Load Pirsch Analytics only after measurement consent with the c15t pirsch helper, keep custom event bindings working, and check it in DevTools.
|
|
113
114
|
- [Plausible Analytics](./integrations/plausible-analytics.md): Load the Plausible Analytics tracker only after measurement consent with the c15t plausibleAnalytics helper, and check it in DevTools.
|
|
114
|
-
- [PostHog](./integrations/posthog.md): Load PostHog before or after measurement consent with the c15t posthog helper, choose its cookieless behavior, and sync consent with an SDK you already initialize.
|
|
115
|
+
- [PostHog](./integrations/posthog.md): Load PostHog before or after measurement consent with the c15t posthog helper, choose its cookieless behavior, turn off PostHog modules you do not use, and sync consent with an SDK you already initialize.
|
|
115
116
|
- [Promptwatch](./integrations/promptwatch.md): Load the Promptwatch attribution client only after measurement consent with the c15t promptwatch helper, and check it in DevTools.
|
|
116
117
|
- [Reddit Pixel](./integrations/reddit-pixel.md): Load the Reddit Pixel only after marketing consent with the c15t redditPixel helper, guard rdt conversion calls, and check it in DevTools.
|
|
117
118
|
- [RudderStack](./integrations/rudderstack.md): Load the RudderStack JavaScript SDK after measurement consent with the c15t rudderstack helper, or map c15t categories to destination consent IDs, and check each mode.
|
|
@@ -31,8 +31,9 @@ feature, stay blocked.
|
|
|
31
31
|
|
|
32
32
|
A save records the choice in the browser first and sends it to the backend
|
|
33
33
|
afterwards. The stock banner, preference dialog and IAB surfaces in every
|
|
34
|
-
framework adapter, and the
|
|
35
|
-
and
|
|
34
|
+
framework adapter, and the `acceptAll()`, `rejectAll()` and `save()` methods
|
|
35
|
+
of the browser and Astro clients, close without waiting for the backend. In
|
|
36
|
+
order:
|
|
36
37
|
|
|
37
38
|
1. In the click task, the explicit choice and effective permissions change,
|
|
38
39
|
`onChoiceRecorded` and `onPermissionsChanged` run, gated scripts, iframes
|
|
@@ -52,9 +53,10 @@ and `save()`, close without waiting for the backend. In order:
|
|
|
52
53
|
|
|
53
54
|
A failed request does not reopen the surface or roll the choice back. The
|
|
54
55
|
kernel emits `command:error`, which reaches the `onError` callback in adapters
|
|
55
|
-
that accept one, and queues the payload in localStorage.
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
that accept one, and queues the payload in localStorage. Where localStorage is
|
|
57
|
+
unavailable, the queue lives in memory until the page unloads. The queue is
|
|
58
|
+
replayed after the next successful initialization and when the browser comes
|
|
59
|
+
back online, up to 10 attempts over 7 days. A replay carries the original action
|
|
58
60
|
time and policy snapshot token, so the backend records when the visitor
|
|
59
61
|
decided, and a duplicate submission resolves to the same consent record. A
|
|
60
62
|
backend that signs policy snapshot tokens rejects a replay made after the
|
|
@@ -66,6 +68,14 @@ after its TC string is encoded, which can wait for the TCF library to load.
|
|
|
66
68
|
If that local step records nothing, for example because the vendor list
|
|
67
69
|
failed to load, the surface comes back so the visitor can try again.
|
|
68
70
|
|
|
71
|
+
Every adapter leaves the same surface after a save: the banner while the
|
|
72
|
+
policy still owes a choice or a notice, and nothing once no prompt is owed,
|
|
73
|
+
while the policy is still loading, or after it failed to resolve. A banner
|
|
74
|
+
the visitor reopened closes too. A save that records nothing new, such as an
|
|
75
|
+
unchanged selection, closes the surface when it resolves successfully. Opening
|
|
76
|
+
or closing a surface, or starting another save, before then leaves the surface
|
|
77
|
+
as the visitor set it.
|
|
78
|
+
|
|
69
79
|
## Preserve records during hydration
|
|
70
80
|
|
|
71
81
|
Server helpers return records with policy information and evaluation time.
|
|
@@ -194,6 +204,10 @@ receive a stale TC string: c15t withdraws it, or holds it back, before
|
|
|
194
204
|
|
|
195
205
|
### Clearing records across tabs
|
|
196
206
|
|
|
207
|
+
`clearRecords()` also drops every save queued for replay, with or without
|
|
208
|
+
browser persistence, so nothing the visitor decided before the clear reaches
|
|
209
|
+
the backend afterwards.
|
|
210
|
+
|
|
197
211
|
`clearRecords()` removes every record and then stores the time of the clear,
|
|
198
212
|
the clear epoch, under its own key: `c15t-epoch` in localStorage and a cookie
|
|
199
213
|
of the same name (`<storageKey>-epoch` with a custom `storageKey`). Clearing
|
|
@@ -68,8 +68,7 @@ The `ConsentGate` placeholder reads the `consentGate` section:
|
|
|
68
68
|
| `consentGate.policyBlocked` | React and Vue show it in place of the title, with no button, when a strict policy leaves the category out of scope. |
|
|
69
69
|
|
|
70
70
|
Earlier versions called this section `frame`. Copy under `frame` in
|
|
71
|
-
`i18n.messages
|
|
72
|
-
still applies. c15t reads it as `consentGate`, a key set under `consentGate`
|
|
71
|
+
`i18n.messages` or custom translations still applies. c15t reads it as `consentGate`, a key set under `consentGate`
|
|
73
72
|
wins over the same key under `frame`, and c15t logs a warning once outside
|
|
74
73
|
production. Rename the section to `consentGate` to remove the warning.
|
|
75
74
|
|
|
@@ -49,8 +49,12 @@ this provider and passes it server-resolved state.
|
|
|
49
49
|
## Provider options
|
|
50
50
|
|
|
51
51
|
Keep the provider mounted across client navigation. It reads `mode`,
|
|
52
|
-
`prefetch`, `persistence`, `clearOnRevocation` and
|
|
53
|
-
when it mounts.
|
|
52
|
+
`prefetch`, `persistence`, `storageConfig`, `clearOnRevocation`, `i18n` and
|
|
53
|
+
`experiment` once, when it mounts. Outside production, changing `mode`,
|
|
54
|
+
`i18n`, `experiment`, `persistence` or `storageConfig` logs a warning. Remount
|
|
55
|
+
the provider to change them. `scripts`, `vendors`, `networkBlocker`,
|
|
56
|
+
`iframeBlocker`, `consentCategories`, `overrides`, `user`, `callbacks` and
|
|
57
|
+
`enabled` apply when they change.
|
|
54
58
|
|
|
55
59
|
| Option | Purpose |
|
|
56
60
|
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -95,7 +95,7 @@ explicit scope or policy categories, bulk saves cover all known categories.
|
|
|
95
95
|
| ------------ | -------------------------------------------------------------------------------------------- |
|
|
96
96
|
| **Consents** | Inspect and save categories, accept all, or reject optional categories |
|
|
97
97
|
| **Scripts** | Configured scripts, loading status, search, and external page resources |
|
|
98
|
-
| **Location** |
|
|
98
|
+
| **Location** | Resolved country and region, and location overrides |
|
|
99
99
|
| **Policy** | Resolved policy and UI configuration |
|
|
100
100
|
| **IAB** | Edit vendors, purposes, legitimate interests, and special features; save and copy TC strings |
|
|
101
101
|
| **Events** | Timeline of consent changes, kernel events, and script lifecycle events |
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: IAB GPP
|
|
3
|
+
description: Add the IAB Global Privacy Platform API (__gpp) to a React app with
|
|
4
|
+
ConsentGPP from @c15t/react/gpp, so ad tech can read US state opt-outs and the
|
|
5
|
+
TCF EU consent string.
|
|
6
|
+
group: frameworks
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What GPP does
|
|
10
|
+
|
|
11
|
+
`ConsentGPP` from `@c15t/react/gpp` installs `window.__gpp`, the GPP 1.1 CMP
|
|
12
|
+
API, and keeps its GPP string in step with the visitor's choices. Prebid.js,
|
|
13
|
+
Google Ad Manager and other ad tech read US privacy signals from it.
|
|
14
|
+
|
|
15
|
+
## Turn on GPP
|
|
16
|
+
|
|
17
|
+
Render `ConsentGPP` inside `ConsentProvider`:
|
|
18
|
+
|
|
19
|
+
```tsx title="src/consent.tsx"
|
|
20
|
+
import { ConsentGPP } from '@c15t/react/gpp';
|
|
21
|
+
|
|
22
|
+
<ConsentProvider options={{ mode, scripts }}>
|
|
23
|
+
<ConsentGPP />
|
|
24
|
+
{children}
|
|
25
|
+
</ConsentProvider>;
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`ConsentGPP` renders nothing. It installs `__gpp` after it mounts and
|
|
29
|
+
removes it when it unmounts. It lives in its own entry, like
|
|
30
|
+
`@c15t/react/iab`, so apps that do not import it bundle none of the GPP
|
|
31
|
+
code. `@c15t/react` already depends on `@c15t/iab`; with the `c15t`
|
|
32
|
+
package, import from `c15t/react/gpp`.
|
|
33
|
+
|
|
34
|
+
The props are the GPP options listed below, for example
|
|
35
|
+
`<ConsentGPP usFallback="none" />`. It works the same with a runtime you
|
|
36
|
+
pass to `ConsentProvider` as `runtime`.
|
|
37
|
+
|
|
38
|
+
The GPP string follows the policy and location your backend resolves for the
|
|
39
|
+
visitor, so a US visitor's state comes from the backend. With `offline()`
|
|
40
|
+
mode, pass the state yourself, for example
|
|
41
|
+
`overrides: { country: 'US', region: 'CA' }`.
|
|
42
|
+
|
|
43
|
+
To add the TCF EU section for visitors under an `iab` policy, set up
|
|
44
|
+
[IAB TCF](./iab.md) as well.
|
|
45
|
+
|
|
46
|
+
## How the policy decides the section
|
|
47
|
+
|
|
48
|
+
The policy rule c15t matched for the visitor decides whether a section
|
|
49
|
+
applies. The visitor's location only picks which US section carries it.
|
|
50
|
+
|
|
51
|
+
| Matched rule and visitor | Section in the GPP string |
|
|
52
|
+
| ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
53
|
+
| `iab` rule, with IAB TCF set up | `tcfeuv2` (ID 2): the TC String the CMP confirmed, unchanged |
|
|
54
|
+
| `iab` rule, any visitor, with `tcf: false` | None; `applicableSections` is `[-1]` |
|
|
55
|
+
| Any other rule with the `preferences` or `opt-out` right, US visitor in a state with a section | That state's section, such as `usca` (ID 8) |
|
|
56
|
+
| The same rule, US visitor whose region is unknown or whose state has no section | `usnat` (ID 7), MSPA US National version 2; none with `usFallback: 'none'` |
|
|
57
|
+
| The same rule, `usApproach: 'national'` | `usnat` for every US visitor |
|
|
58
|
+
| A rule without those rights, such as `none` | None |
|
|
59
|
+
| A visitor outside the US under any rule other than `iab` | None |
|
|
60
|
+
|
|
61
|
+
Every `opt-in` and `opt-out` rule has the `preferences` right, and every
|
|
62
|
+
`opt-out` rule also has `opt-out`. A `none` rule has them only if you add
|
|
63
|
+
them. A rule that gives the visitor no way to opt out produces no US
|
|
64
|
+
section, even when the visitor sends a GPC signal.
|
|
65
|
+
|
|
66
|
+
State sections exist for California, Colorado, Connecticut, Delaware, Florida,
|
|
67
|
+
Iowa, Minnesota, Montana, Nebraska, New Hampshire, New Jersey, Oregon,
|
|
68
|
+
Tennessee, Texas, Utah and Virginia. Indiana, Kentucky, Maryland and Rhode
|
|
69
|
+
Island are not encoded yet: their published specifications start the section
|
|
70
|
+
with a header that the IAB reference implementation does not encode. Visitors
|
|
71
|
+
there get the fallback, `usnat` by default. So does a US visitor whose region
|
|
72
|
+
the geo headers did not supply.
|
|
73
|
+
|
|
74
|
+
The MSPA US National specification describes `usnat` for MSPA signatories
|
|
75
|
+
that chose the national approach. Without `mspaMode`, c15t reports the
|
|
76
|
+
fallback as a transaction the MSPA does not cover (`MspaCoveredTransaction:
|
|
77
|
+
2`), which still carries the opt-outs to vendors such as Prebid.js. If you
|
|
78
|
+
reserve `usnat` for the national approach, set `usFallback: 'none'`; those
|
|
79
|
+
visitors then get no section until their state resolves.
|
|
80
|
+
|
|
81
|
+
## What the US sections report
|
|
82
|
+
|
|
83
|
+
* `SaleOptOut`, `SharingOptOut` and `TargetedAdvertisingOptOut`: `1` (opted
|
|
84
|
+
out) when the `marketing` category is not permitted, otherwise `2`. A
|
|
85
|
+
refusal, a GPC signal the rule maps to `marketing` through
|
|
86
|
+
`privacySignals.gpc`, and an opt-in rule without a grant all count.
|
|
87
|
+
* The opt-out notices: `1` (given), since the rule offers an opt-out.
|
|
88
|
+
* The sharing or processing notice: `1` when the rule has the `disclosure`
|
|
89
|
+
right, otherwise `2`.
|
|
90
|
+
* `Gpc`: the browser's Global Privacy Control signal, in sections that have a
|
|
91
|
+
GPC subsection. It is reported even when the rule does not map GPC to a
|
|
92
|
+
category, so give US rules a `privacySignals.gpc` mapping if the opt-outs
|
|
93
|
+
should follow it too.
|
|
94
|
+
* Sensitive data and known-child consents: `0` (not applicable). c15t has no
|
|
95
|
+
category for them, so the string states that you do not process sensitive
|
|
96
|
+
data or knowingly process children's data. If you do, GPP from c15t does
|
|
97
|
+
not describe your processing; collect and signal that consent separately.
|
|
98
|
+
* `MspaCoveredTransaction`: `2` (not covered) unless you set `mspaMode`.
|
|
99
|
+
|
|
100
|
+
The notice fields are your attestation, made through the rule's rights:
|
|
101
|
+
c15t cannot see whether your privacy notice is on the page. Show the notices
|
|
102
|
+
the rule promises, including a persistent opt-out control.
|
|
103
|
+
|
|
104
|
+
## GPP options
|
|
105
|
+
|
|
106
|
+
Every field is optional. Pass them in the `gpp` option, where `gpp: true`
|
|
107
|
+
uses the defaults, as props on `ConsentGPP` in React, or to `mountGPP()` in
|
|
108
|
+
`@c15t/browser`.
|
|
109
|
+
|
|
110
|
+
| Option | Default | Effect |
|
|
111
|
+
| ------------------ | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
112
|
+
| `cmpId` | the IAB CMP ID c15t holds, else `1` | CMP ID reported by `ping`. The GPP specification has string creators without a registered ID, including MSPA US National creators, use `1`. A TCF EU section needs the registered ID its TC String names. |
|
|
113
|
+
| `usApproach` | `'state'` | `'state'` uses the visitor's state section. `'national'` reports `usnat` for every US visitor; the MSPA reserves it for signatories that chose the national approach. |
|
|
114
|
+
| `usFallback` | `'usnat'` | Under the state approach, the section for a US visitor whose state is unknown or has no section: `'usnat'` or `'none'`. |
|
|
115
|
+
| `mspaMode` | unset | `'opt-out-option'` or `'service-provider'`. Set it only if you signed the IAB Multi-State Privacy Agreement; the transaction is then reported as covered. In service provider mode the opt-outs are reported as not applicable. |
|
|
116
|
+
| `optOutCategories` | `['marketing']` | Categories whose refusal reports an opt-out of sale, sharing and targeted advertising. |
|
|
117
|
+
| `tcf` | `true` | Include the `tcfeuv2` section under an `iab` policy. It needs IAB TCF set up as well. |
|
|
118
|
+
|
|
119
|
+
## Check the signal
|
|
120
|
+
|
|
121
|
+
Open the browser console on a page with GPP on and call:
|
|
122
|
+
|
|
123
|
+
```js
|
|
124
|
+
__gpp('ping', (data) => console.log(data));
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
For a California visitor who has not opted out, the result includes
|
|
128
|
+
`applicableSections: [8]`, `signalStatus: 'ready'` and
|
|
129
|
+
`parsedSections.usca[0].SaleOptOut === 2`. After the visitor refuses
|
|
130
|
+
`marketing`, `SaleOptOut` is `1`. `__gpp('getField', cb, 'usca.SaleOptOut')`
|
|
131
|
+
returns the same value. Scripts in iframes reach the API through the
|
|
132
|
+
`__gppLocator` frame and `postMessage`.
|
|
133
|
+
|
|
134
|
+
Under an `iab` rule, `parsedSections.tcfeuv2` uses the field names of the
|
|
135
|
+
IAB Europe TCF section, such as `PurposeConsent`, `VendorConsent` and
|
|
136
|
+
`PubRestrictions`. `getSection` and `getField` answer `null` for `tcfeuv2`,
|
|
137
|
+
as the IAB reference implementation does: TCF vendors read consent from
|
|
138
|
+
events, not on demand.
|
|
139
|
+
|
|
140
|
+
`signalStatus` stays `'not ready'` while the policy is pending, while the
|
|
141
|
+
banner or dialog is open, while an `iab` rule has no confirmed TC String,
|
|
142
|
+
and while a new TC String is decoded. Listeners added with
|
|
143
|
+
`addEventListener` get `signalStatus: 'not ready'`, then `cmpDisplayStatus`
|
|
144
|
+
and `sectionChange` events, then `signalStatus: 'ready'`.
|
|
145
|
+
|
|
146
|
+
## Ad tags that load before c15t
|
|
147
|
+
|
|
148
|
+
c15t installs `__gpp` in the browser once consent starts, after it loads the
|
|
149
|
+
GPP code. Vendor scripts that call `__gpp` earlier need a stub. c15t takes over
|
|
150
|
+
the calls and listeners a stub queued, whether the stub keeps listeners on
|
|
151
|
+
`__gpp.events`, as the GPP specification's sample does, or returns them from
|
|
152
|
+
`__gpp('events')`, as `@iabgpp/stub` does. Call `initializeGPPStub()` from
|
|
153
|
+
`@c15t/iab/gpp` in your first script, or use the IAB's own stub snippet.
|
|
154
|
+
When another stub already answers iframes, c15t leaves that to it, so each
|
|
155
|
+
iframe call gets one reply.
|
|
156
|
+
|
|
157
|
+
If a CMP that has already loaded owns `__gpp`, c15t leaves it in place.
|
|
158
|
+
The `gpp` option reports the conflict to the `onError` callback,
|
|
159
|
+
`ConsentGPP` logs it, and `mountGPP()` and `createGPP()` throw. Run one GPP
|
|
160
|
+
CMP per page.
|
|
161
|
+
|
|
162
|
+
GPP signals what the visitor chose; it does not block scripts. Gate vendor
|
|
163
|
+
scripts with c15t's script loading as well.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: PostHog
|
|
3
3
|
description: Load PostHog before or after measurement consent with the c15t
|
|
4
|
-
posthog helper, choose its cookieless behavior,
|
|
5
|
-
you already initialize.
|
|
4
|
+
posthog helper, choose its cookieless behavior, turn off PostHog modules you
|
|
5
|
+
do not use, and sync consent with an SDK you already initialize.
|
|
6
6
|
icon: posthog
|
|
7
7
|
group: integrations
|
|
8
8
|
---
|
|
@@ -257,15 +257,20 @@ A kernel you create yourself needs a loader from
|
|
|
257
257
|
|
|
258
258
|
## Options
|
|
259
259
|
|
|
260
|
-
| Option
|
|
261
|
-
|
|
|
262
|
-
| `id`
|
|
263
|
-
| `region`
|
|
264
|
-
| `apiHost`
|
|
265
|
-
| `uiHost`
|
|
266
|
-
| `scriptUrl`
|
|
267
|
-
| `loadMode`
|
|
268
|
-
| `
|
|
260
|
+
| Option | Default | Behavior |
|
|
261
|
+
| ----------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
262
|
+
| `id` | Required | Project token, starting with `phc_`. The helper trims it. Empty or whitespace-only values throw. |
|
|
263
|
+
| `region` | `'eu'` | `'eu'` or `'us'`. Picks the API, UI and loader hosts when you do not set them. |
|
|
264
|
+
| `apiHost` | `https://eu.i.posthog.com` | API host for a proxy or self-hosted PostHog. Without `scriptUrl`, the loader URL becomes `<apiHost>/static/array.js`. |
|
|
265
|
+
| `uiHost` | The region's UI host | UI host, for example `https://eu.posthog.com`. A custom `apiHost` with no `region` uses the API host. |
|
|
266
|
+
| `scriptUrl` | `https://eu-assets.i.posthog.com/static/array.js` | Loader URL override. A blank value falls back to the default. |
|
|
267
|
+
| `loadMode` | `'always'` | When the SDK loads. See the table below. |
|
|
268
|
+
| `features.surveys` | Unset | `false` sets `disable_surveys: true` and skips `surveys.js`. See [turn off features you do not use](#turn-off-features-you-do-not-use). |
|
|
269
|
+
| `features.heatmaps` | Unset, follows the project | Sets `capture_heatmaps`. |
|
|
270
|
+
| `features.deadClicks` | Unset, follows the project | Sets `capture_dead_clicks`. |
|
|
271
|
+
| `features.webVitals` | Unset, follows the project | Sets `capture_performance: { web_vitals }`. Replay network timing keeps following the project. |
|
|
272
|
+
| `features.featureFlags` | Unset, follows the project | `false` sets `advanced_disable_feature_flags: true` and stops `/flags` requests. |
|
|
273
|
+
| `initOptions` | `{ cookieless_mode: 'on_reject', defaults: '2026-01-30' }` | Options passed to `posthog.init`, merged over the defaults and `features`. The helper sets `api_host` and `ui_host` after your values, so change hosts with the options above. |
|
|
269
274
|
|
|
270
275
|
## Loading and revocation
|
|
271
276
|
|
|
@@ -283,6 +288,78 @@ project; see
|
|
|
283
288
|
Set `cookieless_mode: 'never'`, as in the example, if a refusal must stop
|
|
284
289
|
capture.
|
|
285
290
|
|
|
291
|
+
## Turn off features you do not use
|
|
292
|
+
|
|
293
|
+
After `array.js` loads, PostHog reads your `posthog.init` options and the
|
|
294
|
+
project's remote config, then decides which extra modules to download and
|
|
295
|
+
whether to request `/flags`. Set a `features` switch to `false` for each
|
|
296
|
+
feature your site does not use:
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
posthog({
|
|
300
|
+
id: 'phc_YOUR_PROJECT_TOKEN',
|
|
301
|
+
region: 'eu',
|
|
302
|
+
loadMode: 'after-consent',
|
|
303
|
+
features: {
|
|
304
|
+
surveys: false,
|
|
305
|
+
heatmaps: false,
|
|
306
|
+
deadClicks: false,
|
|
307
|
+
webVitals: false,
|
|
308
|
+
featureFlags: false,
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
| Switch | `false` sets | What PostHog skips |
|
|
314
|
+
| -------------- | -------------------------------------------- | --------------------------------------------------------------------------- |
|
|
315
|
+
| `surveys` | `disable_surveys: true` | `surveys.js`, about 29 KB |
|
|
316
|
+
| `heatmaps` | `capture_heatmaps: false` | Heatmap capture. With `deadClicks: false` too, `dead-clicks-autocapture.js` |
|
|
317
|
+
| `deadClicks` | `capture_dead_clicks: false` | `dead-clicks-autocapture.js`, about 8 KB, once heatmaps are off too |
|
|
318
|
+
| `webVitals` | `capture_performance: { web_vitals: false }` | `web-vitals-with-attribution.js`, about 6 KB |
|
|
319
|
+
| `featureFlags` | `advanced_disable_feature_flags: true` | `/flags` requests. The remote config still loads |
|
|
320
|
+
|
|
321
|
+
Sizes are brotli-compressed, measured from posthog-js 1.436.1.
|
|
322
|
+
|
|
323
|
+
An unset switch adds nothing to `posthog.init`. For heatmaps, dead clicks, web
|
|
324
|
+
vitals and feature flags, PostHog then follows the setting in your PostHog
|
|
325
|
+
project. `true` sets the opposite value and overrides the project. For
|
|
326
|
+
`surveys` and `featureFlags`, `true` is PostHog's own default, so it behaves
|
|
327
|
+
the same as unset.
|
|
328
|
+
|
|
329
|
+
Surveys work differently. PostHog downloads `surveys.js` whenever the remote
|
|
330
|
+
config includes a `surveys` value, even when surveys are off in the project.
|
|
331
|
+
`surveys: false` is the only way to skip it.
|
|
332
|
+
|
|
333
|
+
`initOptions` wins over a switch that sets the same key. A
|
|
334
|
+
`capture_performance` value in `initOptions` replaces the whole object that
|
|
335
|
+
`webVitals` builds.
|
|
336
|
+
|
|
337
|
+
### Avoid PostHog's option traps
|
|
338
|
+
|
|
339
|
+
These rules also apply when you pass PostHog options yourself, in
|
|
340
|
+
`initOptions` or in your own `posthog.init`:
|
|
341
|
+
|
|
342
|
+
* Use `advanced_disable_feature_flags: true` to stop `/flags`, not
|
|
343
|
+
`advanced_disable_flags: true`. The second also stops PostHog loading the
|
|
344
|
+
remote config, so session replay never starts and other features fall back to
|
|
345
|
+
local config.
|
|
346
|
+
* With feature flags off, surveys that target a feature flag never show.
|
|
347
|
+
PostHog logs a warning about it. If you need those surveys, leave
|
|
348
|
+
`featureFlags` unset and pass
|
|
349
|
+
`advanced_only_evaluate_survey_feature_flags: true` instead. PostHog still
|
|
350
|
+
requests `/flags`, but evaluates only survey flags.
|
|
351
|
+
* While heatmaps are on, in `posthog.init` or in the project, PostHog loads
|
|
352
|
+
`dead-clicks-autocapture.js` whatever `capture_dead_clicks` says. Turn off
|
|
353
|
+
both to skip it.
|
|
354
|
+
* `capture_performance: false` turns off web vitals and session replay network
|
|
355
|
+
timing. `{ web_vitals: false }`, which `webVitals: false` sets, leaves network
|
|
356
|
+
timing to the project. `capture_performance: true` forces both on.
|
|
357
|
+
|
|
358
|
+
Product tours (`product-tours.js`, about 36 KB) and exception autocapture
|
|
359
|
+
(`exception-autocapture.js`, about 6 KB) load only when the project turns them
|
|
360
|
+
on. To keep them off whatever the project says, pass
|
|
361
|
+
`disable_product_tours: true` or `capture_exceptions: false` in `initOptions`.
|
|
362
|
+
|
|
286
363
|
## Guard your own capture calls
|
|
287
364
|
|
|
288
365
|
Events your code sends need their own permission check. The `posthog` global
|
|
@@ -338,6 +415,11 @@ measurement is denied, so the SDK is told to opt out. `onConsentChange` runs on
|
|
|
338
415
|
every later change. This does not delay the SDK import or its first request.
|
|
339
416
|
`loadMode: 'disabled'` is not a substitute, because it syncs nothing.
|
|
340
417
|
|
|
418
|
+
`features` belongs to the helper, so it does nothing here. To skip modules you
|
|
419
|
+
do not use, pass the PostHog options from
|
|
420
|
+
[turn off features you do not use](#turn-off-features-you-do-not-use) to your
|
|
421
|
+
own `posthog.init`, for example `disable_surveys: true`.
|
|
422
|
+
|
|
341
423
|
## Measure opt-in rate
|
|
342
424
|
|
|
343
425
|
If you run a banner experiment, the backend already counts visitors and
|
|
@@ -355,6 +437,12 @@ With `loadMode: 'always'`, `array.js` loads before a choice instead. Check that
|
|
|
355
437
|
no capture request is sent while measurement is denied, unless you chose
|
|
356
438
|
cookieless capture.
|
|
357
439
|
|
|
440
|
+
If you turned features off, allow measurement and filter the DevTools Network
|
|
441
|
+
panel by `posthog`. Reload the page. You should see `array.js`, the remote
|
|
442
|
+
config and capture requests, but no `/flags` request with `featureFlags: false`
|
|
443
|
+
and none of the modules you turned off, such as `surveys.js` or
|
|
444
|
+
`dead-clicks-autocapture.js`.
|
|
445
|
+
|
|
358
446
|
Test in a private window with an opt-in policy. Open DevTools Network, disable
|
|
359
447
|
the cache and filter by the vendor's domain:
|
|
360
448
|
|