@c15t/react 3.0.0-alpha.9 → 3.0.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 +7 -9
- package/README.md +41 -70
- package/SKILL.md +1 -1
- package/dist/aggregate-components.js +1 -1
- package/dist/components/consent-gate/atoms.js +1 -1
- package/dist/components/consent-gate/frame.js +2 -0
- package/dist/components/consent-gate/index.js +1 -1
- package/dist/components/iab-panel/atoms/root.js +1 -1
- package/dist/components/iab-panel/iab-panel.js +1 -1
- package/dist/components/iab-prompt/atoms/root.js +1 -1
- package/dist/components/iab-prompt/iab-prompt.js +1 -1
- package/dist/components/panel/atoms/root.js +1 -1
- package/dist/components/panel-trigger/atoms/root.js +1 -1
- package/dist/components/panel-trigger/panel-trigger.js +1 -1
- package/dist/components/panel-trigger/toolbar-loader.js +2 -0
- package/dist/components/preferences/atoms/root.js +1 -1
- package/dist/components/prompt/atoms/early-tap-script.js +2 -0
- package/dist/components/prompt/atoms/root.js +1 -1
- package/dist/components/shared/primitives/button.js +1 -1
- package/dist/components/shared/surface-styles.js +1 -1
- package/dist/consent-gate.js +1 -1
- package/dist/context/index.js +1 -1
- package/dist/devtools.js +1 -1
- package/dist/iab/styles.tw3.css +2 -2
- package/dist/iab-dialog-deferred.js +2 -0
- package/dist/iab.js +1 -1
- package/dist/index-parts/consent-gate.js +1 -1
- package/dist/index-parts/core.js +1 -1
- package/dist/index-parts/frame.js +1 -0
- package/dist/index-parts/hosted.js +1 -0
- package/dist/index-parts/offline.js +1 -0
- package/dist/index-parts/presets.js +1 -0
- package/dist/index.js +1 -1
- package/dist/modes.js +1 -0
- package/dist/panel-link.js +1 -1
- package/dist/panel-trigger.js +1 -1
- package/dist/provider.js +1 -1
- package/dist/styles.tw3.css +2 -2
- package/dist/transports/hosted.js +1 -0
- package/dist/transports/manifest.js +1 -0
- package/dist/utils/deferred-module.js +1 -1
- package/dist/version.js +1 -1
- package/dist-types/chunk-warming.d.ts +7 -6
- package/dist-types/components/consent-gate/frame.d.ts +19 -0
- package/dist-types/components/consent-gate/index.d.ts +3 -19
- package/dist-types/components/iab-prompt/iab-prompt.d.ts +1 -1
- package/dist-types/components/panel/index.d.ts +1 -1
- package/dist-types/components/panel-trigger/toolbar-loader.d.ts +34 -0
- package/dist-types/components/preferences/index.d.ts +1 -1
- package/dist-types/components/prompt/atoms/early-tap-script.d.ts +17 -0
- package/dist-types/components/prompt/index.d.ts +1 -1
- package/dist-types/components/shared/surface-styles.d.ts +26 -2
- package/dist-types/consent-gate.d.ts +1 -1
- package/dist-types/context/index.d.ts +3 -3
- package/dist-types/context.d.ts +2 -0
- package/dist-types/gpp.d.ts +1 -1
- package/dist-types/iab-dialog-deferred.d.ts +36 -0
- package/dist-types/iab.d.ts +3 -2
- package/dist-types/index-parts/consent-gate.d.ts +1 -1
- package/dist-types/index-parts/core.d.ts +1 -2
- package/dist-types/index-parts/frame.d.ts +7 -0
- package/dist-types/index-parts/hosted.d.ts +7 -0
- package/dist-types/index-parts/offline.d.ts +7 -0
- package/dist-types/index-parts/presets.d.ts +7 -0
- package/dist-types/index.d.ts +5 -1
- package/dist-types/modes.d.ts +26 -0
- package/dist-types/panel-link.d.ts +1 -1
- package/dist-types/panel-trigger.d.ts +1 -1
- package/dist-types/provider.d.ts +3 -3
- package/dist-types/transports/hosted.d.ts +36 -0
- package/dist-types/transports/manifest.d.ts +48 -0
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +7 -9
- package/docs/concepts/choose-your-setup.md +45 -10
- package/docs/concepts/consent-categories.md +1 -1
- package/docs/concepts/consent-state.md +5 -2
- package/docs/concepts/data-fetching.md +100 -42
- package/docs/concepts/modes.md +281 -0
- package/docs/customization/dark-mode.md +1 -1
- package/docs/customization/motion.md +2 -2
- package/docs/customization/recipes.md +4 -4
- package/docs/customization/slots.md +25 -25
- package/docs/customization/stylesheets.md +12 -14
- package/docs/customization/tailwind.md +17 -11
- package/docs/customization/tokens.md +36 -7
- package/docs/frameworks/react/components/consent-banner.md +14 -10
- package/docs/frameworks/react/components/consent-dialog.md +14 -10
- package/docs/frameworks/react/components/consent-provider.md +51 -44
- package/docs/frameworks/react/components.md +14 -10
- package/docs/frameworks/react/content-security-policy.md +21 -12
- package/docs/frameworks/react/hooks.md +2 -2
- package/docs/frameworks/react/iab.md +20 -2
- package/docs/frameworks/react/quickstart.md +63 -97
- package/docs/frameworks/react/rendering.md +168 -94
- package/docs/frameworks/react/scripts.md +19 -28
- package/docs/frameworks/react/troubleshooting.md +57 -25
- package/docs/frameworks/react/upgrade-v3.md +110 -62
- package/docs/guides/banner-experiments.md +21 -6
- package/docs/guides/troubleshooting.md +89 -25
- package/docs/guides/verify-consent.md +23 -8
- package/docs/integrations/adobe-analytics.md +60 -64
- package/docs/integrations/ahrefs-analytics.md +58 -63
- package/docs/integrations/amplitude.md +60 -64
- package/docs/integrations/clearbit.md +59 -63
- package/docs/integrations/cloudflare-web-analytics.md +56 -60
- package/docs/integrations/cloudflare-zaraz.md +55 -57
- package/docs/integrations/crisp.md +64 -69
- package/docs/integrations/databuddy.md +62 -64
- package/docs/integrations/fathom-analytics.md +56 -60
- package/docs/integrations/front-chat.md +56 -60
- package/docs/integrations/google-maps.md +25 -13
- package/docs/integrations/google-tag-manager.md +153 -77
- package/docs/integrations/google-tag.md +134 -78
- package/docs/integrations/heap.md +56 -60
- package/docs/integrations/hightouch.md +55 -60
- package/docs/integrations/hotjar.md +60 -64
- package/docs/integrations/intercom.md +55 -60
- package/docs/integrations/klaviyo.md +65 -66
- package/docs/integrations/linkedin-insights.md +58 -63
- package/docs/integrations/logrocket.md +55 -60
- package/docs/integrations/matomo-analytics.md +58 -60
- package/docs/integrations/meta-pixel.md +56 -60
- package/docs/integrations/microsoft-clarity.md +57 -60
- package/docs/integrations/microsoft-uet.md +58 -61
- package/docs/integrations/mixpanel-analytics.md +73 -75
- package/docs/integrations/one-dollar-stats.md +53 -59
- package/docs/integrations/openai-pixel.md +58 -60
- package/docs/integrations/overview.md +59 -42
- package/docs/integrations/pinterest-tag.md +56 -60
- package/docs/integrations/pirsch.md +54 -60
- package/docs/integrations/plausible-analytics.md +55 -60
- package/docs/integrations/posthog.md +56 -60
- package/docs/integrations/promptwatch.md +57 -63
- package/docs/integrations/reddit-pixel.md +57 -60
- package/docs/integrations/rudderstack.md +65 -67
- package/docs/integrations/rybbit-analytics.md +70 -75
- package/docs/integrations/segment.md +56 -60
- package/docs/integrations/sentry.md +65 -60
- package/docs/integrations/snapchat-pixel.md +54 -60
- package/docs/integrations/tiktok-pixel.md +59 -63
- package/docs/integrations/umami-analytics.md +54 -60
- package/docs/integrations/vercel-analytics.md +53 -59
- package/docs/integrations/vercel-speed-insights.md +317 -0
- package/docs/integrations/x-pixel.md +57 -63
- package/docs/integrations/youtube.md +25 -13
- package/package.json +18 -8
- package/docs/upgrade-v3.md +0 -429
|
@@ -1,24 +1,42 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Google Tag Manager
|
|
3
|
-
description: Load a Google Tag Manager container
|
|
4
|
-
signals, configure consent checks inside the container,
|
|
5
|
-
DevTools.
|
|
3
|
+
description: Load a Google Tag Manager container before or after consent with
|
|
4
|
+
c15t Consent Mode v2 signals, configure consent checks inside the container,
|
|
5
|
+
and verify both in DevTools.
|
|
6
|
+
seoTitle: Google Tag Manager Consent Mode v2 with c15t
|
|
7
|
+
seoDescription: Set Google Consent Mode v2 defaults before your GTM container
|
|
8
|
+
starts. Load it on every page or only after consent with the c15t
|
|
9
|
+
googleTagManager helper.
|
|
6
10
|
icon: google-tag-manager
|
|
7
11
|
group: integrations
|
|
8
12
|
---
|
|
9
13
|
|
|
14
|
+
The c15t `googleTagManager` helper loads your Google Tag Manager container,
|
|
15
|
+
`gtm.js`. With the default `loadMode: 'always'`, the container loads on every
|
|
16
|
+
page, before the visitor chooses, under the `necessary` category. With
|
|
17
|
+
`loadMode: 'after-consent'`, c15t sends nothing to Google until the helper's
|
|
18
|
+
`category` has consent, which defaults to `measurement` or `marketing`. In both
|
|
19
|
+
modes, the helper sends the Google Consent Mode v2 default with
|
|
20
|
+
`gtag('consent', 'default', ...)` before the container starts. Once the
|
|
21
|
+
container runs, each later consent change sends an `update`, and then a
|
|
22
|
+
`consent-update` event.
|
|
23
|
+
`measurement` controls `analytics_storage`, and `marketing` controls
|
|
24
|
+
`ad_storage`, `ad_user_data`, and `ad_personalization`. Tags in the container
|
|
25
|
+
that are not from Google ignore these signals, unless you add consent checks in
|
|
26
|
+
GTM.
|
|
27
|
+
|
|
10
28
|
## Configure Google Tag Manager
|
|
11
29
|
|
|
12
30
|
Copy the container ID, which starts with `GTM-`, from your GTM workspace.
|
|
13
31
|
Remove the existing GTM snippet, its `<noscript>` iframe and any framework
|
|
14
32
|
plugin that loads the same container.
|
|
15
33
|
|
|
16
|
-
| Package manager | Command
|
|
17
|
-
| :-------------- |
|
|
18
|
-
| npm | `npm install @c15t/integrations
|
|
19
|
-
| pnpm | `pnpm add @c15t/integrations
|
|
20
|
-
| yarn | `yarn add @c15t/integrations
|
|
21
|
-
| bun | `bun add @c15t/integrations
|
|
34
|
+
| Package manager | Command |
|
|
35
|
+
| :-------------- | :------------------------------- |
|
|
36
|
+
| npm | `npm install @c15t/integrations` |
|
|
37
|
+
| pnpm | `pnpm add @c15t/integrations` |
|
|
38
|
+
| yarn | `yarn add @c15t/integrations` |
|
|
39
|
+
| bun | `bun add @c15t/integrations` |
|
|
22
40
|
|
|
23
41
|
```ts title="src/consent-scripts.ts"
|
|
24
42
|
import { googleTagManager } from '@c15t/integrations/google-tag-manager';
|
|
@@ -33,51 +51,41 @@ endpoint, policy, styles and consent UI. Remove the vendor's original script,
|
|
|
33
51
|
SDK initializer or tag-manager entry, so the vendor loads only through c15t.
|
|
34
52
|
|
|
35
53
|
The vendor pages put the helper in `src/consent-scripts.ts`. If your framework
|
|
36
|
-
quickstart already
|
|
37
|
-
Next.js guide, add the helper to that array instead of creating a
|
|
54
|
+
quickstart already has a `scripts` array, such as the one in `c15t.config.ts`
|
|
55
|
+
in the Next.js guide, add the helper to that array instead of creating a
|
|
56
|
+
second file.
|
|
38
57
|
The `scripts` export is a configuration, not an initializer. Add it to the c15t provider you already have, at the registration
|
|
39
58
|
point for your framework below. These are edits to that provider, not a second
|
|
40
59
|
provider.
|
|
41
60
|
|
|
42
61
|
**Next.js**
|
|
43
62
|
|
|
44
|
-
|
|
63
|
+
Add the configuration to `scripts` in `c15t.config.ts`, next to
|
|
64
|
+
`next.config.ts`:
|
|
45
65
|
|
|
46
|
-
```ts
|
|
47
|
-
import {
|
|
48
|
-
import { scripts } from './consent-scripts';
|
|
49
|
-
```
|
|
66
|
+
```ts title="c15t.config.ts"
|
|
67
|
+
import { defineConsentConfig } from 'c15t/next';
|
|
68
|
+
import { scripts } from './src/consent-scripts';
|
|
50
69
|
|
|
51
|
-
|
|
52
|
-
router guide. Its manifest, init and save URLs stay in effect. Add
|
|
53
|
-
`scripts` as a top-level prop on the existing root:
|
|
54
|
-
|
|
55
|
-
```tsx
|
|
56
|
-
<ConsentRoot state={state} config={consentConfig} scripts={scripts}>
|
|
57
|
-
{children}
|
|
58
|
-
</ConsentRoot>
|
|
70
|
+
export default defineConsentConfig({ scripts });
|
|
59
71
|
```
|
|
60
72
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
Keep the rest of your config, such as `mode` and `routePrefix`, in the
|
|
74
|
+
same call. `ConsentRoot` reads the config in the browser, so the layout
|
|
75
|
+
keeps passing only `state`. App Router, Pages Router and static export all
|
|
76
|
+
read the same file. See
|
|
64
77
|
[Next.js scripts and embeds](https://c15t.com/docs/frameworks/next/scripts).
|
|
65
78
|
|
|
66
79
|
**TanStack Start**
|
|
67
80
|
|
|
68
81
|
Import the configuration into your root route and pass it to the existing
|
|
69
|
-
`ConsentRoot` as a top-level prop. Keep the loader
|
|
70
|
-
|
|
82
|
+
`ConsentRoot` as a top-level prop. Keep the loader from the
|
|
83
|
+
[TanStack Start quickstart](https://c15t.com/docs/frameworks/tanstack-start/quickstart):
|
|
71
84
|
|
|
72
85
|
```tsx title="src/routes/__root.tsx"
|
|
73
86
|
import { scripts } from '../consent-scripts';
|
|
74
87
|
|
|
75
|
-
<ConsentRoot
|
|
76
|
-
state={consent}
|
|
77
|
-
backendURL={backendURL}
|
|
78
|
-
initRoute={false}
|
|
79
|
-
scripts={scripts}
|
|
80
|
-
>
|
|
88
|
+
<ConsentRoot state={consent} scripts={scripts}>
|
|
81
89
|
```
|
|
82
90
|
|
|
83
91
|
Import vendor helpers in the root route module, not in a server function.
|
|
@@ -96,8 +104,8 @@ import { scripts } from './consent-scripts';
|
|
|
96
104
|
<ConsentProvider options={{ mode, scripts }}>
|
|
97
105
|
```
|
|
98
106
|
|
|
99
|
-
`mode` is the `
|
|
100
|
-
|
|
107
|
+
`mode` is the `manifest()` value from the
|
|
108
|
+
[React quickstart](../frameworks/react/quickstart.md). Keep the banner,
|
|
101
109
|
dialog and preferences link inside the provider. See
|
|
102
110
|
[React scripts and embeds](../frameworks/react/scripts.md).
|
|
103
111
|
|
|
@@ -126,15 +134,16 @@ callbacks. Write the vendor IDs into `consent-scripts.ts`. See
|
|
|
126
134
|
Pass the scripts to the existing `c15tVue` plugin call in `src/main.ts`:
|
|
127
135
|
|
|
128
136
|
```ts title="src/main.ts"
|
|
137
|
+
import { c15tVue, manifest } from 'c15t/vue/vue-plugin';
|
|
129
138
|
import { scripts } from './consent-scripts';
|
|
130
139
|
|
|
131
140
|
app.use(c15tVue, {
|
|
132
|
-
|
|
141
|
+
mode: manifest(),
|
|
133
142
|
scripts,
|
|
134
143
|
});
|
|
135
144
|
```
|
|
136
145
|
|
|
137
|
-
Keep your existing
|
|
146
|
+
Keep your existing `mode` and other options. The plugin starts one
|
|
138
147
|
script loader when the app mounts, after it has applied the visitor's stored
|
|
139
148
|
choice. Do not also call `createScriptLoader` from a component. See
|
|
140
149
|
[Vue scripts and embeds](https://c15t.com/docs/frameworks/vue/scripts).
|
|
@@ -142,12 +151,11 @@ choice. Do not also call `createScriptLoader` from a component. See
|
|
|
142
151
|
**Astro**
|
|
143
152
|
|
|
144
153
|
Add the scripts to the client entrypoint from the
|
|
145
|
-
[Astro quickstart](https://c15t.com/docs/frameworks/astro/quickstart),
|
|
146
|
-
integration
|
|
147
|
-
|
|
148
|
-
already exports scripts, combine the two arrays.
|
|
154
|
+
[Astro quickstart](https://c15t.com/docs/frameworks/astro/quickstart), `src/c15t.client.ts`,
|
|
155
|
+
which the integration finds on its own. Keep `astro.config.mjs` as it is.
|
|
156
|
+
If the module already exports scripts, combine the two arrays.
|
|
149
157
|
|
|
150
|
-
```ts title="src/
|
|
158
|
+
```ts title="src/c15t.client.ts"
|
|
151
159
|
import type { C15tClientOptionsExtension } from 'c15t/astro';
|
|
152
160
|
import { scripts } from './consent-scripts';
|
|
153
161
|
|
|
@@ -167,15 +175,13 @@ pass them as a top-level prop:
|
|
|
167
175
|
|
|
168
176
|
```svelte title="src/App.svelte"
|
|
169
177
|
<script lang="ts">
|
|
170
|
-
import {
|
|
178
|
+
import { ConsentProvider, manifest } from '@c15t/svelte';
|
|
171
179
|
import { scripts } from './consent-scripts';
|
|
172
|
-
|
|
173
|
-
const mode = hosted({ url: 'https://your-project.inth.app' });
|
|
174
180
|
</script>
|
|
175
181
|
|
|
176
|
-
<
|
|
182
|
+
<ConsentProvider mode={manifest()} {scripts}>
|
|
177
183
|
<!-- Keep your application, consent UI and preferences link here. -->
|
|
178
|
-
</
|
|
184
|
+
</ConsentProvider>
|
|
179
185
|
```
|
|
180
186
|
|
|
181
187
|
Retain the styles and consent UI from the [Svelte quickstart](https://c15t.com/docs/frameworks/svelte/quickstart).
|
|
@@ -183,22 +189,21 @@ The provider owns the loader and disposes it on unmount.
|
|
|
183
189
|
|
|
184
190
|
**SvelteKit**
|
|
185
191
|
|
|
186
|
-
Add the scripts to the existing root layout
|
|
187
|
-
and
|
|
192
|
+
Add the scripts to the existing `ConsentRoot` in the root layout. Keep the
|
|
193
|
+
handle and the layout load from the [SvelteKit quickstart](https://c15t.com/docs/frameworks/sveltekit/quickstart).
|
|
188
194
|
|
|
189
195
|
```svelte title="src/routes/+layout.svelte"
|
|
190
196
|
<script lang="ts">
|
|
191
|
-
import {
|
|
197
|
+
import { ConsentRoot } from '@c15t/svelte';
|
|
192
198
|
import { scripts } from '../consent-scripts';
|
|
193
199
|
|
|
194
200
|
let { children, data } = $props();
|
|
195
|
-
const mode = hosted({ url: 'https://your-project.inth.app' });
|
|
196
201
|
</script>
|
|
197
202
|
|
|
198
|
-
<
|
|
203
|
+
<ConsentRoot state={data.consent} {scripts}>
|
|
199
204
|
{@render children()}
|
|
200
205
|
<!-- Keep your consent UI and preferences link here. -->
|
|
201
|
-
</
|
|
206
|
+
</ConsentRoot>
|
|
202
207
|
```
|
|
203
208
|
|
|
204
209
|
Import vendor helpers in the layout component, not in `+layout.server.ts`:
|
|
@@ -225,20 +230,19 @@ to a pasted snippet. See [HTML scripts](https://c15t.com/docs/frameworks/html/sc
|
|
|
225
230
|
|
|
226
231
|
**JavaScript**
|
|
227
232
|
|
|
228
|
-
Pass the scripts to `init()` from `@c15t/browser`, next to your
|
|
229
|
-
URL:
|
|
233
|
+
Pass the scripts to `init()` from `@c15t/browser`, next to your mode:
|
|
230
234
|
|
|
231
235
|
```ts
|
|
232
|
-
import { init } from '@c15t/browser';
|
|
236
|
+
import { init, manifest } from '@c15t/browser';
|
|
233
237
|
import { scripts } from './consent-scripts';
|
|
234
238
|
|
|
235
239
|
const consent = init({
|
|
236
|
-
|
|
240
|
+
mode: manifest(),
|
|
237
241
|
scripts,
|
|
238
242
|
});
|
|
239
243
|
```
|
|
240
244
|
|
|
241
|
-
Keep the
|
|
245
|
+
Keep the mode from your quickstart. With
|
|
242
246
|
`createConsentRuntime` from `c15t/runtime`, pass `scripts` to it instead.
|
|
243
247
|
A kernel you create yourself needs a loader from
|
|
244
248
|
`c15t/modules/script-loader`. Attach one loader per kernel. See
|
|
@@ -246,25 +250,79 @@ A kernel you create yourself needs a loader from
|
|
|
246
250
|
|
|
247
251
|
## Options
|
|
248
252
|
|
|
249
|
-
| Option | Default
|
|
250
|
-
| ----------------- |
|
|
251
|
-
| `id` | Required
|
|
252
|
-
| `dataLayer` | `'dataLayer'`
|
|
253
|
-
| `updateEventName` | `'consent-update'`
|
|
254
|
-
| `consentMapping` | The table below
|
|
253
|
+
| Option | Default | Behavior |
|
|
254
|
+
| ----------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
255
|
+
| `id` | Required | Container ID, for example `GTM-1234XXX`. The helper trims it. Empty or whitespace-only values log an error and the script does not load. |
|
|
256
|
+
| `dataLayer` | `'dataLayer'` | Queue name. A custom name adds `&l=<name>` to the container URL and renames the helper's queue function to `<name>Gtag`. |
|
|
257
|
+
| `updateEventName` | `'consent-update'` | `dataLayer` event pushed after every consent update. Use it as a GTM trigger. |
|
|
258
|
+
| `consentMapping` | The table below | Replaces the category-to-Google mapping. |
|
|
259
|
+
| `loadMode` | `'always'` | When `gtm.js` loads. See [choose when the container loads](#choose-when-the-container-loads). |
|
|
260
|
+
| `category` | `'necessary'`, or `{ or: ['measurement', 'marketing'] }` with `loadMode: 'after-consent'` | Consent condition for the container. With `'after-consent'`, `gtm.js` waits for it. With `'always'`, it sets the script's permission, which callbacks receive, but does not delay loading. |
|
|
261
|
+
|
|
262
|
+
## Choose when the container loads
|
|
255
263
|
|
|
256
|
-
|
|
264
|
+
| `loadMode` | Until the category is allowed | After the category is allowed |
|
|
265
|
+
| ----------------- | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
266
|
+
| `'always'` | Loads `gtm.js` and sends `consent` `default` with the current permissions before the `gtm.js` start event. | Sends `consent` `update`, then the `consent-update` event. |
|
|
267
|
+
| `'after-consent'` | Sends nothing to Google. The helper creates no `dataLayer` or `gtag` function. | Loads `gtm.js` once. `consent` `default` carries the current permissions and comes before the `gtm.js` start event. Later changes send `update` and `consent-update`. |
|
|
257
268
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
269
|
+
Use `'after-consent'` when your policy forbids any request to Google before
|
|
270
|
+
the visitor opts in:
|
|
271
|
+
|
|
272
|
+
```ts title="src/consent-scripts.ts (partial)"
|
|
273
|
+
googleTagManager({ id: 'GTM-XXXXXXX', loadMode: 'after-consent' }),
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
`'after-consent'` waits for the category to be allowed, not for a recorded
|
|
277
|
+
choice. Under an `opt-in` policy, that happens when the visitor allows it.
|
|
278
|
+
Under an `opt-out` or `none` policy, optional categories are allowed before a
|
|
279
|
+
choice, so `gtm.js` loads on the first page unless a saved refusal or a
|
|
280
|
+
privacy signal restricts the category; see
|
|
281
|
+
[policies](../concepts/policies.md).
|
|
282
|
+
|
|
283
|
+
`necessary` is always allowed, so a gated container needs another category.
|
|
284
|
+
This mode defaults to `{ or: ['measurement', 'marketing'] }`. A container
|
|
285
|
+
usually holds Analytics tags and advertising tags, and this default loads it
|
|
286
|
+
once the visitor allows either purpose. Google tags inside still follow the
|
|
287
|
+
Consent Mode types, so an Ads tag stays restricted for a visitor who allowed
|
|
288
|
+
only measurement. If the container holds only Analytics tags, pass
|
|
289
|
+
`category: 'measurement'`.
|
|
290
|
+
|
|
291
|
+
This mode gives up part of Consent Mode. With `'always'`, Google tags send
|
|
292
|
+
cookieless pings while a type is denied, and Google uses them to model
|
|
293
|
+
conversions and behavior for visitors who refused or have not chosen. With
|
|
294
|
+
`'after-consent'`, visitors whose category is denied send nothing, so Google
|
|
295
|
+
has no data to model them from. Reports cover only visitors who allowed the
|
|
296
|
+
category.
|
|
297
|
+
|
|
298
|
+
The container starts with the visitor's current choice in its `default`
|
|
299
|
+
command. On the page where the visitor accepts, it loads after the choice, so
|
|
300
|
+
no `consent-update` event fires for that choice. Triggers that wait only for
|
|
301
|
+
`consent-update` first fire on a later change. Use the tag's consent settings,
|
|
302
|
+
described below, for tags that should fire on the first page.
|
|
303
|
+
|
|
304
|
+
When the visitor withdraws the category, c15t reloads the page and the new
|
|
305
|
+
page does not load `gtm.js`. With `reloadOnConsentRevoked: false`, the running
|
|
306
|
+
container stays on the page and gets an `update` that denies the withdrawn
|
|
307
|
+
types. A later grant reuses it instead of starting a second container.
|
|
308
|
+
|
|
309
|
+
## Google loads before a choice by default
|
|
310
|
+
|
|
311
|
+
With the default `loadMode: 'always'`, the `googleTagManager` and `gtag`
|
|
312
|
+
helpers set `alwaysLoad: true`. Before the visitor chooses, the helper creates
|
|
313
|
+
the `dataLayer` queue, sends `gtag('consent', 'default', ...)` with the current
|
|
314
|
+
permissions and loads Google's script. After each permission change it sends
|
|
262
315
|
`gtag('consent', 'update', ...)`. Google's tags then adjust what they store and
|
|
263
316
|
send; see Google's
|
|
264
317
|
[Consent Mode overview](https://developers.google.com/tag-platform/security/concepts/consent-mode).
|
|
265
318
|
|
|
266
|
-
So the browser
|
|
267
|
-
Google request until the visitor allows it,
|
|
319
|
+
So the browser contacts Google before consent. If your policy requires no
|
|
320
|
+
Google request until the visitor allows it, set `loadMode: 'after-consent'`.
|
|
321
|
+
The helper then creates nothing and requests nothing until its category is
|
|
322
|
+
allowed. When it loads, it sends the `default` command first, with the
|
|
323
|
+
permissions at that moment, and `update` commands after later changes. Under
|
|
324
|
+
an `opt-out` or `none` policy, optional categories are allowed before a
|
|
325
|
+
choice, so the helper loads on the first page.
|
|
268
326
|
|
|
269
327
|
## How categories map to Google consent types
|
|
270
328
|
|
|
@@ -286,10 +344,12 @@ visitor has chosen anything. That is a permission, not a recorded choice.
|
|
|
286
344
|
|
|
287
345
|
## Configure consent inside the container
|
|
288
346
|
|
|
289
|
-
`googleTagManager` uses the `necessary`
|
|
290
|
-
container loads on every page.
|
|
291
|
-
|
|
292
|
-
|
|
347
|
+
With the default `loadMode: 'always'`, `googleTagManager` uses the `necessary`
|
|
348
|
+
category and `alwaysLoad`, so the container loads on every page. With
|
|
349
|
+
`'after-consent'`, it loads once its category is allowed. In both modes,
|
|
350
|
+
consent signals reach Google tags that support Consent Mode. Other tags in the
|
|
351
|
+
container, such as a third-party pixel added as Custom HTML, ignore those
|
|
352
|
+
signals and fire on their triggers.
|
|
293
353
|
|
|
294
354
|
For each non-Google tag, add a consent requirement in the tag's consent
|
|
295
355
|
settings, or fire it from a Custom Event trigger on `consent-update`. If a
|
|
@@ -305,6 +365,8 @@ choices per arm. To see the arm in GTM as well, forward the `onSurfaceShown` and
|
|
|
305
365
|
|
|
306
366
|
## Verify Google Tag Manager
|
|
307
367
|
|
|
368
|
+
With the default `loadMode: 'always'`:
|
|
369
|
+
|
|
308
370
|
1. In a private window with an opt-in policy, load the page. `gtm.js` loads.
|
|
309
371
|
In Google Tag Assistant, the first consent command is `default` with
|
|
310
372
|
`analytics_storage` and `ad_storage` set to `denied`.
|
|
@@ -317,5 +379,19 @@ choices per arm. To see the arm in GTM as well, forward the `onSurfaceShown` and
|
|
|
317
379
|
4. Turn measurement off again and save. c15t reloads the page, and the new
|
|
318
380
|
page starts with `analytics_storage` denied.
|
|
319
381
|
|
|
382
|
+
With `loadMode: 'after-consent'`:
|
|
383
|
+
|
|
384
|
+
1. In a private window with an opt-in policy, filter DevTools Network by
|
|
385
|
+
`google` and load the page. No request appears, and `window.dataLayer` is
|
|
386
|
+
`undefined` in the Console.
|
|
387
|
+
2. Allow measurement. `gtm.js` loads once. In Tag Assistant, the first command
|
|
388
|
+
is `consent` `default` with `analytics_storage` set to `granted`, before
|
|
389
|
+
the container starts.
|
|
390
|
+
3. Allow marketing as well. Tag Assistant shows an `update` command that
|
|
391
|
+
grants the ad types, followed by a `consent-update` event. No second
|
|
392
|
+
`gtm.js` request appears.
|
|
393
|
+
4. Turn both off again and save. c15t reloads the page, and the new page makes
|
|
394
|
+
no request to Google.
|
|
395
|
+
|
|
320
396
|
See the [consent verification guide](../guides/verify-consent.md) for
|
|
321
397
|
navigation and hosting checks.
|