@c15t/scripts 2.2.0 → 3.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +74 -48
- package/README.md +3 -3
- package/dist/e2e-test-utils.js +60 -24
- package/dist/engine/compile.js +45 -45
- package/dist/engine/runtime.js +119 -119
- package/dist/registry.js +186 -176
- package/dist/resolve.js +12 -12
- package/dist/vendors/_shared/attributes.js +5 -5
- package/dist/vendors/_shared/google-consent.js +10 -10
- package/dist/vendors/_shared/install-builders.js +9 -9
- package/dist/vendors/_shared/script-url.js +12 -12
- package/dist/vendors/ads-and-pixels/linkedin-insights.js +16 -16
- package/dist/vendors/ads-and-pixels/meta-pixel.js +82 -82
- package/dist/vendors/ads-and-pixels/microsoft-uet.js +57 -57
- package/dist/vendors/ads-and-pixels/openai-pixel.js +88 -0
- package/dist/vendors/ads-and-pixels/reddit-pixel.js +39 -39
- package/dist/vendors/ads-and-pixels/snapchat-pixel.js +25 -25
- package/dist/vendors/ads-and-pixels/tiktok-pixel.js +31 -31
- package/dist/vendors/ads-and-pixels/x-pixel.js +17 -17
- package/dist/vendors/analytics/adobe-analytics.js +17 -17
- package/dist/vendors/analytics/ahrefs-analytics.js +8 -8
- package/dist/vendors/analytics/amplitude.js +39 -39
- package/dist/vendors/analytics/clearbit.js +11 -11
- package/dist/vendors/analytics/cloudflare-web-analytics.js +13 -13
- package/dist/vendors/analytics/databuddy.js +45 -45
- package/dist/vendors/analytics/fathom-analytics.js +15 -15
- package/dist/vendors/analytics/google-tag.js +23 -23
- package/dist/vendors/analytics/heap.js +37 -37
- package/dist/vendors/analytics/hightouch.js +30 -30
- package/dist/vendors/analytics/hotjar.js +14 -14
- package/dist/vendors/analytics/logrocket.js +24 -24
- package/dist/vendors/analytics/matomo-analytics.js +51 -51
- package/dist/vendors/analytics/microsoft-clarity.js +31 -31
- package/dist/vendors/analytics/mixpanel-analytics.js +31 -31
- package/dist/vendors/analytics/pirsch.js +27 -27
- package/dist/vendors/analytics/plausible-analytics.js +24 -24
- package/dist/vendors/analytics/posthog.js +84 -79
- package/dist/vendors/analytics/promptwatch.js +8 -8
- package/dist/vendors/analytics/rudderstack.js +50 -50
- package/dist/vendors/analytics/rybbit-analytics.js +30 -30
- package/dist/vendors/analytics/segment.js +16 -16
- package/dist/vendors/analytics/umami-analytics.js +16 -16
- package/dist/vendors/analytics/vercel-analytics.js +22 -22
- package/dist/vendors/functional/crisp.js +49 -51
- package/dist/vendors/functional/intercom.js +18 -18
- package/dist/vendors/tag-managers/google-tag-manager.js +20 -20
- package/dist-types/__tests__/helpers.d.ts +10 -10
- package/dist-types/engine/compile.d.ts +2 -2
- package/dist-types/engine/runtime.d.ts +3 -3
- package/dist-types/registry.d.ts +182 -173
- package/dist-types/resolve.d.ts +2 -2
- package/dist-types/types.d.ts +2 -2
- package/dist-types/vendors/_shared/attributes.d.ts +2 -2
- package/dist-types/vendors/_shared/google-consent.d.ts +2 -2
- package/dist-types/vendors/_shared/install-builders.d.ts +1 -1
- package/dist-types/vendors/_shared/script-url.d.ts +6 -6
- package/dist-types/vendors/ads-and-pixels/linkedin-insights.d.ts +14 -14
- package/dist-types/vendors/ads-and-pixels/meta-pixel.d.ts +27 -27
- package/dist-types/vendors/ads-and-pixels/microsoft-uet.d.ts +40 -40
- package/dist-types/vendors/ads-and-pixels/openai-pixel.d.ts +211 -0
- package/dist-types/vendors/ads-and-pixels/reddit-pixel.d.ts +28 -29
- package/dist-types/vendors/ads-and-pixels/snapchat-pixel.d.ts +23 -23
- package/dist-types/vendors/ads-and-pixels/tiktok-pixel.d.ts +22 -22
- package/dist-types/vendors/ads-and-pixels/x-pixel.d.ts +15 -15
- package/dist-types/vendors/analytics/adobe-analytics.d.ts +3 -3
- package/dist-types/vendors/analytics/ahrefs-analytics.d.ts +5 -5
- package/dist-types/vendors/analytics/amplitude.d.ts +24 -24
- package/dist-types/vendors/analytics/clearbit.d.ts +5 -5
- package/dist-types/vendors/analytics/cloudflare-web-analytics.d.ts +6 -6
- package/dist-types/vendors/analytics/databuddy.d.ts +34 -31
- package/dist-types/vendors/analytics/fathom-analytics.d.ts +8 -8
- package/dist-types/vendors/analytics/google-tag.d.ts +17 -17
- package/dist-types/vendors/analytics/heap.d.ts +17 -17
- package/dist-types/vendors/analytics/hightouch.d.ts +15 -15
- package/dist-types/vendors/analytics/hotjar.d.ts +9 -9
- package/dist-types/vendors/analytics/logrocket.d.ts +11 -11
- package/dist-types/vendors/analytics/matomo-analytics.d.ts +3 -3
- package/dist-types/vendors/analytics/microsoft-clarity.d.ts +12 -13
- package/dist-types/vendors/analytics/mixpanel-analytics.d.ts +20 -20
- package/dist-types/vendors/analytics/pirsch.d.ts +10 -10
- package/dist-types/vendors/analytics/plausible-analytics.d.ts +13 -13
- package/dist-types/vendors/analytics/posthog.d.ts +35 -32
- package/dist-types/vendors/analytics/promptwatch.d.ts +5 -5
- package/dist-types/vendors/analytics/rudderstack.d.ts +16 -16
- package/dist-types/vendors/analytics/rybbit-analytics.d.ts +15 -15
- package/dist-types/vendors/analytics/segment.d.ts +11 -11
- package/dist-types/vendors/analytics/umami-analytics.d.ts +9 -9
- package/dist-types/vendors/analytics/vercel-analytics.d.ts +13 -13
- package/dist-types/vendors/functional/crisp.d.ts +9 -9
- package/dist-types/vendors/functional/intercom.d.ts +12 -12
- package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +16 -16
- package/docs/README.md +74 -48
- package/docs/assets/v3/brand-bar.png +0 -0
- package/docs/assets/v3/brand-card.png +0 -0
- package/docs/assets/v3/choice-wall.png +0 -0
- package/docs/assets/v3/mobile-card.png +0 -0
- package/docs/assets/v3/preferences.png +0 -0
- package/docs/customization/overview.md +45 -0
- package/docs/customization/recipes.md +79 -0
- package/docs/customization/slots.md +55 -0
- package/docs/customization/tokens.md +76 -0
- package/docs/customization/translations.md +49 -0
- package/docs/frameworks/javascript/script-loader.md +30 -339
- package/docs/frameworks/next/script-loader.md +134 -467
- package/docs/frameworks/react/script-loader.md +35 -535
- package/docs/guides/consent-state.md +60 -0
- package/docs/guides/data-fetching.md +163 -0
- package/docs/guides/deployment-modes.md +63 -0
- package/docs/guides/troubleshooting.md +68 -0
- package/docs/guides/verify-consent.md +62 -0
- package/docs/integrations/adobe-analytics.md +239 -105
- package/docs/integrations/ahrefs-analytics.md +238 -104
- package/docs/integrations/amplitude.md +219 -157
- package/docs/integrations/building-integrations.md +32 -224
- package/docs/integrations/clearbit.md +247 -86
- package/docs/integrations/cloudflare-web-analytics.md +250 -84
- package/docs/integrations/crisp.md +251 -97
- package/docs/integrations/databuddy.md +259 -153
- package/docs/integrations/fathom-analytics.md +239 -96
- package/docs/integrations/google-maps.md +328 -207
- package/docs/integrations/google-tag-manager.md +248 -96
- package/docs/integrations/google-tag.md +261 -90
- package/docs/integrations/heap.md +222 -149
- package/docs/integrations/hightouch.md +225 -131
- package/docs/integrations/hotjar.md +239 -90
- package/docs/integrations/intercom.md +239 -98
- package/docs/integrations/linkedin-insights.md +243 -113
- package/docs/integrations/logrocket.md +241 -123
- package/docs/integrations/matomo-analytics.md +256 -111
- package/docs/integrations/meta-pixel.md +197 -324
- package/docs/integrations/microsoft-clarity.md +233 -114
- package/docs/integrations/microsoft-uet.md +245 -110
- package/docs/integrations/mixpanel-analytics.md +252 -87
- package/docs/integrations/openai-pixel.md +441 -0
- package/docs/integrations/overview.md +95 -133
- package/docs/integrations/pirsch.md +249 -96
- package/docs/integrations/plausible-analytics.md +241 -100
- package/docs/integrations/posthog.md +353 -214
- package/docs/integrations/promptwatch.md +251 -81
- package/docs/integrations/reddit-pixel.md +226 -173
- package/docs/integrations/rudderstack.md +244 -187
- package/docs/integrations/rybbit-analytics.md +244 -91
- package/docs/integrations/segment.md +238 -92
- package/docs/integrations/snapchat-pixel.md +240 -110
- package/docs/integrations/tiktok-pixel.md +249 -81
- package/docs/integrations/umami-analytics.md +242 -95
- package/docs/integrations/vercel-analytics.md +242 -90
- package/docs/integrations/x-pixel.md +238 -104
- package/docs/integrations/youtube.md +354 -142
- package/docs/upgrade-v3.md +334 -0
- package/package.json +85 -78
- package/readme.json +2 -2
- package/dist/e2e-test-utils.cjs +0 -166
- package/dist/engine/compile.cjs +0 -130
- package/dist/engine/runtime.cjs +0 -475
- package/dist/registry.cjs +0 -423
- package/dist/resolve.cjs +0 -71
- package/dist/types.cjs +0 -69
- package/dist/vendors/_shared/attributes.cjs +0 -55
- package/dist/vendors/_shared/google-consent.cjs +0 -69
- package/dist/vendors/_shared/install-builders.cjs +0 -59
- package/dist/vendors/_shared/script-url.cjs +0 -78
- package/dist/vendors/ads-and-pixels/linkedin-insights.cjs +0 -89
- package/dist/vendors/ads-and-pixels/meta-pixel.cjs +0 -206
- package/dist/vendors/ads-and-pixels/microsoft-uet.cjs +0 -151
- package/dist/vendors/ads-and-pixels/reddit-pixel.cjs +0 -151
- package/dist/vendors/ads-and-pixels/snapchat-pixel.cjs +0 -131
- package/dist/vendors/ads-and-pixels/tiktok-pixel.cjs +0 -130
- package/dist/vendors/ads-and-pixels/x-pixel.cjs +0 -92
- package/dist/vendors/analytics/adobe-analytics.cjs +0 -90
- package/dist/vendors/analytics/ahrefs-analytics.cjs +0 -68
- package/dist/vendors/analytics/amplitude.cjs +0 -193
- package/dist/vendors/analytics/clearbit.cjs +0 -69
- package/dist/vendors/analytics/cloudflare-web-analytics.cjs +0 -73
- package/dist/vendors/analytics/databuddy.cjs +0 -144
- package/dist/vendors/analytics/fathom-analytics.cjs +0 -76
- package/dist/vendors/analytics/google-tag.cjs +0 -107
- package/dist/vendors/analytics/heap.cjs +0 -181
- package/dist/vendors/analytics/hightouch.cjs +0 -153
- package/dist/vendors/analytics/hotjar.cjs +0 -85
- package/dist/vendors/analytics/logrocket.cjs +0 -99
- package/dist/vendors/analytics/matomo-analytics.cjs +0 -232
- package/dist/vendors/analytics/microsoft-clarity.cjs +0 -138
- package/dist/vendors/analytics/mixpanel-analytics.cjs +0 -134
- package/dist/vendors/analytics/pirsch.cjs +0 -108
- package/dist/vendors/analytics/plausible-analytics.cjs +0 -122
- package/dist/vendors/analytics/posthog.cjs +0 -236
- package/dist/vendors/analytics/promptwatch.cjs +0 -70
- package/dist/vendors/analytics/rudderstack.cjs +0 -227
- package/dist/vendors/analytics/rybbit-analytics.cjs +0 -104
- package/dist/vendors/analytics/segment.cjs +0 -97
- package/dist/vendors/analytics/umami-analytics.cjs +0 -80
- package/dist/vendors/analytics/vercel-analytics.cjs +0 -94
- package/dist/vendors/functional/crisp.cjs +0 -143
- package/dist/vendors/functional/intercom.cjs +0 -89
- package/dist/vendors/tag-managers/google-tag-manager.cjs +0 -100
- package/docs/shared/react/guides/script-loader.md +0 -311
|
@@ -1,239 +1,47 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
3
|
-
description:
|
|
4
|
-
|
|
5
|
-
scripts in c15t.
|
|
2
|
+
title: Custom integrations
|
|
3
|
+
description: Define loading, initialization and consent-change behavior for a
|
|
4
|
+
vendor without a helper.
|
|
6
5
|
group: integrations
|
|
7
6
|
---
|
|
8
|
-
If you cannot find a prebuilt integration in [`@c15t/scripts`](/docs/integrations), you have two good options:
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
2. Build a reusable manifest-backed integration helper.
|
|
8
|
+
## Start with a script configuration
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
### One-off app script
|
|
18
|
-
|
|
19
|
-
Use a raw `Script` when:
|
|
20
|
-
|
|
21
|
-
* the integration is only used in one app
|
|
22
|
-
* the vendor setup is small
|
|
23
|
-
* you do not need to publish or share the helper
|
|
24
|
-
|
|
25
|
-
```ts
|
|
26
|
-
import type { Script } from 'c15t';
|
|
27
|
-
|
|
28
|
-
export function acmeAnalytics(siteId: string): Script {
|
|
29
|
-
return {
|
|
30
|
-
id: 'acme-analytics',
|
|
31
|
-
src: `https://cdn.acme.com/analytics.js?site=${siteId}`,
|
|
32
|
-
category: 'measurement',
|
|
33
|
-
onBeforeLoad: () => {
|
|
34
|
-
window.acmeQueue = window.acmeQueue || [];
|
|
35
|
-
},
|
|
36
|
-
onConsentChange: ({ hasConsent }) => {
|
|
37
|
-
window.acme?.setConsent(hasConsent);
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### Reusable manifest-backed integration
|
|
44
|
-
|
|
45
|
-
Use a manifest-backed helper when:
|
|
46
|
-
|
|
47
|
-
* you want to contribute to `@c15t/scripts`
|
|
48
|
-
* you want the integration to be reusable across apps
|
|
49
|
-
* you need structured startup/setup phases
|
|
50
|
-
* you want compatibility with c15t's server-side support for script loading
|
|
51
|
-
|
|
52
|
-
Manifest integrations should be declarative, serializable, and built from structured steps rather than raw inline JavaScript strings.
|
|
53
|
-
|
|
54
|
-
## Manifest Contract
|
|
55
|
-
|
|
56
|
-
Every reusable manifest carries two contract fields:
|
|
57
|
-
|
|
58
|
-
* `kind`: identifies the payload as a c15t vendor manifest
|
|
59
|
-
* `schemaVersion`: identifies which manifest schema the runtime should compile
|
|
60
|
-
|
|
61
|
-
Use `vendorManifestContract` so helpers stay aligned with the runtime's current contract:
|
|
62
|
-
|
|
63
|
-
```ts
|
|
64
|
-
const acmeManifest = {
|
|
65
|
-
...vendorManifestContract,
|
|
66
|
-
vendor: 'acme-analytics',
|
|
67
|
-
// ...
|
|
68
|
-
} as const satisfies VendorManifest;
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
If manifests are sent from a server later, these fields are how the client can validate that it knows how to interpret the payload before executing anything.
|
|
72
|
-
|
|
73
|
-
## Manifest Mental Model
|
|
74
|
-
|
|
75
|
-
The manifest runtime executes a script in ordered phases:
|
|
76
|
-
|
|
77
|
-
* `bootstrap`: globals or stubs that must exist before anything else
|
|
78
|
-
* `install`: startup steps plus a single `loadScript`
|
|
79
|
-
* `afterLoad`: work that should run after the external script loads
|
|
80
|
-
* `onBeforeLoadGranted` / `onBeforeLoadDenied`: initial consent-specific setup
|
|
81
|
-
* `onLoadGranted` / `onLoadDenied`: post-load consent-specific setup
|
|
82
|
-
* `onConsentChange`: runs on every consent update
|
|
83
|
-
* `onConsentGranted` / `onConsentDenied`: branch-specific consent updates
|
|
84
|
-
|
|
85
|
-
For vendors with explicit consent APIs, you can also use:
|
|
86
|
-
|
|
87
|
-
* `consentMapping`
|
|
88
|
-
* `consentSignal`
|
|
89
|
-
* `consentSignalTarget`
|
|
90
|
-
|
|
91
|
-
That is how the Google integrations map c15t consent categories to Consent Mode v2 and inject `default` and `update` signals in the correct phase order.
|
|
92
|
-
|
|
93
|
-
`category` supports the same consent condition model as a plain `Script`, so manifests can represent simple or nested rules such as:
|
|
10
|
+
Check the installed `@c15t/scripts` exports first. For an unlisted SDK, define a
|
|
11
|
+
stable ID, category and source URL, then pass the configuration to the existing
|
|
12
|
+
provider or loader:
|
|
94
13
|
|
|
95
14
|
```ts
|
|
96
|
-
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Structured Steps
|
|
100
|
-
|
|
101
|
-
Prefer structured steps over raw script text. The current manifest DSL supports patterns like:
|
|
102
|
-
|
|
103
|
-
* `setGlobal`
|
|
104
|
-
* `setGlobalPath`
|
|
105
|
-
* `defineQueueFunction`
|
|
106
|
-
* `defineStubFunction`
|
|
107
|
-
* `pushToQueue`
|
|
108
|
-
* `callGlobal`
|
|
109
|
-
* `defineQueueMethods`
|
|
110
|
-
* `defineGlobalMethods`
|
|
111
|
-
* `constructGlobal`
|
|
112
|
-
* `loadScript`
|
|
113
|
-
|
|
114
|
-
These steps are easier to validate, test, debug, and eventually transport from the server.
|
|
115
|
-
|
|
116
|
-
## Example Manifest Integration
|
|
117
|
-
|
|
118
|
-
If you are building a reusable helper, the pattern looks like this:
|
|
15
|
+
import type { Script } from 'c15t/modules/script-loader';
|
|
119
16
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
import { resolveManifest } from '@c15t/scripts/resolve';
|
|
123
|
-
import {
|
|
124
|
-
vendorManifestContract,
|
|
125
|
-
type VendorManifest,
|
|
126
|
-
} from '@c15t/scripts/types';
|
|
127
|
-
|
|
128
|
-
const acmeManifest = {
|
|
129
|
-
...vendorManifestContract,
|
|
130
|
-
vendor: 'acme-analytics',
|
|
17
|
+
export const analyticsScript = {
|
|
18
|
+
id: 'example-analytics',
|
|
131
19
|
category: 'measurement',
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
type: 'defineQueueFunction',
|
|
141
|
-
name: 'acme',
|
|
142
|
-
queue: 'acmeQueue',
|
|
143
|
-
ifUndefined: true,
|
|
144
|
-
},
|
|
145
|
-
],
|
|
146
|
-
install: [
|
|
147
|
-
{
|
|
148
|
-
type: 'callGlobal',
|
|
149
|
-
global: 'acme',
|
|
150
|
-
args: ['init', '{{siteId}}'],
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
type: 'loadScript',
|
|
154
|
-
src: 'https://cdn.acme.com/analytics.js?site={{siteId}}',
|
|
155
|
-
async: true,
|
|
156
|
-
},
|
|
157
|
-
],
|
|
158
|
-
onConsentGranted: [
|
|
159
|
-
{
|
|
160
|
-
type: 'callGlobal',
|
|
161
|
-
global: 'acme',
|
|
162
|
-
args: ['consent', true],
|
|
163
|
-
},
|
|
164
|
-
],
|
|
165
|
-
onConsentDenied: [
|
|
166
|
-
{
|
|
167
|
-
type: 'callGlobal',
|
|
168
|
-
global: 'acme',
|
|
169
|
-
args: ['consent', false],
|
|
170
|
-
},
|
|
171
|
-
],
|
|
172
|
-
} as const satisfies VendorManifest;
|
|
173
|
-
|
|
174
|
-
export function acmeAnalytics(siteId: string): Script {
|
|
175
|
-
return resolveManifest(acmeManifest, { siteId });
|
|
176
|
-
}
|
|
20
|
+
src: 'https://analytics.example.com/sdk.js',
|
|
21
|
+
onLoad() {
|
|
22
|
+
// Initialize the vendor here using its documented API.
|
|
23
|
+
},
|
|
24
|
+
onError({ error }) {
|
|
25
|
+
console.error('Analytics SDK failed to load', error);
|
|
26
|
+
},
|
|
27
|
+
} satisfies Script;
|
|
177
28
|
```
|
|
178
29
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
* Keep helper logic thin. Put behavior in the manifest, not in post-resolution callback mutation.
|
|
184
|
-
* Keep manifests serializable. Avoid helper-only runtime branches where possible.
|
|
185
|
-
* Use explicit config inputs. Avoid generic override bags when a named option is clearer.
|
|
186
|
-
* Use `alwaysLoad` only when the vendor truly manages its own consent correctly.
|
|
187
|
-
* Use `persistAfterConsentRevoked` only when the vendor exposes a real consent toggle and does not need a full reload.
|
|
188
|
-
* Keep vendor-specific naming out of the core DSL when a generic step can express it.
|
|
189
|
-
|
|
190
|
-
## Testing Checklist
|
|
191
|
-
|
|
192
|
-
At minimum, test these flows:
|
|
193
|
-
|
|
194
|
-
1. Initial page load with consent denied.
|
|
195
|
-
2. Initial page load with consent granted.
|
|
196
|
-
3. Consent granted after the script was previously denied.
|
|
197
|
-
4. Consent revoked after the script was previously active.
|
|
198
|
-
5. Existing script element reuse if the script persists after revocation.
|
|
199
|
-
6. Error handling if the vendor global or loader is missing.
|
|
200
|
-
|
|
201
|
-
If you are contributing to `@c15t/scripts`, add focused engine/helper tests similar to the existing tests in `packages/scripts/src/engine.test.ts` and `packages/scripts/src/helpers.test.ts`.
|
|
202
|
-
|
|
203
|
-
## Debugging
|
|
204
|
-
|
|
205
|
-
Use `@c15t/dev-tools` while implementing and testing integrations.
|
|
206
|
-
|
|
207
|
-
The scripts panel now shows:
|
|
208
|
-
|
|
209
|
-
* whether a script is loaded, pending, or blocked
|
|
210
|
-
* grouped activity for `onBeforeLoad`, `onLoad`, and `onConsentChange`
|
|
211
|
-
* manifest phase activity such as `bootstrap`, `consent-default`, `setup`, and `afterLoad`
|
|
212
|
-
|
|
213
|
-
The events panel also records script lifecycle and manifest step events, which is useful when a vendor reads consent too early or a startup step runs in the wrong order.
|
|
214
|
-
|
|
215
|
-
## When to Stop and Use a Plain Script
|
|
216
|
-
|
|
217
|
-
Not every integration needs a reusable manifest helper.
|
|
218
|
-
|
|
219
|
-
If the vendor snippet is tiny, unique to one app, or mostly static, a plain `Script` object in your runtime options is usually the simpler choice. Reach for the manifest system when you need reuse, consistency, structured startup behavior, or a path to server-driven manifests.
|
|
220
|
-
|
|
221
|
-
## Reference Types
|
|
222
|
-
|
|
223
|
-
### Script
|
|
224
|
-
|
|
225
|
-
|Property|Value|
|
|
226
|
-
|:--|:--|
|
|
227
|
-
|Type Name|\`Script\`|
|
|
228
|
-
|Source Path|\`./packages/core/src/libs/script-loader/types.ts\`|
|
|
30
|
+
Replace the example URL and implement the vendor's initialization. This is a
|
|
31
|
+
loader template, not a functioning analytics SDK. The script stays blocked
|
|
32
|
+
while measurement permission is denied.
|
|
229
33
|
|
|
230
|
-
|
|
34
|
+
## Define revocation deliberately
|
|
231
35
|
|
|
232
|
-
|
|
36
|
+
`onConsentChange` receives current permission information. Use it to update the
|
|
37
|
+
vendor's consent API or disable future work. `persistAfterConsentRevoked` retains
|
|
38
|
+
a loaded script when set; `alwaysLoad` bypasses initial category gating. Enable
|
|
39
|
+
those only when the vendor's own consent behavior matches the intended design.
|
|
233
40
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|Source Path|\`./packages/scripts/src/types.ts\`|
|
|
41
|
+
For a library imported elsewhere, `callbackOnly` allows lifecycle callbacks
|
|
42
|
+
without inserting a script element. It does not prevent that earlier import
|
|
43
|
+
from running. For SDKs with side effects at import time, defer the import too.
|
|
238
44
|
|
|
239
|
-
|
|
45
|
+
A browser cannot undo executed JavaScript merely by removing its script tag.
|
|
46
|
+
Test cleanup, queued events, re-grant and navigation. Use the provider's nonce
|
|
47
|
+
option or a per-script nonce for a nonce-based Content Security Policy.
|
|
@@ -1,130 +1,291 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Clearbit
|
|
3
|
-
description:
|
|
4
|
-
|
|
3
|
+
description: Configure Clearbit with c15t v3, understand marketing permission
|
|
4
|
+
and verify loading and revocation.
|
|
5
5
|
group: integrations
|
|
6
|
-
icon: clearbit
|
|
7
6
|
---
|
|
8
|
-
[Clearbit](https://clearbit.com) provides visitor and company enrichment for go-to-market workflows. The official embed loads `https://tag.clearbitscripts.com/v1/{publishableKey}/tags.js` with a `referrerpolicy` of `strict-origin-when-cross-origin`.
|
|
9
7
|
|
|
10
|
-
##
|
|
8
|
+
## Configure Clearbit
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
Use the publishable key from your Clearbit tag installation. The helper loads the account-specific `tags.js` URL. Do not put a secret enrichment API key in browser code.
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
| Package manager | Command |
|
|
13
|
+
| :-------------- | :-------------------------- |
|
|
14
|
+
| npm | `npm install @c15t/scripts` |
|
|
15
|
+
| pnpm | `pnpm add @c15t/scripts` |
|
|
16
|
+
| yarn | `yarn add @c15t/scripts` |
|
|
17
|
+
| bun | `bun add @c15t/scripts` |
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
publishableKey: 'YOUR_PUBLISHABLE_KEY',
|
|
22
|
-
}),
|
|
23
|
-
];
|
|
19
|
+
```ts title="src/consent-scripts.ts"
|
|
20
|
+
import { clearbit } from '@c15t/scripts/clearbit';
|
|
24
21
|
|
|
25
|
-
export
|
|
26
|
-
return (
|
|
27
|
-
<ConsentManagerProvider
|
|
28
|
-
options={{
|
|
29
|
-
mode: 'hosted',
|
|
30
|
-
backendURL: 'https://your-instance.c15t.dev',
|
|
31
|
-
scripts,
|
|
32
|
-
}}
|
|
33
|
-
>
|
|
34
|
-
{children}
|
|
35
|
-
</ConsentManagerProvider>
|
|
36
|
-
);
|
|
37
|
-
}
|
|
22
|
+
export const scripts = [clearbit({ publishableKey: 'YOUR_PUBLISHABLE_KEY' })];
|
|
38
23
|
```
|
|
39
24
|
|
|
25
|
+
## Register the scripts
|
|
26
|
+
|
|
27
|
+
Complete your [framework quickstart](https://c15t.com/docs/frameworks) first. Keep its Inth
|
|
28
|
+
endpoint, policy, styles and consent UI. Remove the vendor's original script,
|
|
29
|
+
SDK initializer or tag-manager entry so c15t owns loading once.
|
|
30
|
+
|
|
31
|
+
The `scripts` export in `src/consent-scripts.ts` is a configuration, not an
|
|
32
|
+
initializer. Add it to your existing consent owner using the registration point
|
|
33
|
+
below. These are partial edits to that owner, not additional providers.
|
|
34
|
+
|
|
40
35
|
**Next.js**
|
|
41
36
|
|
|
37
|
+
Import the configuration into the client boundary from your router guide:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { ConsentRoot } from 'c15t/next';
|
|
41
|
+
import { scripts } from './consent-scripts';
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Keep the server-resolved `state` and shared `consentConfig` from your
|
|
45
|
+
router guide. Its manifest, init and save URLs stay in effect. Add
|
|
46
|
+
`scripts` as a top-level prop on the existing root:
|
|
47
|
+
|
|
42
48
|
```tsx
|
|
43
|
-
|
|
49
|
+
<ConsentRoot state={state} config={consentConfig} scripts={scripts}>
|
|
50
|
+
{children}
|
|
51
|
+
</ConsentRoot>
|
|
52
|
+
```
|
|
44
53
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
For a Pages Router or static-export setup using `ConsentProvider`, add
|
|
55
|
+
`scripts` to its existing `options` instead. Keep the router-specific setup
|
|
56
|
+
from [Next.js script loading](../frameworks/next/script-loader.md).
|
|
57
|
+
|
|
58
|
+
**TanStack Start**
|
|
48
59
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
publishableKey: 'YOUR_PUBLISHABLE_KEY',
|
|
52
|
-
}),
|
|
53
|
-
];
|
|
60
|
+
In your existing root route component, import the scripts alongside
|
|
61
|
+
`ConsentRoot`. Keep the server loader from the [TanStack Start quickstart](https://c15t.com/docs/frameworks/tanstack-start/quickstart).
|
|
54
62
|
|
|
55
|
-
|
|
63
|
+
```tsx
|
|
64
|
+
import { Outlet } from '@tanstack/react-router';
|
|
65
|
+
import { ConsentRoot } from 'c15t/tanstack-start';
|
|
66
|
+
import { scripts } from '../consent-scripts';
|
|
67
|
+
|
|
68
|
+
function Root() {
|
|
69
|
+
const state = Route.useLoaderData();
|
|
56
70
|
return (
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
scripts,
|
|
62
|
-
}}
|
|
63
|
-
>
|
|
64
|
-
{children}
|
|
65
|
-
</ConsentManagerProvider>
|
|
71
|
+
<ConsentRoot state={state} backendURL={backendURL} initRoute={false} scripts={scripts}>
|
|
72
|
+
<Outlet />
|
|
73
|
+
{/* Keep your consent banner, dialog and preferences link here. */}
|
|
74
|
+
</ConsentRoot>
|
|
66
75
|
);
|
|
67
76
|
}
|
|
68
77
|
```
|
|
69
78
|
|
|
70
|
-
|
|
79
|
+
This edits the existing route. `Route` and `backendURL` come from its setup;
|
|
80
|
+
keep the document shell and head components if they are part of your root.
|
|
81
|
+
`initRoute={false}` keeps the quickstart's direct-backend initialization.
|
|
82
|
+
If your app mounts a consent server route, retain its existing `initRoute`
|
|
83
|
+
instead. Do not return script callbacks from a server function or route loader.
|
|
84
|
+
|
|
85
|
+
**React**
|
|
86
|
+
|
|
87
|
+
Import the scripts into your existing provider component:
|
|
71
88
|
|
|
72
89
|
```ts
|
|
73
|
-
import {
|
|
74
|
-
import {
|
|
90
|
+
import { ConsentProvider } from 'c15t/react';
|
|
91
|
+
import { scripts } from './consent-scripts';
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Keep the existing options and add `scripts`:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
<ConsentProvider options={{ ...consentOptions, scripts }}>
|
|
98
|
+
{children}
|
|
99
|
+
</ConsentProvider>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Here `consentOptions` is your existing configuration, including
|
|
103
|
+
`mode: hosted({ url: backendURL })`. Keep the banner, dialog and preferences
|
|
104
|
+
link inside the provider. See [React script loading](../frameworks/react/script-loader.md).
|
|
105
|
+
|
|
106
|
+
**Nuxt**
|
|
107
|
+
|
|
108
|
+
Attach one loader from the root `app.vue`, after the Nuxt module has
|
|
109
|
+
started its browser runtime. This keeps vendor callbacks in application code rather
|
|
110
|
+
than serialized `nuxt.config.ts` runtime configuration.
|
|
111
|
+
|
|
112
|
+
```vue title="app/app.vue"
|
|
113
|
+
<script setup lang="ts">
|
|
114
|
+
import { onUnmounted } from 'vue';
|
|
115
|
+
import { createScriptLoader } from 'c15t/modules/script-loader';
|
|
116
|
+
import { scripts } from '../src/consent-scripts';
|
|
117
|
+
|
|
118
|
+
const nuxtApp = useNuxtApp();
|
|
119
|
+
const kernel = useConsentKernel();
|
|
120
|
+
let loader: ReturnType<typeof createScriptLoader> | undefined;
|
|
121
|
+
|
|
122
|
+
const removeMountedHook = nuxtApp.hook('app:mounted', () => {
|
|
123
|
+
loader = createScriptLoader({ kernel, scripts });
|
|
124
|
+
});
|
|
125
|
+
onUnmounted(() => {
|
|
126
|
+
removeMountedHook();
|
|
127
|
+
loader?.dispose();
|
|
128
|
+
});
|
|
129
|
+
</script>
|
|
130
|
+
|
|
131
|
+
<template>
|
|
132
|
+
<ConsentRoot />
|
|
133
|
+
<NuxtPage />
|
|
134
|
+
</template>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Merge the setup code into your root and retain its footer and preferences
|
|
138
|
+
link. `useConsentKernel` is auto-imported by the c15t Nuxt module. Adjust the
|
|
139
|
+
relative script import if your `app.vue` is at the project root. This loader
|
|
140
|
+
waits until the module has applied browser persistence and privacy signals,
|
|
141
|
+
then reads the current snapshot and observes future changes. Do not also register these scripts
|
|
142
|
+
in another loader. See the [Nuxt quickstart](https://c15t.com/docs/frameworks/nuxt/quickstart).
|
|
143
|
+
|
|
144
|
+
**Vue**
|
|
145
|
+
|
|
146
|
+
Use the kernel already provided by the Vue plugin. Merge this setup into
|
|
147
|
+
`App.vue`, whose lifetime covers the application:
|
|
148
|
+
|
|
149
|
+
```vue title="src/App.vue"
|
|
150
|
+
<script setup lang="ts">
|
|
151
|
+
import { onMounted, onUnmounted } from 'vue';
|
|
152
|
+
import { createScriptLoader } from 'c15t/modules/script-loader';
|
|
153
|
+
import { useConsentKernel } from 'c15t/vue/vue-plugin';
|
|
154
|
+
import ConsentRoot from 'c15t/vue/consent-root';
|
|
155
|
+
import { scripts } from './consent-scripts';
|
|
156
|
+
|
|
157
|
+
const kernel = useConsentKernel();
|
|
158
|
+
let loader: ReturnType<typeof createScriptLoader> | undefined;
|
|
75
159
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
backendURL: 'https://your-instance.c15t.dev',
|
|
79
|
-
scripts: [
|
|
80
|
-
clearbit({
|
|
81
|
-
publishableKey: 'YOUR_PUBLISHABLE_KEY',
|
|
82
|
-
}),
|
|
83
|
-
],
|
|
160
|
+
onMounted(() => {
|
|
161
|
+
loader = createScriptLoader({ kernel, scripts });
|
|
84
162
|
});
|
|
163
|
+
onUnmounted(() => loader?.dispose());
|
|
164
|
+
</script>
|
|
165
|
+
|
|
166
|
+
<template>
|
|
167
|
+
<ConsentRoot />
|
|
168
|
+
<main>Your application</main>
|
|
169
|
+
</template>
|
|
85
170
|
```
|
|
86
171
|
|
|
87
|
-
|
|
172
|
+
Keep your existing page content and preferences link. The plugin still owns
|
|
173
|
+
the kernel and persistence; this component owns only the vendor loader.
|
|
174
|
+
Do not register the same scripts in plugin configuration as well. See the
|
|
175
|
+
[Vue quickstart](https://c15t.com/docs/frameworks/vue/quickstart).
|
|
88
176
|
|
|
89
|
-
|
|
90
|
-
* **Loads when:** marketing consent is granted
|
|
91
|
-
* **On revocation:** unloaded — c15t removes the script element from the DOM.
|
|
177
|
+
**Astro**
|
|
92
178
|
|
|
93
|
-
|
|
179
|
+
Point the existing Astro integration at a client module. Keep its `mode`,
|
|
180
|
+
`ui` and framework integration from the [Astro quickstart](https://c15t.com/docs/frameworks/astro/quickstart).
|
|
181
|
+
Import `fileURLToPath` in your Astro configuration:
|
|
94
182
|
|
|
95
|
-
|
|
183
|
+
```js title="astro.config.mjs"
|
|
184
|
+
import { fileURLToPath } from 'node:url';
|
|
185
|
+
```
|
|
96
186
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
187
|
+
Add this option to the existing `c15t({ ... })` call. Resolve the path from
|
|
188
|
+
the configuration file because Astro injects the import into a virtual module:
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
clientEntrypoint: fileURLToPath(new URL('./src/c15t.client.ts', import.meta.url)),
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Export the scripts from that module:
|
|
195
|
+
|
|
196
|
+
```ts title="src/c15t.client.ts"
|
|
197
|
+
import type { C15tClientOptionsExtension } from '@c15t/astro';
|
|
198
|
+
import { scripts } from './consent-scripts';
|
|
199
|
+
|
|
200
|
+
export default { scripts } satisfies C15tClientOptionsExtension;
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The integration passes this extension to its shared browser runtime. Vendor
|
|
204
|
+
helpers contain callbacks, so do not put them in the serialized `scripts`
|
|
205
|
+
option in `astro.config.mjs`. Keep one runtime across consent islands and
|
|
206
|
+
`ClientRouter` navigation.
|
|
207
|
+
|
|
208
|
+
**Svelte**
|
|
209
|
+
|
|
210
|
+
Import the scripts in the component that owns your existing provider and
|
|
211
|
+
pass them as a top-level prop:
|
|
212
|
+
|
|
213
|
+
```svelte title="src/App.svelte"
|
|
214
|
+
<script lang="ts">
|
|
215
|
+
import { ConsentManagerProvider, hosted } from '@c15t/svelte';
|
|
216
|
+
import { scripts } from './consent-scripts';
|
|
217
|
+
|
|
218
|
+
const backendURL = import.meta.env.VITE_C15T_BACKEND_URL;
|
|
219
|
+
if (!backendURL) throw new Error('Set VITE_C15T_BACKEND_URL');
|
|
220
|
+
const mode = hosted({ url: backendURL });
|
|
221
|
+
</script>
|
|
222
|
+
|
|
223
|
+
<ConsentManagerProvider {mode} {scripts}>
|
|
224
|
+
<!-- Keep your application, consent UI and preferences link here. -->
|
|
225
|
+
</ConsentManagerProvider>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Retain the styles and consent UI from the [Svelte quickstart](https://c15t.com/docs/frameworks/svelte/quickstart).
|
|
229
|
+
The provider owns the loader and disposes it on unmount.
|
|
230
|
+
|
|
231
|
+
**SvelteKit**
|
|
232
|
+
|
|
233
|
+
Add the scripts to the existing root layout provider. Keep the server load
|
|
234
|
+
and its serializable prefetch data from the [SvelteKit quickstart](https://c15t.com/docs/frameworks/sveltekit/quickstart).
|
|
235
|
+
|
|
236
|
+
```svelte title="src/routes/+layout.svelte"
|
|
237
|
+
<script lang="ts">
|
|
238
|
+
import { ConsentManagerProvider, hosted } from '@c15t/svelte';
|
|
239
|
+
import { scripts } from '../consent-scripts';
|
|
240
|
+
|
|
241
|
+
let { children, data } = $props();
|
|
242
|
+
const mode = hosted({ url: data.backendURL });
|
|
243
|
+
</script>
|
|
244
|
+
|
|
245
|
+
<ConsentManagerProvider {mode} {scripts} prefetch={data.prefetch}>
|
|
246
|
+
{@render children()}
|
|
247
|
+
<!-- Keep your consent UI and preferences link here. -->
|
|
248
|
+
</ConsentManagerProvider>
|
|
101
249
|
```
|
|
102
250
|
|
|
103
|
-
|
|
251
|
+
Import vendor helpers in the layout component, not in `+layout.server.ts`.
|
|
252
|
+
For static hosting, keep your browser-only `mode` setup and omit request
|
|
253
|
+
prefetch; the `scripts` prop stays the same. If you pass an externally owned
|
|
254
|
+
`runtime` to the provider, register scripts when creating that runtime instead.
|
|
255
|
+
|
|
256
|
+
**JavaScript**
|
|
257
|
+
|
|
258
|
+
Attach the loader to your existing kernel before calling
|
|
259
|
+
`kernel.commands.init()`:
|
|
104
260
|
|
|
105
261
|
```ts
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
})
|
|
262
|
+
import { createScriptLoader } from 'c15t/modules/script-loader';
|
|
263
|
+
import { scripts } from './consent-scripts';
|
|
264
|
+
|
|
265
|
+
const loader = createScriptLoader({ kernel, scripts });
|
|
110
266
|
```
|
|
111
267
|
|
|
112
|
-
|
|
268
|
+
Call `loader.dispose()` when that application instance is destroyed.
|
|
269
|
+
`kernel` is the hosted kernel from your quickstart. A provider-owned kernel
|
|
270
|
+
already has a loader; do not attach a second one. See
|
|
271
|
+
[JavaScript script loading](../frameworks/javascript/script-loader.md).
|
|
272
|
+
|
|
273
|
+
## Options
|
|
113
274
|
|
|
114
|
-
|
|
275
|
+
| Option | Behavior |
|
|
276
|
+
| ---------------- | -------------------------------------------------------------------------- |
|
|
277
|
+
| `publishableKey` | Required non-empty publishable key. |
|
|
278
|
+
| `scriptUrl` | Optional full loader override; otherwise derived from the publishable key. |
|
|
115
279
|
|
|
116
|
-
|
|
117
|
-
|:--|:--|
|
|
118
|
-
|Type Name|\`ClearbitOptions\`|
|
|
119
|
-
|Source Path|\`./packages/scripts/src/vendors/analytics/clearbit.ts\`|
|
|
280
|
+
## Consent behavior
|
|
120
281
|
|
|
121
|
-
|
|
282
|
+
Clearbit is listed under Analytics for discovery, but its helper uses marketing permission because it performs enrichment. The helper has no vendor revocation callback; do not assume removing the tag stops an enrichment SDK that already ran.
|
|
122
283
|
|
|
123
|
-
|
|
284
|
+
## Verify the integration
|
|
124
285
|
|
|
125
|
-
|
|
126
|
-
|:--|:--|
|
|
127
|
-
|Type Name|\`Script\`|
|
|
128
|
-
|Source Path|\`./packages/core/src/libs/script-loader/types.ts\`|
|
|
286
|
+
Check the account key in the requested loader URL and inspect enrichment requests. Confirm marketing rejection prevents the initial load, even when measurement is allowed.
|
|
129
287
|
|
|
130
|
-
|
|
288
|
+
Use a fresh session with an opt-in policy to check initial denial. Then grant
|
|
289
|
+
`marketing`, revoke it, and reload. Inspect both network requests and future
|
|
290
|
+
application events. Removing a script cannot undo code or requests that already
|
|
291
|
+
ran. Follow the [consent verification guide](../guides/verify-consent.md).
|