@c15t/scripts 2.1.0 → 2.2.0-canary-20260804162155
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 +62 -0
- package/README.md +32 -20
- package/dist/e2e-test-utils.cjs +51 -10
- package/dist/e2e-test-utils.js +37 -3
- package/dist/engine/compile.cjs +9 -5
- package/dist/engine/runtime.cjs +103 -17
- package/dist/engine/runtime.js +94 -12
- package/dist/registry.cjs +97 -12
- package/dist/registry.js +80 -0
- package/dist/resolve.cjs +9 -5
- package/dist/types.cjs +17 -13
- package/dist/vendors/_shared/attributes.cjs +13 -9
- package/dist/vendors/_shared/google-consent.cjs +14 -9
- package/dist/vendors/_shared/install-builders.cjs +12 -8
- package/dist/vendors/_shared/script-url.cjs +16 -12
- package/dist/vendors/ads-and-pixels/linkedin-insights.cjs +9 -5
- package/dist/vendors/ads-and-pixels/meta-pixel.cjs +13 -9
- package/dist/vendors/ads-and-pixels/microsoft-uet.cjs +11 -7
- package/dist/vendors/ads-and-pixels/reddit-pixel.cjs +9 -5
- package/dist/vendors/ads-and-pixels/snapchat-pixel.cjs +11 -7
- package/dist/vendors/ads-and-pixels/tiktok-pixel.cjs +9 -5
- package/dist/vendors/ads-and-pixels/x-pixel.cjs +9 -5
- package/dist/vendors/analytics/adobe-analytics.cjs +90 -0
- package/dist/vendors/analytics/adobe-analytics.js +49 -0
- package/dist/vendors/analytics/ahrefs-analytics.cjs +11 -7
- package/dist/vendors/analytics/amplitude.cjs +193 -0
- package/dist/vendors/analytics/amplitude.js +134 -0
- package/dist/vendors/analytics/clearbit.cjs +69 -0
- package/dist/vendors/analytics/clearbit.js +28 -0
- package/dist/vendors/analytics/cloudflare-web-analytics.cjs +11 -7
- package/dist/vendors/analytics/databuddy.cjs +11 -7
- package/dist/vendors/analytics/fathom-analytics.cjs +11 -7
- package/dist/vendors/analytics/google-tag.cjs +11 -7
- package/dist/vendors/analytics/heap.cjs +181 -0
- package/dist/vendors/analytics/heap.js +134 -0
- package/dist/vendors/analytics/hightouch.cjs +153 -0
- package/dist/vendors/analytics/hightouch.js +109 -0
- package/dist/vendors/analytics/hotjar.cjs +11 -7
- package/dist/vendors/analytics/logrocket.cjs +99 -0
- package/dist/vendors/analytics/logrocket.js +58 -0
- package/dist/vendors/analytics/matomo-analytics.cjs +9 -5
- package/dist/vendors/analytics/microsoft-clarity.cjs +75 -47
- package/dist/vendors/analytics/microsoft-clarity.js +64 -40
- package/dist/vendors/analytics/mixpanel-analytics.cjs +31 -16
- package/dist/vendors/analytics/mixpanel-analytics.js +22 -11
- package/dist/vendors/analytics/pirsch.cjs +108 -0
- package/dist/vendors/analytics/pirsch.js +67 -0
- package/dist/vendors/analytics/plausible-analytics.cjs +9 -5
- package/dist/vendors/analytics/posthog.cjs +63 -27
- package/dist/vendors/analytics/posthog.js +52 -20
- package/dist/vendors/analytics/promptwatch.cjs +11 -7
- package/dist/vendors/analytics/rudderstack.cjs +227 -0
- package/dist/vendors/analytics/rudderstack.js +183 -0
- package/dist/vendors/analytics/rybbit-analytics.cjs +9 -5
- package/dist/vendors/analytics/segment.cjs +9 -5
- package/dist/vendors/analytics/umami-analytics.cjs +9 -5
- package/dist/vendors/analytics/vercel-analytics.cjs +11 -7
- package/dist/vendors/functional/crisp.cjs +9 -5
- package/dist/vendors/functional/intercom.cjs +11 -7
- package/dist/vendors/tag-managers/google-tag-manager.cjs +11 -7
- package/dist-types/registry.d.ts +313 -241
- package/dist-types/types.d.ts +46 -4
- package/dist-types/vendors/ads-and-pixels/linkedin-insights.d.ts +18 -18
- package/dist-types/vendors/ads-and-pixels/meta-pixel.d.ts +21 -21
- package/dist-types/vendors/ads-and-pixels/microsoft-uet.d.ts +32 -32
- package/dist-types/vendors/ads-and-pixels/reddit-pixel.d.ts +19 -19
- package/dist-types/vendors/ads-and-pixels/snapchat-pixel.d.ts +16 -16
- package/dist-types/vendors/ads-and-pixels/tiktok-pixel.d.ts +28 -28
- package/dist-types/vendors/ads-and-pixels/x-pixel.d.ts +13 -13
- package/dist-types/vendors/analytics/adobe-analytics.d.ts +75 -0
- package/dist-types/vendors/analytics/ahrefs-analytics.d.ts +7 -7
- package/dist-types/vendors/analytics/amplitude.d.ts +234 -0
- package/dist-types/vendors/analytics/clearbit.d.ts +60 -0
- package/dist-types/vendors/analytics/cloudflare-web-analytics.d.ts +7 -7
- package/dist-types/vendors/analytics/databuddy.d.ts +25 -25
- package/dist-types/vendors/analytics/fathom-analytics.d.ts +11 -11
- package/dist-types/vendors/analytics/google-tag.d.ts +17 -17
- package/dist-types/vendors/analytics/heap.d.ts +316 -0
- package/dist-types/vendors/analytics/hightouch.d.ts +285 -0
- package/dist-types/vendors/analytics/hotjar.d.ts +14 -14
- package/dist-types/vendors/analytics/logrocket.d.ts +101 -0
- package/dist-types/vendors/analytics/microsoft-clarity.d.ts +42 -30
- package/dist-types/vendors/analytics/mixpanel-analytics.d.ts +40 -28
- package/dist-types/vendors/analytics/pirsch.d.ts +96 -0
- package/dist-types/vendors/analytics/plausible-analytics.d.ts +13 -13
- package/dist-types/vendors/analytics/posthog.d.ts +63 -45
- package/dist-types/vendors/analytics/promptwatch.d.ts +7 -7
- package/dist-types/vendors/analytics/rudderstack.d.ts +330 -0
- package/dist-types/vendors/analytics/rybbit-analytics.d.ts +18 -18
- package/dist-types/vendors/analytics/segment.d.ts +13 -13
- package/dist-types/vendors/analytics/umami-analytics.d.ts +12 -12
- package/dist-types/vendors/analytics/vercel-analytics.d.ts +16 -16
- package/dist-types/vendors/functional/crisp.d.ts +11 -11
- package/dist-types/vendors/functional/intercom.d.ts +16 -16
- package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +18 -18
- package/docs/README.md +62 -0
- package/docs/frameworks/javascript/script-loader.md +356 -0
- package/docs/frameworks/next/script-loader.md +501 -0
- package/docs/frameworks/react/script-loader.md +555 -0
- package/docs/integrations/adobe-analytics.md +160 -0
- package/docs/integrations/ahrefs-analytics.md +157 -0
- package/docs/integrations/amplitude.md +230 -0
- package/docs/integrations/building-integrations.md +239 -0
- package/docs/integrations/clearbit.md +130 -0
- package/docs/integrations/cloudflare-web-analytics.md +126 -0
- package/docs/integrations/crisp.md +140 -0
- package/docs/integrations/databuddy.md +205 -0
- package/docs/integrations/fathom-analytics.md +150 -0
- package/docs/integrations/google-maps.md +263 -0
- package/docs/integrations/google-tag-manager.md +154 -0
- package/docs/integrations/google-tag.md +134 -0
- package/docs/integrations/heap.md +219 -0
- package/docs/integrations/hightouch.md +199 -0
- package/docs/integrations/hotjar.md +143 -0
- package/docs/integrations/intercom.md +144 -0
- package/docs/integrations/linkedin-insights.md +161 -0
- package/docs/integrations/logrocket.md +175 -0
- package/docs/integrations/matomo-analytics.md +171 -0
- package/docs/integrations/meta-pixel.md +412 -0
- package/docs/integrations/microsoft-clarity.md +173 -0
- package/docs/integrations/microsoft-uet.md +156 -0
- package/docs/integrations/mixpanel-analytics.md +130 -0
- package/docs/integrations/overview.md +149 -0
- package/docs/integrations/pirsch.md +142 -0
- package/docs/integrations/plausible-analytics.md +154 -0
- package/docs/integrations/posthog.md +258 -0
- package/docs/integrations/promptwatch.md +121 -0
- package/docs/integrations/reddit-pixel.md +241 -0
- package/docs/integrations/rudderstack.md +271 -0
- package/docs/integrations/rybbit-analytics.md +143 -0
- package/docs/integrations/segment.md +146 -0
- package/docs/integrations/snapchat-pixel.md +163 -0
- package/docs/integrations/tiktok-pixel.md +123 -0
- package/docs/integrations/umami-analytics.md +148 -0
- package/docs/integrations/vercel-analytics.md +141 -0
- package/docs/integrations/x-pixel.md +157 -0
- package/docs/integrations/youtube.md +193 -0
- package/docs/shared/react/guides/script-loader.md +311 -0
- package/package.json +61 -7
- package/readme.json +8 -4
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Reddit Pixel
|
|
3
|
+
description: Track conversions and build retargeting audiences for Reddit
|
|
4
|
+
advertising campaigns.
|
|
5
|
+
group: integrations
|
|
6
|
+
icon: reddit
|
|
7
|
+
---
|
|
8
|
+
Reddit Pixel is Reddit's conversion tracking tool for ads and remarketing. It seeds the standard `rdt` queue before the vendor bundle loads, initializes your pixel, and by default records a `PageVisit` event once consent for `marketing` is available.
|
|
9
|
+
|
|
10
|
+
## Integrate with c15t
|
|
11
|
+
|
|
12
|
+
**React**
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { type ReactNode } from 'react';
|
|
16
|
+
import { ConsentManagerProvider } from '@c15t/react';
|
|
17
|
+
import { redditPixel } from '@c15t/scripts/reddit-pixel';
|
|
18
|
+
|
|
19
|
+
const scripts = [redditPixel({ pixelId: 't2_abcdef' })];
|
|
20
|
+
|
|
21
|
+
export function ConsentProvider({ children }: { children: ReactNode }) {
|
|
22
|
+
return (
|
|
23
|
+
<ConsentManagerProvider
|
|
24
|
+
options={{
|
|
25
|
+
mode: 'hosted',
|
|
26
|
+
backendURL: 'https://your-instance.c15t.dev',
|
|
27
|
+
scripts,
|
|
28
|
+
}}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
</ConsentManagerProvider>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Next.js**
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
'use client';
|
|
40
|
+
|
|
41
|
+
import { type ReactNode } from 'react';
|
|
42
|
+
import { ConsentManagerProvider } from '@c15t/nextjs';
|
|
43
|
+
import { redditPixel } from '@c15t/scripts/reddit-pixel';
|
|
44
|
+
|
|
45
|
+
const scripts = [redditPixel({ pixelId: 't2_abcdef' })];
|
|
46
|
+
|
|
47
|
+
export function ConsentProvider({ children }: { children: ReactNode }) {
|
|
48
|
+
return (
|
|
49
|
+
<ConsentManagerProvider
|
|
50
|
+
options={{
|
|
51
|
+
mode: 'hosted',
|
|
52
|
+
backendURL: '/api/c15t',
|
|
53
|
+
scripts,
|
|
54
|
+
}}
|
|
55
|
+
>
|
|
56
|
+
{children}
|
|
57
|
+
</ConsentManagerProvider>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**JavaScript**
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { getOrCreateConsentRuntime } from 'c15t';
|
|
66
|
+
import { redditPixel } from '@c15t/scripts/reddit-pixel';
|
|
67
|
+
|
|
68
|
+
getOrCreateConsentRuntime({
|
|
69
|
+
mode: 'hosted',
|
|
70
|
+
backendURL: 'https://your-instance.c15t.dev',
|
|
71
|
+
scripts: [redditPixel({ pixelId: 't2_abcdef' })],
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## How c15t loads it
|
|
76
|
+
|
|
77
|
+
* **Category:** `marketing` (Ads & Pixels)
|
|
78
|
+
* **Loads when:** marketing consent is granted
|
|
79
|
+
* **On revocation:** retained in the DOM so c15t can call Reddit's
|
|
80
|
+
first-party-cookie controls. c15t calls `rdt('disableFirstPartyCookies')`
|
|
81
|
+
when marketing consent is denied and `rdt('enableFirstPartyCookies')` when
|
|
82
|
+
it is granted again.
|
|
83
|
+
|
|
84
|
+
If you prefer to control page-view tracking yourself, disable the default `PageVisit` call:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
redditPixel({
|
|
88
|
+
pixelId: 't2_abcdef',
|
|
89
|
+
trackPageVisit: false,
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Tracking events in your app
|
|
94
|
+
|
|
95
|
+
c15t gates the Reddit Pixel script from loading until `marketing` consent is granted. Your application code that calls Reddit's runtime API (`window.rdt(...)`) is **not** automatically gated - `window.rdt` does not exist until the script is loaded, so unguarded calls before consent throw.
|
|
96
|
+
|
|
97
|
+
Guard event calls by checking consent state. From React:
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import { useCallback } from 'react';
|
|
101
|
+
import { useConsentManager } from '@c15t/react';
|
|
102
|
+
import { redditPixelEvent } from '@c15t/scripts/reddit-pixel';
|
|
103
|
+
|
|
104
|
+
function CheckoutExample() {
|
|
105
|
+
const { has } = useConsentManager();
|
|
106
|
+
|
|
107
|
+
const trackPurchase = useCallback(() => {
|
|
108
|
+
if (has('marketing')) {
|
|
109
|
+
redditPixelEvent('Purchase', {
|
|
110
|
+
currency: 'USD',
|
|
111
|
+
value: 99,
|
|
112
|
+
conversionId: 'order-123',
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}, [has]);
|
|
116
|
+
|
|
117
|
+
// Call trackPurchase() from your conversion success path.
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
From plain JavaScript:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { getOrCreateConsentRuntime } from 'c15t';
|
|
125
|
+
|
|
126
|
+
const { consentStore } = getOrCreateConsentRuntime();
|
|
127
|
+
|
|
128
|
+
if (consentStore.getState().has('marketing')) {
|
|
129
|
+
window.rdt?.('track', 'Purchase', {
|
|
130
|
+
currency: 'USD',
|
|
131
|
+
value: 99,
|
|
132
|
+
conversionId: 'order-123',
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
When you use Reddit Pixel and Conversions API together, send the same
|
|
138
|
+
`conversionId` in the browser event and the server event so Reddit can
|
|
139
|
+
deduplicate them.
|
|
140
|
+
|
|
141
|
+
## Consent and privacy
|
|
142
|
+
|
|
143
|
+
c15t keeps Reddit Pixel behind `marketing` consent. Before marketing consent,
|
|
144
|
+
the Reddit script is not loaded. After marketing consent is granted, c15t loads
|
|
145
|
+
the script and queues the Reddit `init` call.
|
|
146
|
+
|
|
147
|
+
For stricter first-party-cookie behavior, disable Reddit first-party cookies
|
|
148
|
+
during initialization:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
redditPixel({
|
|
152
|
+
pixelId: 't2_abcdef',
|
|
153
|
+
disableFirstPartyCookies: true,
|
|
154
|
+
})
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
You can also pass Reddit's initialization options directly:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
redditPixel({
|
|
161
|
+
pixelId: 't2_abcdef',
|
|
162
|
+
initOptions: {
|
|
163
|
+
optOut: true,
|
|
164
|
+
disableFirstPartyCookies: true,
|
|
165
|
+
},
|
|
166
|
+
})
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Reddit supports a Limited Data Use flag through data processing fields. Use the
|
|
170
|
+
values required by your policy and jurisdiction:
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
redditPixel({
|
|
174
|
+
pixelId: 't2_abcdef',
|
|
175
|
+
initOptions: {
|
|
176
|
+
dpm: ['LDU'],
|
|
177
|
+
dpcc: 'US',
|
|
178
|
+
dprc: 'CA',
|
|
179
|
+
},
|
|
180
|
+
})
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Reddit can also receive attribution matching signals such as `email`,
|
|
184
|
+
`phoneNumber`, `externalId`, `aaid`, and `idfa`. Only pass those fields after
|
|
185
|
+
you have the right consent or legal basis for your use case:
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
redditPixel({
|
|
189
|
+
pixelId: 't2_abcdef',
|
|
190
|
+
initOptions: {
|
|
191
|
+
email: 'person@example.com',
|
|
192
|
+
externalId: 'customer-123',
|
|
193
|
+
aam: {
|
|
194
|
+
email: false,
|
|
195
|
+
phone_number: false,
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
})
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
See Reddit's docs for [Limited Data Use](https://business.reddithelp.com/s/article/Limited-Data-Use),
|
|
202
|
+
[event metadata](https://business.reddithelp.com/s/article/about-event-metadata),
|
|
203
|
+
and [event deduplication](https://business.reddithelp.com/s/article/event-deduplication).
|
|
204
|
+
|
|
205
|
+
## Types
|
|
206
|
+
|
|
207
|
+
### RedditPixelOptions
|
|
208
|
+
|
|
209
|
+
|Property|Value|
|
|
210
|
+
|:--|:--|
|
|
211
|
+
|Type Name|\`RedditPixelOptions\`|
|
|
212
|
+
|Source Path|\`./packages/scripts/src/vendors/ads-and-pixels/reddit-pixel.ts\`|
|
|
213
|
+
|
|
214
|
+
\*ExtractedTypeTable: Could not extract "RedditPixelOptions" from "./packages/scripts/src/vendors/ads-and-pixels/reddit-pixel.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
|
|
215
|
+
|
|
216
|
+
### RedditPixelInitOptions
|
|
217
|
+
|
|
218
|
+
|Property|Value|
|
|
219
|
+
|:--|:--|
|
|
220
|
+
|Type Name|\`RedditPixelInitOptions\`|
|
|
221
|
+
|Source Path|\`./packages/scripts/src/vendors/ads-and-pixels/reddit-pixel.ts\`|
|
|
222
|
+
|
|
223
|
+
\*ExtractedTypeTable: Could not extract "RedditPixelInitOptions" from "./packages/scripts/src/vendors/ads-and-pixels/reddit-pixel.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
|
|
224
|
+
|
|
225
|
+
### RedditPixelEventMetadata
|
|
226
|
+
|
|
227
|
+
|Property|Value|
|
|
228
|
+
|:--|:--|
|
|
229
|
+
|Type Name|\`RedditPixelEventMetadata\`|
|
|
230
|
+
|Source Path|\`./packages/scripts/src/vendors/ads-and-pixels/reddit-pixel.ts\`|
|
|
231
|
+
|
|
232
|
+
\*ExtractedTypeTable: Could not extract "RedditPixelEventMetadata" from "./packages/scripts/src/vendors/ads-and-pixels/reddit-pixel.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
|
|
233
|
+
|
|
234
|
+
### Script
|
|
235
|
+
|
|
236
|
+
|Property|Value|
|
|
237
|
+
|:--|:--|
|
|
238
|
+
|Type Name|\`Script\`|
|
|
239
|
+
|Source Path|\`./packages/core/src/libs/script-loader/types.ts\`|
|
|
240
|
+
|
|
241
|
+
\*ExtractedTypeTable: Could not extract "Script" from "./packages/core/src/libs/script-loader/types.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: RudderStack
|
|
3
|
+
description: Load RudderStack's JavaScript SDK with c15t and gate the browser
|
|
4
|
+
SDK behind measurement consent.
|
|
5
|
+
group: integrations
|
|
6
|
+
icon: rudderstack
|
|
7
|
+
---
|
|
8
|
+
[RudderStack](https://www.rudderstack.com/) collects customer data from websites and routes it through your RudderStack data plane to downstream destinations. The `rudderstack()` helper creates RudderStack's `window.rudderanalytics` v3 queue, queues the required `load()` call with your write key and data plane URL, optionally queues the initial `page()` call, and loads the browser SDK when `measurement` consent is available.
|
|
9
|
+
|
|
10
|
+
## Integrate with c15t
|
|
11
|
+
|
|
12
|
+
**React**
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { type ReactNode } from 'react';
|
|
16
|
+
import { ConsentManagerProvider } from '@c15t/react';
|
|
17
|
+
import { rudderstack } from '@c15t/scripts/rudderstack';
|
|
18
|
+
|
|
19
|
+
const scripts = [
|
|
20
|
+
rudderstack({
|
|
21
|
+
writeKey: 'WRITE_KEY',
|
|
22
|
+
dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
|
|
23
|
+
}),
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
export function ConsentProvider({ children }: { children: ReactNode }) {
|
|
27
|
+
return (
|
|
28
|
+
<ConsentManagerProvider
|
|
29
|
+
options={{
|
|
30
|
+
mode: 'hosted',
|
|
31
|
+
backendURL: 'https://your-instance.c15t.dev',
|
|
32
|
+
scripts,
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
35
|
+
{children}
|
|
36
|
+
</ConsentManagerProvider>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Next.js**
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
'use client';
|
|
45
|
+
|
|
46
|
+
import { type ReactNode } from 'react';
|
|
47
|
+
import { ConsentManagerProvider } from '@c15t/nextjs';
|
|
48
|
+
import { rudderstack } from '@c15t/scripts/rudderstack';
|
|
49
|
+
|
|
50
|
+
const scripts = [
|
|
51
|
+
rudderstack({
|
|
52
|
+
writeKey: 'WRITE_KEY',
|
|
53
|
+
dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
|
|
54
|
+
}),
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
export function ConsentProvider({ children }: { children: ReactNode }) {
|
|
58
|
+
return (
|
|
59
|
+
<ConsentManagerProvider
|
|
60
|
+
options={{
|
|
61
|
+
mode: 'hosted',
|
|
62
|
+
backendURL: '/api/c15t',
|
|
63
|
+
scripts,
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
{children}
|
|
67
|
+
</ConsentManagerProvider>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**JavaScript**
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { getOrCreateConsentRuntime } from 'c15t';
|
|
76
|
+
import { rudderstack } from '@c15t/scripts/rudderstack';
|
|
77
|
+
|
|
78
|
+
getOrCreateConsentRuntime({
|
|
79
|
+
mode: 'hosted',
|
|
80
|
+
backendURL: 'https://your-instance.c15t.dev',
|
|
81
|
+
scripts: [
|
|
82
|
+
rudderstack({
|
|
83
|
+
writeKey: 'WRITE_KEY',
|
|
84
|
+
dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
|
|
85
|
+
}),
|
|
86
|
+
],
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## How c15t loads it
|
|
91
|
+
|
|
92
|
+
* **Category:** `measurement` (Analytics)
|
|
93
|
+
* **Loads when:** measurement consent is granted
|
|
94
|
+
* **On revocation:** unloaded - c15t removes the script element from the DOM and clears RudderStack globals until consent is granted again.
|
|
95
|
+
|
|
96
|
+
The helper maps RudderStack's v3 browser snippet into the manifest engine:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
rudderstack({
|
|
100
|
+
writeKey: 'WRITE_KEY',
|
|
101
|
+
dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
It creates `window.rudderanalytics`, defines the v3 snippet queue methods, queues:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
window.rudderanalytics.load(
|
|
109
|
+
'WRITE_KEY',
|
|
110
|
+
'https://example.dataplane.rudderstack.com',
|
|
111
|
+
{}
|
|
112
|
+
);
|
|
113
|
+
window.rudderanalytics.page();
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
and loads:
|
|
117
|
+
|
|
118
|
+
```txt
|
|
119
|
+
https://cdn.rudderlabs.com/v3/modern/rsa.min.js
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`writeKey` and `dataPlaneUrl` are both required and must be non-empty strings after trimming. `dataPlaneUrl` must be a valid HTTPS URL.
|
|
123
|
+
|
|
124
|
+
## Configure load options
|
|
125
|
+
|
|
126
|
+
Pass `loadOptions` to provide RudderStack SDK options as the third `load()` argument. Values must be JSON-serializable: plain objects, arrays, strings, numbers, booleans, and `null`.
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import { rudderstack } from '@c15t/scripts/rudderstack';
|
|
130
|
+
|
|
131
|
+
rudderstack({
|
|
132
|
+
writeKey: 'WRITE_KEY',
|
|
133
|
+
dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
|
|
134
|
+
loadOptions: {
|
|
135
|
+
useBeacon: true,
|
|
136
|
+
plugins: ['BeaconQueue'],
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Do not pass functions, Dates, Maps, Sets, class instances, symbols, or other non-JSON values in `loadOptions`.
|
|
142
|
+
|
|
143
|
+
## Configure page tracking
|
|
144
|
+
|
|
145
|
+
By default the helper queues `rudderanalytics.page()` before the vendor bundle loads. If you want to handle page views yourself, set `trackPageView` to `false`.
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
rudderstack({
|
|
149
|
+
writeKey: 'WRITE_KEY',
|
|
150
|
+
dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
|
|
151
|
+
trackPageView: false,
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
To proxy or self-host the loader, pass a custom URL:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
rudderstack({
|
|
159
|
+
writeKey: 'WRITE_KEY',
|
|
160
|
+
dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
|
|
161
|
+
scriptUrl: 'https://analytics.example.com/rsa.min.js',
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Consent behavior
|
|
166
|
+
|
|
167
|
+
RudderStack exposes a `consent()` API for its own consent-management flow and pre-consent event handling. That API is not a simple runtime opt-out or revocation API for c15t to call after a user withdraws `measurement` consent.
|
|
168
|
+
|
|
169
|
+
c15t therefore uses the post-consent model recommended by RudderStack's docs: it does not load the SDK until `measurement` consent is granted, and it unloads the script if that consent is later revoked.
|
|
170
|
+
|
|
171
|
+
### Why c15t blocks the load instead of mapping consent into RudderStack
|
|
172
|
+
|
|
173
|
+
Some integrations — Google Tag Manager is the clearest example — load immediately and receive c15t's consent state through the vendor's own consent API (Google Consent Mode v2). That model is only safe when the vendor API provides denied-by-default semantics where **nothing identifying is stored or transmitted before consent**.
|
|
174
|
+
|
|
175
|
+
Loading the RudderStack SDK does not provide that guarantee on its own: once loaded normally it writes its `anonymousId` cookie and delivers events to your data plane, and the `consent()` API filters which downstream *destinations* receive those events rather than preventing collection. Even RudderStack's pre-consent mode defaults to `events.delivery: 'immediate'`, which still sends pre-decision events. "Loaded but consent-filtered" is still collection, so c15t treats blocking the load as the only default that reliably honors a missing or denied `measurement` consent.
|
|
176
|
+
|
|
177
|
+
RudderStack v3 does offer a pre-consent mode (`preConsent` load options with storage disabled and buffered delivery) designed for CMP integrations, which allows a GTM-style flow. c15t supports it as an explicit opt-in — see below. It is not the default because it runs vendor code before consent and depends on vendor-side configuration (consent IDs on every destination) that c15t cannot verify from the browser.
|
|
178
|
+
|
|
179
|
+
The same reasoning applies to the other customer-data-platform helpers (Segment, Hightouch): their consent surfaces are destination filters, not collection gates, so those helpers block the load too.
|
|
180
|
+
|
|
181
|
+
### Opt-in: pre-consent mode with consent ID mapping
|
|
182
|
+
|
|
183
|
+
Pass `consentManagement` to make c15t the consent provider for RudderStack's pre-consent flow:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { rudderstack } from '@c15t/scripts/rudderstack';
|
|
187
|
+
|
|
188
|
+
rudderstack({
|
|
189
|
+
writeKey: 'WRITE_KEY',
|
|
190
|
+
dataPlaneUrl: 'https://example.dataplane.rudderstack.com',
|
|
191
|
+
consentManagement: {
|
|
192
|
+
// c15t category → RudderStack consent IDs (from your destination settings)
|
|
193
|
+
mapping: {
|
|
194
|
+
measurement: ['product-analytics'],
|
|
195
|
+
marketing: ['ad-destinations'],
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
In this mode:
|
|
202
|
+
|
|
203
|
+
* The SDK loads immediately for every visitor, but **inert**: `preConsent` is enabled with storage strategy `none` (no cookies, no localStorage) and buffered event delivery — nothing reaches your data plane before a consent decision.
|
|
204
|
+
* On every consent decision and change, c15t calls `rudderanalytics.consent()` with `allowedConsentIds`/`deniedConsentIds` partitioned from your mapping. The initial signal is queued before the SDK loads, so consent state is known the moment the SDK initializes.
|
|
205
|
+
* Consent revocation re-signals with the denied IDs instead of unloading the script.
|
|
206
|
+
|
|
207
|
+
**Event attribution.** This is the reason to opt in: events fired before the user interacts with the consent banner (the initial `page()` call, early product events) are buffered and delivered once consent is granted, so consenting users keep their full journey. In the default blocked-load mode those pre-consent events are simply lost. If you want session stitching across the consent boundary as well, pass your own `preConsent` in `loadOptions` with storage strategy `'session'` — c15t keeps your storage choice but always forces `preConsent.enabled`, buffered event delivery, and the `custom` consent provider, since any of those falling back to SDK defaults would leak pre-consent events.
|
|
208
|
+
|
|
209
|
+
**Requirements and caveats:**
|
|
210
|
+
|
|
211
|
+
* Every destination in your RudderStack workspace must be assigned the consent IDs used in the mapping. Destinations without consent IDs receive events regardless of consent — that is RudderStack behavior c15t cannot detect or prevent from the browser.
|
|
212
|
+
* Users who never consent have their buffered events discarded; nothing is persisted for them.
|
|
213
|
+
* The daily [script vendor monitor](https://github.com/c15t/c15t/issues/899) probes this mode against the live SDK: it loads RudderStack with denied consent in a real browser and asserts zero data plane requests and zero `rl_*` storage, so a vendor-side change to pre-consent semantics is caught automatically.
|
|
214
|
+
|
|
215
|
+
### Choosing a consent model for CDPs
|
|
216
|
+
|
|
217
|
+
* **Default (blocked load)** — strictest interpretation of consent; no vendor code runs pre-consent. Pre-consent events are lost. Right when compliance posture outweighs attribution.
|
|
218
|
+
* **Pre-consent mode (`consentManagement`)** — vendor-sanctioned CMP flow; pre-consent events are buffered and attributed for consenting users. Requires disciplined destination consent-ID configuration and accepts vendor code running before consent, with the live monitor verifying its inertness daily.
|
|
219
|
+
|
|
220
|
+
## Tracking events in your app
|
|
221
|
+
|
|
222
|
+
c15t gates the RudderStack browser SDK from loading until `measurement` consent is granted. Your application code that calls RudderStack's runtime API (`window.rudderanalytics.track`, `identify`, etc.) is **not** automatically gated - `window.rudderanalytics` does not exist until the script is loaded, so unguarded calls before consent throw.
|
|
223
|
+
|
|
224
|
+
Guard event calls by checking consent state. From React:
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
import { useCallback } from 'react';
|
|
228
|
+
import { useConsentManager } from '@c15t/react';
|
|
229
|
+
|
|
230
|
+
function SignupExample() {
|
|
231
|
+
const { has } = useConsentManager();
|
|
232
|
+
|
|
233
|
+
const trackSignup = useCallback(() => {
|
|
234
|
+
if (has('measurement')) {
|
|
235
|
+
window.rudderanalytics?.track('Signup Completed', { plan: 'pro' });
|
|
236
|
+
}
|
|
237
|
+
}, [has]);
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
From plain JavaScript:
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
import { getOrCreateConsentRuntime } from 'c15t';
|
|
245
|
+
|
|
246
|
+
const { consentStore } = getOrCreateConsentRuntime();
|
|
247
|
+
|
|
248
|
+
if (consentStore.getState().has('measurement')) {
|
|
249
|
+
window.rudderanalytics?.track('Signup Completed', { plan: 'pro' });
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Types
|
|
254
|
+
|
|
255
|
+
### RudderStackOptions
|
|
256
|
+
|
|
257
|
+
|Property|Value|
|
|
258
|
+
|:--|:--|
|
|
259
|
+
|Type Name|\`RudderStackOptions\`|
|
|
260
|
+
|Source Path|\`./packages/scripts/src/vendors/analytics/rudderstack.ts\`|
|
|
261
|
+
|
|
262
|
+
\*ExtractedTypeTable: Could not extract "RudderStackOptions" from "./packages/scripts/src/vendors/analytics/rudderstack.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
|
|
263
|
+
|
|
264
|
+
### Script
|
|
265
|
+
|
|
266
|
+
|Property|Value|
|
|
267
|
+
|:--|:--|
|
|
268
|
+
|Type Name|\`Script\`|
|
|
269
|
+
|Source Path|\`./packages/core/src/libs/script-loader/types.ts\`|
|
|
270
|
+
|
|
271
|
+
\*ExtractedTypeTable: Could not extract "Script" from "./packages/core/src/libs/script-loader/types.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Rybbit Analytics
|
|
3
|
+
description: Privacy-friendly analytics with script-tag configuration via
|
|
4
|
+
Rybbit's data attributes.
|
|
5
|
+
group: integrations
|
|
6
|
+
icon: rybbit-analytics
|
|
7
|
+
---
|
|
8
|
+
Rybbit Analytics loads through `@c15t/scripts` and configures tracking behavior via `data-*` attributes on the script element.
|
|
9
|
+
|
|
10
|
+
## Integrate with c15t
|
|
11
|
+
|
|
12
|
+
**React**
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { type ReactNode } from 'react';
|
|
16
|
+
import { ConsentManagerProvider } from '@c15t/react';
|
|
17
|
+
import { rybbitAnalytics } from '@c15t/scripts/rybbit-analytics';
|
|
18
|
+
|
|
19
|
+
const scripts = [rybbitAnalytics({ siteId: 'rybbit-123' })];
|
|
20
|
+
|
|
21
|
+
export function ConsentProvider({ children }: { children: ReactNode }) {
|
|
22
|
+
return (
|
|
23
|
+
<ConsentManagerProvider
|
|
24
|
+
options={{
|
|
25
|
+
mode: 'hosted',
|
|
26
|
+
backendURL: 'https://your-instance.c15t.dev',
|
|
27
|
+
scripts,
|
|
28
|
+
}}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
</ConsentManagerProvider>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Next.js**
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
'use client';
|
|
40
|
+
|
|
41
|
+
import { type ReactNode } from 'react';
|
|
42
|
+
import { ConsentManagerProvider } from '@c15t/nextjs';
|
|
43
|
+
import { rybbitAnalytics } from '@c15t/scripts/rybbit-analytics';
|
|
44
|
+
|
|
45
|
+
const scripts = [rybbitAnalytics({ siteId: 'rybbit-123' })];
|
|
46
|
+
|
|
47
|
+
export function ConsentProvider({ children }: { children: ReactNode }) {
|
|
48
|
+
return (
|
|
49
|
+
<ConsentManagerProvider
|
|
50
|
+
options={{
|
|
51
|
+
mode: 'hosted',
|
|
52
|
+
backendURL: '/api/c15t',
|
|
53
|
+
scripts,
|
|
54
|
+
}}
|
|
55
|
+
>
|
|
56
|
+
{children}
|
|
57
|
+
</ConsentManagerProvider>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**JavaScript**
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { getOrCreateConsentRuntime } from 'c15t';
|
|
66
|
+
import { rybbitAnalytics } from '@c15t/scripts/rybbit-analytics';
|
|
67
|
+
|
|
68
|
+
getOrCreateConsentRuntime({
|
|
69
|
+
mode: 'hosted',
|
|
70
|
+
backendURL: 'https://your-instance.c15t.dev',
|
|
71
|
+
scripts: [rybbitAnalytics({ siteId: 'rybbit-123' })],
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## How c15t loads it
|
|
76
|
+
|
|
77
|
+
* **Category:** `measurement` (Analytics)
|
|
78
|
+
* **Loads when:** measurement consent is granted
|
|
79
|
+
* **On revocation:** unloaded - c15t removes the script from the DOM and stops network activity until consent is granted again.
|
|
80
|
+
|
|
81
|
+
To use a custom analytics host:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
rybbitAnalytics({
|
|
85
|
+
siteId: 'rybbit-123',
|
|
86
|
+
analyticsHost: 'https://analytics.example.com',
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Tracking events in your app
|
|
91
|
+
|
|
92
|
+
c15t gates the Rybbit script from loading until `measurement` consent is granted. Your application code that calls Rybbit's runtime API (`window.rybbit`) is **not** automatically gated - `window.rybbit` does not exist until the script is loaded, so unguarded calls before consent throw.
|
|
93
|
+
|
|
94
|
+
Guard event calls by checking consent state. From React:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import { useCallback } from 'react';
|
|
98
|
+
import { useConsentManager } from '@c15t/react';
|
|
99
|
+
|
|
100
|
+
export default function SignupExample() {
|
|
101
|
+
const { has } = useConsentManager();
|
|
102
|
+
|
|
103
|
+
const trackSignup = useCallback(() => {
|
|
104
|
+
if (has('measurement')) {
|
|
105
|
+
window.rybbit?.event('signup');
|
|
106
|
+
}
|
|
107
|
+
}, [has]);
|
|
108
|
+
|
|
109
|
+
return <button onClick={trackSignup}>Sign up</button>;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
From plain JavaScript:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { getOrCreateConsentRuntime } from 'c15t';
|
|
117
|
+
|
|
118
|
+
const { consentStore } = getOrCreateConsentRuntime();
|
|
119
|
+
|
|
120
|
+
if (consentStore.getState().has('measurement')) {
|
|
121
|
+
window.rybbit?.event('signup');
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Types
|
|
126
|
+
|
|
127
|
+
### RybbitAnalyticsOptions
|
|
128
|
+
|
|
129
|
+
|Property|Value|
|
|
130
|
+
|:--|:--|
|
|
131
|
+
|Type Name|\`RybbitAnalyticsOptions\`|
|
|
132
|
+
|Source Path|\`./packages/scripts/src/vendors/analytics/rybbit-analytics.ts\`|
|
|
133
|
+
|
|
134
|
+
\*ExtractedTypeTable: Could not extract "RybbitAnalyticsOptions" from "./packages/scripts/src/vendors/analytics/rybbit-analytics.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
|
|
135
|
+
|
|
136
|
+
### Script
|
|
137
|
+
|
|
138
|
+
|Property|Value|
|
|
139
|
+
|:--|:--|
|
|
140
|
+
|Type Name|\`Script\`|
|
|
141
|
+
|Source Path|\`./packages/core/src/libs/script-loader/types.ts\`|
|
|
142
|
+
|
|
143
|
+
\*ExtractedTypeTable: Could not extract "Script" from "./packages/core/src/libs/script-loader/types.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
|