@c15t/scripts 3.0.0-alpha.2 → 3.0.0-alpha.4
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 +129 -63
- package/README.md +8 -29
- package/SKILL.md +33 -0
- package/dist/adobe-analytics.js +2 -0
- package/dist/ahrefs-analytics.js +2 -0
- package/dist/amplitude.js +2 -0
- package/dist/clearbit.js +2 -0
- package/dist/cloudflare-web-analytics.js +2 -0
- package/dist/cloudflare-zaraz.js +2 -0
- package/dist/crisp.js +2 -0
- package/dist/databuddy.js +2 -0
- package/dist/e2e-test-utils.js +2 -139
- package/dist/engine/compile.js +2 -89
- package/dist/engine/runtime.js +2 -448
- package/dist/events.js +2 -218
- package/dist/fathom-analytics.js +2 -0
- package/dist/front-chat.js +2 -0
- package/dist/google-tag-manager.js +2 -0
- package/dist/google-tag.js +2 -0
- package/dist/heap.js +2 -0
- package/dist/hightouch.js +2 -0
- package/dist/hotjar.js +2 -0
- package/dist/intercom.js +2 -0
- package/dist/klaviyo.js +2 -0
- package/dist/linkedin-insights.js +2 -0
- package/dist/logrocket.js +2 -0
- package/dist/matomo-analytics.js +2 -0
- package/dist/meta-pixel.js +2 -0
- package/dist/microsoft-clarity.js +2 -0
- package/dist/microsoft-uet.js +2 -0
- package/dist/mixpanel-analytics.js +2 -0
- package/dist/one-dollar-stats.js +2 -0
- package/dist/openai-pixel.js +2 -0
- package/dist/pinterest-tag.js +2 -0
- package/dist/pirsch.js +2 -0
- package/dist/plausible-analytics.js +2 -0
- package/dist/posthog.js +2 -0
- package/dist/promptwatch.js +2 -0
- package/dist/reddit-pixel.js +2 -0
- package/dist/registry.js +2 -422
- package/dist/resolve.js +2 -33
- package/dist/rudderstack.js +2 -0
- package/dist/rybbit-analytics.js +2 -0
- package/dist/segment.js +2 -0
- package/dist/snapchat-pixel.js +2 -0
- package/dist/tiktok-pixel.js +2 -0
- package/dist/types.js +2 -16
- package/dist/umami-analytics.js +2 -0
- package/dist/vendors/_shared/attributes.js +2 -14
- package/dist/vendors/_shared/google-consent.js +2 -27
- package/dist/vendors/_shared/install-builders.js +2 -21
- package/dist/vendors/_shared/required-id.js +2 -0
- package/dist/vendors/_shared/script-url.js +2 -28
- package/dist/vendors/ads-and-pixels/linkedin-insights.js +2 -48
- package/dist/vendors/ads-and-pixels/meta-pixel.js +2 -153
- package/dist/vendors/ads-and-pixels/microsoft-uet.js +2 -110
- package/dist/vendors/ads-and-pixels/openai-pixel.js +2 -88
- package/dist/vendors/ads-and-pixels/pinterest-tag.js +2 -123
- package/dist/vendors/ads-and-pixels/reddit-pixel.js +2 -107
- package/dist/vendors/ads-and-pixels/snapchat-pixel.js +2 -87
- package/dist/vendors/ads-and-pixels/tiktok-pixel.js +2 -89
- package/dist/vendors/ads-and-pixels/x-pixel.js +2 -48
- package/dist/vendors/analytics/adobe-analytics.js +2 -49
- package/dist/vendors/analytics/ahrefs-analytics.js +2 -27
- package/dist/vendors/analytics/amplitude.js +2 -134
- package/dist/vendors/analytics/clearbit.js +2 -28
- package/dist/vendors/analytics/cloudflare-web-analytics.js +2 -32
- package/dist/vendors/analytics/databuddy.js +2 -103
- package/dist/vendors/analytics/fathom-analytics.js +2 -35
- package/dist/vendors/analytics/google-tag.js +2 -78
- package/dist/vendors/analytics/heap.js +2 -134
- package/dist/vendors/analytics/hightouch.js +2 -109
- package/dist/vendors/analytics/hotjar.js +2 -44
- package/dist/vendors/analytics/logrocket.js +2 -58
- package/dist/vendors/analytics/matomo-analytics.js +2 -191
- package/dist/vendors/analytics/microsoft-clarity.js +2 -100
- package/dist/vendors/analytics/mixpanel-analytics.js +2 -93
- package/dist/vendors/analytics/one-dollar-stats.js +2 -30
- package/dist/vendors/analytics/pirsch.js +2 -67
- package/dist/vendors/analytics/plausible-analytics.js +2 -81
- package/dist/vendors/analytics/posthog.js +2 -200
- package/dist/vendors/analytics/promptwatch.js +2 -29
- package/dist/vendors/analytics/rudderstack.js +2 -183
- package/dist/vendors/analytics/rybbit-analytics.js +2 -63
- package/dist/vendors/analytics/segment.js +2 -65
- package/dist/vendors/analytics/umami-analytics.js +2 -39
- package/dist/vendors/analytics/vercel-analytics.js +2 -53
- package/dist/vendors/email-and-sms/klaviyo.js +2 -0
- package/dist/vendors/functional/crisp.js +2 -100
- package/dist/vendors/functional/front-chat.js +2 -64
- package/dist/vendors/functional/intercom.js +2 -45
- package/dist/vendors/tag-managers/cloudflare-zaraz.js +2 -98
- package/dist/vendors/tag-managers/google-tag-manager.js +2 -73
- package/dist/vercel-analytics.js +2 -0
- package/dist/x-pixel.js +2 -0
- package/dist-types/adobe-analytics.d.ts +2 -0
- package/dist-types/ahrefs-analytics.d.ts +2 -0
- package/dist-types/amplitude.d.ts +2 -0
- package/dist-types/clearbit.d.ts +2 -0
- package/dist-types/cloudflare-web-analytics.d.ts +2 -0
- package/dist-types/cloudflare-zaraz.d.ts +2 -0
- package/dist-types/crisp.d.ts +2 -0
- package/dist-types/databuddy.d.ts +2 -0
- package/dist-types/e2e-test-utils.d.ts +2 -0
- package/dist-types/engine/compile.d.ts +2 -3
- package/dist-types/engine/runtime.d.ts +2 -3
- package/dist-types/events.d.ts +2 -46
- package/dist-types/fathom-analytics.d.ts +2 -0
- package/dist-types/front-chat.d.ts +2 -0
- package/dist-types/google-tag-manager.d.ts +2 -0
- package/dist-types/google-tag.d.ts +2 -0
- package/dist-types/heap.d.ts +2 -0
- package/dist-types/hightouch.d.ts +2 -0
- package/dist-types/hotjar.d.ts +2 -0
- package/dist-types/intercom.d.ts +2 -0
- package/dist-types/klaviyo.d.ts +2 -0
- package/dist-types/linkedin-insights.d.ts +2 -0
- package/dist-types/logrocket.d.ts +2 -0
- package/dist-types/matomo-analytics.d.ts +2 -0
- package/dist-types/meta-pixel.d.ts +2 -0
- package/dist-types/microsoft-clarity.d.ts +2 -0
- package/dist-types/microsoft-uet.d.ts +2 -0
- package/dist-types/mixpanel-analytics.d.ts +2 -0
- package/dist-types/one-dollar-stats.d.ts +2 -0
- package/dist-types/openai-pixel.d.ts +2 -0
- package/dist-types/pinterest-tag.d.ts +2 -0
- package/dist-types/pirsch.d.ts +2 -0
- package/dist-types/plausible-analytics.d.ts +2 -0
- package/dist-types/posthog.d.ts +2 -0
- package/dist-types/promptwatch.d.ts +2 -0
- package/dist-types/reddit-pixel.d.ts +2 -0
- package/dist-types/registry.d.ts +2 -485
- package/dist-types/resolve.d.ts +2 -9
- package/dist-types/rudderstack.d.ts +2 -0
- package/dist-types/rybbit-analytics.d.ts +2 -0
- package/dist-types/segment.d.ts +2 -0
- package/dist-types/snapchat-pixel.d.ts +2 -0
- package/dist-types/tiktok-pixel.d.ts +2 -0
- package/dist-types/types.d.ts +2 -314
- package/dist-types/umami-analytics.d.ts +2 -0
- package/dist-types/vendors/_shared/attributes.d.ts +2 -35
- package/dist-types/vendors/_shared/google-consent.d.ts +2 -47
- package/dist-types/vendors/_shared/install-builders.d.ts +2 -30
- package/dist-types/vendors/_shared/required-id.d.ts +2 -0
- package/dist-types/vendors/_shared/script-url.d.ts +2 -75
- package/dist-types/vendors/ads-and-pixels/linkedin-insights.d.ts +2 -92
- package/dist-types/vendors/ads-and-pixels/meta-pixel.d.ts +2 -289
- package/dist-types/vendors/ads-and-pixels/microsoft-uet.d.ts +2 -105
- package/dist-types/vendors/ads-and-pixels/openai-pixel.d.ts +2 -211
- package/dist-types/vendors/ads-and-pixels/pinterest-tag.d.ts +2 -295
- package/dist-types/vendors/ads-and-pixels/reddit-pixel.d.ts +2 -210
- package/dist-types/vendors/ads-and-pixels/snapchat-pixel.d.ts +2 -171
- package/dist-types/vendors/ads-and-pixels/tiktok-pixel.d.ts +2 -106
- package/dist-types/vendors/ads-and-pixels/x-pixel.d.ts +2 -183
- package/dist-types/vendors/analytics/adobe-analytics.d.ts +2 -75
- package/dist-types/vendors/analytics/ahrefs-analytics.d.ts +2 -62
- package/dist-types/vendors/analytics/amplitude.d.ts +2 -234
- package/dist-types/vendors/analytics/clearbit.d.ts +2 -60
- package/dist-types/vendors/analytics/cloudflare-web-analytics.d.ts +2 -67
- package/dist-types/vendors/analytics/databuddy.d.ts +2 -147
- package/dist-types/vendors/analytics/fathom-analytics.d.ts +2 -90
- package/dist-types/vendors/analytics/google-tag.d.ts +2 -95
- package/dist-types/vendors/analytics/heap.d.ts +2 -316
- package/dist-types/vendors/analytics/hightouch.d.ts +2 -285
- package/dist-types/vendors/analytics/hotjar.d.ts +2 -73
- package/dist-types/vendors/analytics/logrocket.d.ts +2 -101
- package/dist-types/vendors/analytics/matomo-analytics.d.ts +2 -41
- package/dist-types/vendors/analytics/microsoft-clarity.d.ts +2 -97
- package/dist-types/vendors/analytics/mixpanel-analytics.d.ts +2 -113
- package/dist-types/vendors/analytics/one-dollar-stats.d.ts +2 -39
- package/dist-types/vendors/analytics/pirsch.d.ts +2 -96
- package/dist-types/vendors/analytics/plausible-analytics.d.ts +2 -122
- package/dist-types/vendors/analytics/posthog.d.ts +2 -175
- package/dist-types/vendors/analytics/promptwatch.d.ts +2 -36
- package/dist-types/vendors/analytics/rudderstack.d.ts +2 -330
- package/dist-types/vendors/analytics/rybbit-analytics.d.ts +2 -82
- package/dist-types/vendors/analytics/segment.d.ts +2 -164
- package/dist-types/vendors/analytics/umami-analytics.d.ts +2 -93
- package/dist-types/vendors/analytics/vercel-analytics.d.ts +2 -66
- package/dist-types/vendors/email-and-sms/klaviyo.d.ts +2 -0
- package/dist-types/vendors/functional/crisp.d.ts +2 -78
- package/dist-types/vendors/functional/front-chat.d.ts +2 -62
- package/dist-types/vendors/functional/intercom.d.ts +2 -135
- package/dist-types/vendors/tag-managers/cloudflare-zaraz.d.ts +2 -39
- package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +2 -96
- package/dist-types/vercel-analytics.d.ts +2 -0
- package/dist-types/x-pixel.d.ts +2 -0
- package/docs/README.md +129 -63
- package/docs/assets/v3/bottom-bar.png +0 -0
- package/docs/assets/v3/brand-card.png +0 -0
- package/docs/assets/v3/brand-preferences.png +0 -0
- package/docs/assets/v3/choice-wall.png +0 -0
- package/docs/assets/v3/headless-bar-html.png +0 -0
- package/docs/assets/v3/headless-bar-mobile.png +0 -0
- package/docs/assets/v3/headless-bar.png +0 -0
- package/docs/assets/v3/slim-bar.png +0 -0
- package/docs/concepts/choose-your-setup.md +87 -0
- package/docs/concepts/consent-categories.md +84 -0
- package/docs/{guides → concepts}/consent-state.md +89 -105
- package/docs/{guides → concepts}/data-fetching.md +31 -27
- package/docs/concepts/how-consent-works.md +123 -0
- package/docs/concepts/policies.md +71 -0
- package/docs/customization/class-names.md +202 -0
- package/docs/customization/dark-mode.md +157 -0
- package/docs/customization/motion.md +119 -0
- package/docs/customization/overview.md +67 -34
- package/docs/customization/recipes.md +839 -49
- package/docs/customization/slots.md +216 -35
- package/docs/customization/stylesheets.md +147 -0
- package/docs/customization/tailwind.md +842 -0
- package/docs/customization/tokens.md +163 -96
- package/docs/customization/translations.md +60 -3
- package/docs/frameworks/astro/embeds.md +160 -0
- package/docs/frameworks/astro/network-blocker.md +86 -0
- package/docs/frameworks/astro/scripts.md +155 -0
- package/docs/frameworks/html/embeds.md +142 -0
- package/docs/frameworks/html/network-blocker.md +105 -0
- package/docs/frameworks/html/scripts.md +164 -0
- package/docs/frameworks/javascript/scripts.md +137 -0
- package/docs/frameworks/next/embeds.md +90 -0
- package/docs/frameworks/next/network-blocker.md +153 -0
- package/docs/frameworks/next/scripts.md +196 -0
- package/docs/frameworks/nuxt/embeds.md +81 -0
- package/docs/frameworks/nuxt/network-blocker.md +97 -0
- package/docs/frameworks/nuxt/scripts.md +89 -0
- package/docs/frameworks/react/embeds.md +89 -0
- package/docs/frameworks/react/network-blocker.md +140 -0
- package/docs/frameworks/react/scripts.md +115 -0
- package/docs/frameworks/svelte/embeds.md +96 -0
- package/docs/frameworks/svelte/network-blocker.md +141 -0
- package/docs/frameworks/svelte/scripts.md +144 -0
- package/docs/frameworks/sveltekit/embeds.md +103 -0
- package/docs/frameworks/sveltekit/network-blocker.md +159 -0
- package/docs/frameworks/sveltekit/scripts.md +172 -0
- package/docs/frameworks/tanstack-start/embeds.md +96 -0
- package/docs/frameworks/tanstack-start/network-blocker.md +145 -0
- package/docs/frameworks/tanstack-start/scripts.md +103 -0
- package/docs/frameworks/vue/embeds.md +84 -0
- package/docs/frameworks/vue/network-blocker.md +99 -0
- package/docs/frameworks/vue/scripts.md +93 -0
- package/docs/guides/banner-experiments.md +654 -0
- package/docs/guides/troubleshooting.md +120 -47
- package/docs/guides/verify-consent.md +81 -49
- package/docs/integrations/adobe-analytics.md +167 -159
- package/docs/integrations/ahrefs-analytics.md +152 -154
- package/docs/integrations/amplitude.md +162 -156
- package/docs/integrations/building-integrations.md +136 -37
- package/docs/integrations/clearbit.md +154 -154
- package/docs/integrations/cloudflare-web-analytics.md +156 -156
- package/docs/integrations/cloudflare-zaraz.md +209 -261
- package/docs/integrations/crisp.md +164 -158
- package/docs/integrations/databuddy.md +157 -173
- package/docs/integrations/fathom-analytics.md +158 -156
- package/docs/integrations/front-chat.md +167 -167
- package/docs/integrations/google-maps.md +118 -83
- package/docs/integrations/google-tag-manager.md +178 -163
- package/docs/integrations/google-tag.md +163 -160
- package/docs/integrations/heap.md +163 -155
- package/docs/integrations/hightouch.md +161 -157
- package/docs/integrations/hotjar.md +159 -155
- package/docs/integrations/intercom.md +183 -153
- package/docs/integrations/klaviyo.md +486 -0
- package/docs/integrations/linkedin-insights.md +174 -150
- package/docs/integrations/logrocket.md +160 -156
- package/docs/integrations/matomo-analytics.md +188 -178
- package/docs/integrations/meta-pixel.md +188 -150
- package/docs/integrations/microsoft-clarity.md +163 -155
- package/docs/integrations/microsoft-uet.md +148 -154
- package/docs/integrations/mixpanel-analytics.md +155 -160
- package/docs/integrations/one-dollar-stats.md +166 -165
- package/docs/integrations/openai-pixel.md +204 -301
- package/docs/integrations/overview.md +137 -80
- package/docs/integrations/pinterest-tag.md +191 -183
- package/docs/integrations/pirsch.md +169 -159
- package/docs/integrations/plausible-analytics.md +172 -158
- package/docs/integrations/posthog.md +313 -240
- package/docs/integrations/promptwatch.md +154 -154
- package/docs/integrations/reddit-pixel.md +185 -157
- package/docs/integrations/rudderstack.md +201 -186
- package/docs/integrations/rybbit-analytics.md +171 -160
- package/docs/integrations/segment.md +182 -154
- package/docs/integrations/snapchat-pixel.md +186 -156
- package/docs/integrations/tiktok-pixel.md +171 -150
- package/docs/integrations/umami-analytics.md +163 -158
- package/docs/integrations/vercel-analytics.md +166 -157
- package/docs/integrations/x-pixel.md +176 -150
- package/docs/integrations/youtube.md +121 -86
- package/docs/upgrade-v3.md +496 -467
- package/package.json +10 -257
- package/dist-types/__tests__/helpers.d.ts +0 -141
- package/docs/assets/v3/brand-bar.png +0 -0
- package/docs/assets/v3/mobile-card.png +0 -0
- package/docs/assets/v3/preferences.png +0 -0
- package/docs/frameworks/javascript/script-loader.md +0 -100
- package/docs/frameworks/next/script-loader.md +0 -216
- package/docs/frameworks/react/script-loader.md +0 -69
- package/docs/guides/deployment-modes.md +0 -75
- package/docs/guides/shared-consent-controls.md +0 -158
- package/docs/integrations/clear-on-revocation.md +0 -167
- package/docs/integrations/granular-consent.md +0 -210
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Scripts
|
|
3
|
+
description: Load vendor scripts and gated inline scripts on an Astro site only
|
|
4
|
+
after the visitor allows their consent category, and stop them when consent is
|
|
5
|
+
withdrawn.
|
|
6
|
+
group: frameworks
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Register vendor scripts
|
|
10
|
+
|
|
11
|
+
The `ConsentBanner` component does not stop a `<script>` tag you already have.
|
|
12
|
+
Give c15t each vendor script to load instead, and remove the vendor's own
|
|
13
|
+
snippet so it loads once.
|
|
14
|
+
|
|
15
|
+
Vendor helpers from `@c15t/integrations` contain callbacks, and the integration
|
|
16
|
+
options in `astro.config.mjs` must survive JSON serialization. So register
|
|
17
|
+
helpers in the module that the integration's `clientEntrypoint` option names.
|
|
18
|
+
This list loads PostHog on measurement and X Pixel on marketing:
|
|
19
|
+
|
|
20
|
+
```ts title="src/example-scripts.ts"
|
|
21
|
+
import { posthog } from '@c15t/integrations/posthog';
|
|
22
|
+
import { xPixel } from '@c15t/integrations/x-pixel';
|
|
23
|
+
|
|
24
|
+
export const scripts = [
|
|
25
|
+
posthog({
|
|
26
|
+
id: 'phc_your_project_key',
|
|
27
|
+
initOptions: { cookieless_mode: 'never' },
|
|
28
|
+
loadMode: 'after-consent',
|
|
29
|
+
region: 'eu',
|
|
30
|
+
}),
|
|
31
|
+
xPixel({ pixelId: 'your-pixel-id' }),
|
|
32
|
+
];
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```ts title="src/consent-client.ts"
|
|
36
|
+
import type { C15tClientOptionsExtension } from 'c15t/astro';
|
|
37
|
+
|
|
38
|
+
import { scripts } from './example-scripts';
|
|
39
|
+
|
|
40
|
+
export default { scripts } satisfies C15tClientOptionsExtension;
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The integration imports that module into the page's boot script, so every page
|
|
44
|
+
shares one script loader. Each helper's guide under
|
|
45
|
+
[integrations](../../integrations/overview.md) lists its options and the requests
|
|
46
|
+
to expect.
|
|
47
|
+
|
|
48
|
+
## Add a script without a helper
|
|
49
|
+
|
|
50
|
+
A script with no callbacks can go straight into the integration options. Give
|
|
51
|
+
it an `id`, a `category`, and either a `src` or inline `textContent`:
|
|
52
|
+
|
|
53
|
+
```js title="astro.config.mjs (partial)"
|
|
54
|
+
c15t({
|
|
55
|
+
mode: hosted({ url: 'https://your-project.inth.app' }),
|
|
56
|
+
scripts: [
|
|
57
|
+
{
|
|
58
|
+
id: 'example-analytics',
|
|
59
|
+
category: 'measurement',
|
|
60
|
+
src: 'https://analytics.example.com/script.js',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Scripts from `astro.config.mjs` and from the client entrypoint both load.
|
|
67
|
+
|
|
68
|
+
## What a site without scripts skips
|
|
69
|
+
|
|
70
|
+
The script loader is part of the page's boot script only when the site
|
|
71
|
+
configures `scripts` in `astro.config.mjs` or sets a `clientEntrypoint`, which
|
|
72
|
+
may add some. A site with neither never downloads it, about 4 KB gzip less on
|
|
73
|
+
every page. The [network blocker](./network-blocker.md) works the same way: it
|
|
74
|
+
ships in the boot script when the integration options have `networkBlocker`
|
|
75
|
+
rules, and loads as its own chunk when only the client entrypoint sets them.
|
|
76
|
+
|
|
77
|
+
## Gate an inline script
|
|
78
|
+
|
|
79
|
+
For a script that has to stay in the page's markup, make it inert and label it
|
|
80
|
+
with a category. c15t runs it once the category is allowed:
|
|
81
|
+
|
|
82
|
+
```astro title="src/pages/index.astro (partial)"
|
|
83
|
+
<script data-c15t-category="measurement" is:inline type="text/plain">
|
|
84
|
+
document.getElementById('inline-script-status').textContent =
|
|
85
|
+
'Measurement script ran';
|
|
86
|
+
</script>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Three attributes matter:
|
|
90
|
+
|
|
91
|
+
* `type="text/plain"` stops the browser from running the script.
|
|
92
|
+
* `data-c15t-category` names one category. An unknown name logs a warning and
|
|
93
|
+
the script never runs.
|
|
94
|
+
* `is:inline` makes Astro ship the tag as written. Without it, Astro bundles the
|
|
95
|
+
script and runs it regardless of consent.
|
|
96
|
+
|
|
97
|
+
Add `data-c15t-vendor` with a vendor slug to also hold the script while the
|
|
98
|
+
visitor has switched that vendor off. See
|
|
99
|
+
[vendor consent](https://c15t.com/docs/frameworks/astro/vendor-consent).
|
|
100
|
+
|
|
101
|
+
Under a nonce-based Content Security Policy, where your middleware sets
|
|
102
|
+
`Astro.locals.c15t.nonce`, also add `nonce={Astro.locals.c15t?.nonce}` to the
|
|
103
|
+
tag. c15t then activates only gated tags that carry the page's nonce, and
|
|
104
|
+
skips the rest with a console warning. See
|
|
105
|
+
[put the nonce on your gated scripts](https://c15t.com/docs/frameworks/astro/content-security-policy#put-the-nonce-on-your-gated-scripts).
|
|
106
|
+
|
|
107
|
+
c15t checks gated scripts when the page loads, after each consent change and
|
|
108
|
+
after each `ClientRouter` navigation, so a script on a page you navigate to
|
|
109
|
+
runs as soon as it is allowed. A script with `src` works the same way. For
|
|
110
|
+
markup you insert later from your own code, call
|
|
111
|
+
`activateGatedScripts(getConsent(), container)` from `c15t/astro/client`.
|
|
112
|
+
Under a nonce policy, give the inserted tags the nonce and pass it as a third
|
|
113
|
+
argument.
|
|
114
|
+
|
|
115
|
+
A script that has run cannot be undone. When the visitor withdraws consent,
|
|
116
|
+
c15t reloads the page, and the reloaded page leaves the script inert.
|
|
117
|
+
|
|
118
|
+
## Gate embeds and requests
|
|
119
|
+
|
|
120
|
+
An iframe loads as soon as it is in the page, so gate embeds separately. See
|
|
121
|
+
[Embeds](./embeds.md) for a component that renders an iframe
|
|
122
|
+
only while its category is allowed, and for the iframe blocker.
|
|
123
|
+
|
|
124
|
+
To stop `fetch` and `XMLHttpRequest` calls to tracking hosts until consent,
|
|
125
|
+
add rules to `networkBlocker`. See
|
|
126
|
+
[Network blocker](./network-blocker.md).
|
|
127
|
+
|
|
128
|
+
## Clear data when consent is withdrawn
|
|
129
|
+
|
|
130
|
+
Set `clearOnRevocation` in the integration options to remove a vendor's
|
|
131
|
+
cookies and storage keys when its category is withdrawn. See
|
|
132
|
+
[clear on revocation](https://c15t.com/docs/frameworks/astro/clear-on-revocation) for the shape.
|
|
133
|
+
|
|
134
|
+
## Withdraw consent without reloading
|
|
135
|
+
|
|
136
|
+
By default c15t reloads the page after a save turns off a category that was
|
|
137
|
+
allowed, because it cannot stop code that has already run. Set
|
|
138
|
+
`reloadOnConsentRevoked: false` in the integration options only if every script
|
|
139
|
+
on the page stops itself when its category is withdrawn. Stop your own code
|
|
140
|
+
from the `onPermissionsChanged` callback. See
|
|
141
|
+
[Callbacks](https://c15t.com/docs/frameworks/astro/callbacks).
|
|
142
|
+
|
|
143
|
+
## Check script loading
|
|
144
|
+
|
|
145
|
+
Build the site and open it in a private window with DevTools Network open:
|
|
146
|
+
|
|
147
|
+
1. Before you choose, filter for each vendor's domain. There are no requests,
|
|
148
|
+
and a gated inline script has not run.
|
|
149
|
+
2. Allow one category from **Cookie preferences**. Only that category's vendors
|
|
150
|
+
load, and inline scripts gated on it run.
|
|
151
|
+
3. Reload. The allowed vendors load again, and the others stay absent.
|
|
152
|
+
4. Withdraw the category and save. The page reloads and the vendor does not
|
|
153
|
+
load.
|
|
154
|
+
|
|
155
|
+
See [Verify consent](../../guides/verify-consent.md) for the full checklist.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Embeds
|
|
3
|
+
description: Hold YouTube videos, maps and other iframes on a plain HTML page
|
|
4
|
+
until their consent category is allowed with data-src and data-category, show
|
|
5
|
+
a placeholder, and configure the c15t iframe blocker.
|
|
6
|
+
group: frameworks
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Gate an iframe
|
|
10
|
+
|
|
11
|
+
Move the iframe's URL from `src` to `data-src` and name its category in
|
|
12
|
+
`data-category`. The c15t script tag gives the iframe its `src` once the
|
|
13
|
+
category is allowed:
|
|
14
|
+
|
|
15
|
+
```html title="index.html"
|
|
16
|
+
<iframe
|
|
17
|
+
data-src="https://www.youtube-nocookie.com/embed/czTksCF6X8Y?playsinline=1"
|
|
18
|
+
data-category="measurement"
|
|
19
|
+
data-vendor="youtube"
|
|
20
|
+
title="YouTube video"
|
|
21
|
+
allow="encrypted-media; picture-in-picture"
|
|
22
|
+
allowfullscreen
|
|
23
|
+
></iframe>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
An iframe with no `src` loads nothing, so the vendor gets no request and sets
|
|
27
|
+
no cookie until the visitor allows the category. Give every embed a `title`
|
|
28
|
+
that says what it shows.
|
|
29
|
+
|
|
30
|
+
## Attributes
|
|
31
|
+
|
|
32
|
+
| Attribute | What it does |
|
|
33
|
+
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
34
|
+
| `data-src` | The embed's URL. c15t moves it to `src` when the gate opens. Only `http:` and `https:` URLs load. A relative URL resolves against the page. |
|
|
35
|
+
| `data-category` | One category name. An unknown name logs a warning and keeps the iframe blocked. |
|
|
36
|
+
| `data-vendor` | Optional vendor ID for vendor-level consent. The iframe also stays blocked while the visitor has turned that vendor off. See [vendor consent](https://c15t.com/docs/frameworks/html/vendor-consent). |
|
|
37
|
+
| `data-c15t-paused` | Set by c15t when it took away a `src` the iframe already had. Do not set it yourself. |
|
|
38
|
+
|
|
39
|
+
Iframes without `data-category` or `data-vendor` are left alone.
|
|
40
|
+
|
|
41
|
+
## Show a placeholder
|
|
42
|
+
|
|
43
|
+
c15t does not draw anything in place of a blocked iframe. Put your own message
|
|
44
|
+
next to it and hide it once the iframe has a `src`. The quickstart page uses
|
|
45
|
+
this markup:
|
|
46
|
+
|
|
47
|
+
```html
|
|
48
|
+
<div class="embed">
|
|
49
|
+
<iframe data-src="…" data-category="measurement" title="YouTube video"></iframe>
|
|
50
|
+
<div class="placeholder">
|
|
51
|
+
<p>Allow measurement to load this YouTube video.</p>
|
|
52
|
+
<a href="#c15t-preferences">Choose video permissions</a>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```css
|
|
58
|
+
.embed iframe:not([src]) { display: none; }
|
|
59
|
+
.embed iframe[src] + .placeholder { display: none; }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The `#c15t-preferences` link opens the preference dialog, where the visitor
|
|
63
|
+
can allow the category. See [preferences link](https://c15t.com/docs/frameworks/html/components/preferences-link).
|
|
64
|
+
|
|
65
|
+
## What happens on withdrawal
|
|
66
|
+
|
|
67
|
+
When a visitor turns the category off, c15t removes the iframe's `src` and puts
|
|
68
|
+
the URL back in `data-src`, which unloads the embed. The page also reloads by
|
|
69
|
+
default, as it does for scripts.
|
|
70
|
+
|
|
71
|
+
An iframe written with a normal `src` and a `data-category` starts loading
|
|
72
|
+
before c15t runs, then c15t removes the `src`. The vendor already got its
|
|
73
|
+
request, so always use `data-src`.
|
|
74
|
+
|
|
75
|
+
## Iframes added later
|
|
76
|
+
|
|
77
|
+
c15t watches the whole document. An iframe that a page builder, a CMS widget
|
|
78
|
+
or your own script adds later is gated the moment it appears, and so is an
|
|
79
|
+
iframe whose `data-category` changes. This keeps working when a client router
|
|
80
|
+
such as Turbo replaces `<body>` on navigation, and when the c15t tag runs in
|
|
81
|
+
`<head>` before `<body>` exists.
|
|
82
|
+
|
|
83
|
+
## Configure the iframe blocker
|
|
84
|
+
|
|
85
|
+
The iframe blocker is on by default in every `@c15t/browser` build. Set
|
|
86
|
+
`iframeBlocker` in a queued `config` call to change it:
|
|
87
|
+
|
|
88
|
+
```html
|
|
89
|
+
<script>
|
|
90
|
+
window.c15t = window.c15t || [];
|
|
91
|
+
c15t.push(['config', { iframeBlocker: false }]);
|
|
92
|
+
</script>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
| Value | Effect |
|
|
96
|
+
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
97
|
+
| omitted or `{}` | Gate every iframe with `data-category` or `data-vendor`, including ones added later. |
|
|
98
|
+
| `{ disableAutomaticBlocking: true }` | Do not scan or watch the page. c15t sets or removes a `src` only when you call `c15t.processIframes()`. See [check iframes yourself](#check-iframes-yourself). |
|
|
99
|
+
| `false` | Turn the blocker off. `data-src` iframes never load. |
|
|
100
|
+
|
|
101
|
+
The categories on gated iframes are added to the preference dialog, as they
|
|
102
|
+
are for gated scripts.
|
|
103
|
+
|
|
104
|
+
## Check iframes yourself
|
|
105
|
+
|
|
106
|
+
With `iframeBlocker: { disableAutomaticBlocking: true }`, c15t leaves iframes
|
|
107
|
+
alone until your page calls `c15t.processIframes()`. Each call pauses gated
|
|
108
|
+
iframes, those with `data-category` or `data-vendor`, that consent does not
|
|
109
|
+
allow, and restores the ones it does. Call it after the policy resolves, after
|
|
110
|
+
you add iframes, and after consent changes:
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<script>
|
|
114
|
+
window.c15t = window.c15t || [];
|
|
115
|
+
c15t.push(['config', { iframeBlocker: { disableAutomaticBlocking: true } }]);
|
|
116
|
+
c15t.push(['processIframes']);
|
|
117
|
+
c15t.push(['on', 'consent', () => c15t.processIframes()]);
|
|
118
|
+
</script>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
A queued `processIframes` runs once the policy has resolved, so
|
|
122
|
+
`c15t.push(['processIframes'])` is safe before and after the tag loads. With
|
|
123
|
+
automatic blocking on, c15t does this by itself and you do not need to call
|
|
124
|
+
it.
|
|
125
|
+
|
|
126
|
+
## Vendor embeds
|
|
127
|
+
|
|
128
|
+
The [integration guides](../../integrations/overview.md) have an HTML tab for
|
|
129
|
+
YouTube, Google Maps and other embeds, with the category each one needs. The
|
|
130
|
+
`youtube-nocookie.com` player still contacts Google when it loads, so gate it
|
|
131
|
+
like any other embed.
|
|
132
|
+
|
|
133
|
+
## Check it works
|
|
134
|
+
|
|
135
|
+
Open the page in a private window with the Network tab open.
|
|
136
|
+
|
|
137
|
+
1. Before you choose, the iframe has no `src` in the Elements panel and there
|
|
138
|
+
is no request to the embed's host. The placeholder shows.
|
|
139
|
+
2. Allow the category. The iframe gets its `src`, the embed loads and the
|
|
140
|
+
placeholder hides.
|
|
141
|
+
3. Open preferences and turn the category off. The page reloads and the embed
|
|
142
|
+
stays unloaded.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Network blocker
|
|
3
|
+
description: Hold fetch and XMLHttpRequest calls from a plain HTML page until
|
|
4
|
+
their consent category is allowed, with network blocker rules queued on the
|
|
5
|
+
c15t script tag.
|
|
6
|
+
group: frameworks
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## When you need it
|
|
10
|
+
|
|
11
|
+
Some code sends data with `fetch` or `XMLHttpRequest` from a place you cannot
|
|
12
|
+
change into a `text/plain` tag, such as a theme's bundled script, a plugin, or your own
|
|
13
|
+
code that runs before consent. A network blocker rule holds those requests
|
|
14
|
+
until the rule's category is allowed. Script tags and iframes do not need it;
|
|
15
|
+
gate those with [gated scripts](https://c15t.com/docs/frameworks/html/components/gated-script)
|
|
16
|
+
and [embeds](./embeds.md).
|
|
17
|
+
|
|
18
|
+
## Add rules
|
|
19
|
+
|
|
20
|
+
Queue a `config` call with `networkBlocker` before the script tag:
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<script>
|
|
24
|
+
window.c15t = window.c15t || [];
|
|
25
|
+
c15t.push(['config', {
|
|
26
|
+
networkBlocker: {
|
|
27
|
+
rules: [
|
|
28
|
+
{ id: 'collector', domain: 'collect.example.com', category: 'measurement' },
|
|
29
|
+
{
|
|
30
|
+
id: 'events',
|
|
31
|
+
domain: 'example.com',
|
|
32
|
+
pathIncludes: '/api/track',
|
|
33
|
+
methods: ['POST'],
|
|
34
|
+
category: 'measurement',
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
onRequestBlocked: ({ method, url, rule }) => {
|
|
38
|
+
console.info('c15t blocked', method, url, rule?.id);
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
}]);
|
|
42
|
+
</script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The first rule blocks every request to `collect.example.com` and its
|
|
46
|
+
subdomains until measurement is allowed. The second blocks only POST requests
|
|
47
|
+
to paths on `example.com` that contain `/api/track`.
|
|
48
|
+
|
|
49
|
+
## Rule fields
|
|
50
|
+
|
|
51
|
+
| Field | Required | What it does |
|
|
52
|
+
| -------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
53
|
+
| `domain` | Yes | The host to match. Subdomains match too: `example.com` covers `www.example.com`. |
|
|
54
|
+
| `category` | Yes | The category that lets matching requests through. A condition such as `{ and: ['measurement', 'marketing'] }` works too. |
|
|
55
|
+
| `pathIncludes` | No | Match only URLs whose path contains this text. |
|
|
56
|
+
| `methods` | No | Match only these HTTP methods, such as `['POST']`. All methods when omitted. |
|
|
57
|
+
| `id` | No | A name for the rule, shown in logs and passed to `onRequestBlocked`. |
|
|
58
|
+
| `vendor` | No | Also block while the visitor has turned this vendor off. |
|
|
59
|
+
| `vendorId`, `iabPurposes`, `iabLegIntPurposes`, `iabSpecialFeatures` | No | IAB TCF conditions, checked only under an IAB policy. |
|
|
60
|
+
|
|
61
|
+
## Blocker options
|
|
62
|
+
|
|
63
|
+
| Option | Default | What it does |
|
|
64
|
+
| -------------------- | -------- | ------------------------------------------------------------- |
|
|
65
|
+
| `rules` | required | The rules above. |
|
|
66
|
+
| `enabled` | `true` | `false` keeps the configuration but blocks nothing. |
|
|
67
|
+
| `logBlockedRequests` | `true` | Log each blocked request with `console.warn`. |
|
|
68
|
+
| `onRequestBlocked` | none | Called with `{ method, url, rule }` for each blocked request. |
|
|
69
|
+
|
|
70
|
+
## What a blocked request sees
|
|
71
|
+
|
|
72
|
+
* A blocked `fetch` resolves with a `451` response. It does not reject, so
|
|
73
|
+
check `response.ok` in code that expects data.
|
|
74
|
+
* A blocked `XMLHttpRequest` fires an `error` event.
|
|
75
|
+
* A request sent before the policy resolves waits, then goes out or is
|
|
76
|
+
blocked once c15t knows the visitor's permissions. If the policy fails to
|
|
77
|
+
load, it is blocked.
|
|
78
|
+
* A request that does not match any rule goes out at once.
|
|
79
|
+
|
|
80
|
+
The rules' categories are added to the preference dialog, as they are for
|
|
81
|
+
gated scripts.
|
|
82
|
+
|
|
83
|
+
## What it cannot block
|
|
84
|
+
|
|
85
|
+
The network blocker patches `fetch` and `XMLHttpRequest` after the script tag
|
|
86
|
+
runs. It does not cover:
|
|
87
|
+
|
|
88
|
+
* `navigator.sendBeacon`, WebSockets and `EventSource`;
|
|
89
|
+
* requests from `<img>`, `<script>`, `<link>` and `<iframe>` elements;
|
|
90
|
+
* requests sent before the c15t tag ran. With `defer`, the tag runs after the
|
|
91
|
+
page has parsed, so inline scripts anywhere in the page run before it;
|
|
92
|
+
* requests from other frames and from service workers.
|
|
93
|
+
|
|
94
|
+
Use gated tags for scripts and iframes. When inline code sends requests while
|
|
95
|
+
the page parses, load the c15t tag without `defer` at the top of `<head>`, so
|
|
96
|
+
it runs first. The banner still waits for the document to parse before it
|
|
97
|
+
mounts.
|
|
98
|
+
|
|
99
|
+
## Check it works
|
|
100
|
+
|
|
101
|
+
1. Open the page in a private window with the console and Network tab open.
|
|
102
|
+
2. Trigger the request, for example by loading the page that sends it. The
|
|
103
|
+
console shows `[c15t] blocked POST https://example.com/api/track (rule: events)`
|
|
104
|
+
and the Network tab shows no request.
|
|
105
|
+
3. Allow measurement and trigger it again. The request goes out.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Scripts
|
|
3
|
+
description: Hold vendor scripts on a plain HTML page until the visitor allows
|
|
4
|
+
their category, load scripts with callbacks, handle withdrawal and clear
|
|
5
|
+
vendor cookies with the c15t script tag and no build step.
|
|
6
|
+
group: frameworks
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Choose how to gate a script
|
|
10
|
+
|
|
11
|
+
The c15t script tag has two ways to hold a vendor script until its category is
|
|
12
|
+
allowed:
|
|
13
|
+
|
|
14
|
+
| Form | Use it when |
|
|
15
|
+
| ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
|
|
16
|
+
| A `<script type="text/plain" data-c15t-category>` tag in your HTML | You paste a vendor snippet into a theme, a CMS field or a page builder. No JavaScript of your own. |
|
|
17
|
+
| A `scripts` entry in a queued `config` call | You need a callback after the vendor loads, on an error, or when consent changes. |
|
|
18
|
+
|
|
19
|
+
Both wait for the same permission and both add their category to the
|
|
20
|
+
preference dialog. Iframes use `data-src` instead; see
|
|
21
|
+
[embeds](./embeds.md). Requests your own code sends with
|
|
22
|
+
`fetch` use the [network blocker](./network-blocker.md).
|
|
23
|
+
|
|
24
|
+
## Gate a pasted snippet
|
|
25
|
+
|
|
26
|
+
Change the vendor's tag to `type="text/plain"` and add
|
|
27
|
+
`data-c15t-category`:
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<script type="text/plain" data-c15t-category="measurement">
|
|
31
|
+
// The vendor's snippet, unchanged
|
|
32
|
+
</script>
|
|
33
|
+
<script type="text/plain" data-c15t-category="marketing" src="https://vendor.example/tag.js"></script>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
On a page whose c15t tag has a nonce, add the same `nonce` to each gated tag,
|
|
37
|
+
or c15t skips it. See
|
|
38
|
+
[gated tags on a page with a nonce](https://c15t.com/docs/frameworks/html/components/gated-script#gated-tags-on-a-page-with-a-nonce).
|
|
39
|
+
The [quickstart](https://c15t.com/docs/frameworks/html/quickstart#gate-your-vendor-scripts)
|
|
40
|
+
shows this with PostHog and X Pixel. [Gated scripts](https://c15t.com/docs/frameworks/html/components/gated-script)
|
|
41
|
+
covers load order, copied attributes and tags added after load.
|
|
42
|
+
|
|
43
|
+
## What happens when a visitor withdraws permission
|
|
44
|
+
|
|
45
|
+
A script that has run cannot be stopped. When a visitor turns off a category
|
|
46
|
+
they had allowed, c15t saves the choice and reloads the page. The new page
|
|
47
|
+
starts with the vendor tag inert again. Allowing a category never reloads.
|
|
48
|
+
|
|
49
|
+
To handle withdrawal yourself, for example by calling a vendor's opt-out
|
|
50
|
+
function, set `reloadOnConsentRevoked: false` in `config`. Then c15t does not
|
|
51
|
+
reload and the vendor code that already ran keeps running until the next page
|
|
52
|
+
load. `callbacks.onBeforeConsentRevocationReload` runs right before the
|
|
53
|
+
reload, if you need to flush something first. See
|
|
54
|
+
[events and callbacks](https://c15t.com/docs/frameworks/html/callbacks).
|
|
55
|
+
|
|
56
|
+
## Load a script with callbacks
|
|
57
|
+
|
|
58
|
+
List the script under `scripts` in a queued `config` call before the tag:
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<script>
|
|
62
|
+
window.c15t = window.c15t || [];
|
|
63
|
+
c15t.push(['config', {
|
|
64
|
+
scripts: [
|
|
65
|
+
{
|
|
66
|
+
id: 'analytics',
|
|
67
|
+
src: 'https://analytics.example/sdk.js',
|
|
68
|
+
category: 'measurement',
|
|
69
|
+
onLoad: () => window.analytics.track('page_view'),
|
|
70
|
+
onConsentChange: ({ hasConsent }) => {
|
|
71
|
+
if (!hasConsent) window.analytics.optOut();
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
}]);
|
|
76
|
+
</script>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`analytics.track` and `analytics.optOut` stand for your vendor's own API.
|
|
80
|
+
c15t adds the script to `<head>` once measurement is allowed, and removes the
|
|
81
|
+
element again when the visitor withdraws it.
|
|
82
|
+
|
|
83
|
+
| Field | What it does |
|
|
84
|
+
| -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
85
|
+
| `id` | A unique, stable name for the script. Required. |
|
|
86
|
+
| `category` | The category it needs, such as `'measurement'`. Required. It also accepts a condition such as `{ and: ['measurement', 'marketing'] }`. |
|
|
87
|
+
| `src` or `textContent` | The URL to load, or inline code to run. One is required unless `callbackOnly` is set. |
|
|
88
|
+
| `callbackOnly` | Add no element. Only run the callbacks, for a vendor that is already on the page. |
|
|
89
|
+
| `alwaysLoad` | Load whatever the consent state. Use it only for tags that manage consent themselves. |
|
|
90
|
+
| `persistAfterConsentRevoked` | Keep the element on the page after withdrawal. |
|
|
91
|
+
| `target` | `'head'` (default) or `'body'`. |
|
|
92
|
+
| `async`, `defer`, `nonce`, `fetchPriority`, `attributes` | Attributes for the created `<script>` element. Without its own `nonce`, the script gets the c15t tag's nonce. |
|
|
93
|
+
| `anonymizeId` | Give the element a random `id` so blockers cannot match it by name. On by default. |
|
|
94
|
+
| `vendor` | A vendor ID for vendor-level consent. See [vendor consent](https://c15t.com/docs/frameworks/html/vendor-consent). |
|
|
95
|
+
| `onBeforeLoad`, `onLoad`, `onError` | Run before a load attempt, after the script loads, or when it fails. |
|
|
96
|
+
| `onConsentChange` | Run each time the script's consent changes. The argument has `hasConsent` and `consents`. |
|
|
97
|
+
| `onDispose` | Run when the script is removed from the configuration or c15t is disposed. |
|
|
98
|
+
|
|
99
|
+
Every callback receives the script's `id`, the created element's
|
|
100
|
+
`elementId`, `hasConsent`, the current `consents`, and the `element` when
|
|
101
|
+
there is one.
|
|
102
|
+
|
|
103
|
+
For a plain vendor snippet, the `text/plain` tag is simpler and works in any
|
|
104
|
+
CMS field that accepts HTML. The vendor helpers in `@c15t/integrations`, such as
|
|
105
|
+
the PostHog and Google tag helpers, are ES modules that need a bundler. On a
|
|
106
|
+
plain HTML page, paste the vendor's own snippet into a `text/plain` tag.
|
|
107
|
+
|
|
108
|
+
## Clear cookies when permission is withdrawn
|
|
109
|
+
|
|
110
|
+
Gating stops new requests but does not delete what a vendor already stored.
|
|
111
|
+
Add `clearOnRevocation` to the config to delete named cookies and storage keys
|
|
112
|
+
when their category is denied. See
|
|
113
|
+
[clear on revocation](https://c15t.com/docs/frameworks/html/clear-on-revocation).
|
|
114
|
+
|
|
115
|
+
## Google Consent Mode and tag managers
|
|
116
|
+
|
|
117
|
+
The script tag does not send Google Consent Mode signals. The Google tag and
|
|
118
|
+
Google Tag Manager helpers in `@c15t/integrations` do, but they need a bundler. On
|
|
119
|
+
a plain HTML page, gate Google's snippet like any other vendor. Google then
|
|
120
|
+
loads only after consent, so it sends nothing before a choice.
|
|
121
|
+
[Gated scripts](https://c15t.com/docs/frameworks/html/components/gated-script#load-order)
|
|
122
|
+
shows the GA4 snippet with its two tags in the right order.
|
|
123
|
+
|
|
124
|
+
If you need Consent Mode instead, load Google's snippet ungated and send the
|
|
125
|
+
signals yourself. Put this before Google's tags:
|
|
126
|
+
|
|
127
|
+
```html
|
|
128
|
+
<script>
|
|
129
|
+
window.dataLayer = window.dataLayer || [];
|
|
130
|
+
function gtag() { dataLayer.push(arguments); }
|
|
131
|
+
gtag('consent', 'default', {
|
|
132
|
+
analytics_storage: 'denied',
|
|
133
|
+
ad_storage: 'denied',
|
|
134
|
+
ad_user_data: 'denied',
|
|
135
|
+
ad_personalization: 'denied',
|
|
136
|
+
});
|
|
137
|
+
window.c15t = window.c15t || [];
|
|
138
|
+
c15t.push(['on', 'consent', (snapshot) => {
|
|
139
|
+
const allowed = snapshot.effectivePermissions;
|
|
140
|
+
const state = (granted) => (granted ? 'granted' : 'denied');
|
|
141
|
+
gtag('consent', 'update', {
|
|
142
|
+
analytics_storage: state(allowed.measurement),
|
|
143
|
+
ad_storage: state(allowed.marketing),
|
|
144
|
+
ad_user_data: state(allowed.marketing),
|
|
145
|
+
ad_personalization: state(allowed.marketing),
|
|
146
|
+
});
|
|
147
|
+
}]);
|
|
148
|
+
</script>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
With Consent Mode, Google receives requests before a choice, marked as denied.
|
|
152
|
+
Decide which behavior your policy needs before you pick one.
|
|
153
|
+
|
|
154
|
+
The vendor guides under [integrations](../../integrations/overview.md) have an
|
|
155
|
+
HTML tab with the no-build setup.
|
|
156
|
+
|
|
157
|
+
## Check it works
|
|
158
|
+
|
|
159
|
+
Open the page in a private window with the Network tab open.
|
|
160
|
+
|
|
161
|
+
1. Filter for each vendor's domain. Nothing loads before a choice.
|
|
162
|
+
2. Allow one category. Only that category's vendors load, and each `onLoad`
|
|
163
|
+
runs.
|
|
164
|
+
3. Turn the category off again. The page reloads and the vendor stays absent.
|