@c15t/scripts 3.0.0-alpha.0 → 3.0.0-alpha.2

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.
Files changed (88) hide show
  1. package/AGENTS.md +7 -0
  2. package/README.md +4 -3
  3. package/dist/e2e-test-utils.js +5 -3
  4. package/dist/engine/runtime.js +14 -3
  5. package/dist/events.js +218 -0
  6. package/dist/registry.js +40 -0
  7. package/dist/vendors/ads-and-pixels/pinterest-tag.js +123 -0
  8. package/dist/vendors/analytics/google-tag.js +14 -2
  9. package/dist/vendors/analytics/microsoft-clarity.js +4 -1
  10. package/dist/vendors/analytics/one-dollar-stats.js +30 -0
  11. package/dist/vendors/analytics/segment.js +10 -1
  12. package/dist/vendors/functional/front-chat.js +64 -0
  13. package/dist/vendors/tag-managers/cloudflare-zaraz.js +98 -0
  14. package/dist/vendors/tag-managers/google-tag-manager.js +17 -3
  15. package/dist-types/__tests__/helpers.d.ts +2 -2
  16. package/dist-types/engine/compile.d.ts +1 -1
  17. package/dist-types/engine/runtime.d.ts +1 -1
  18. package/dist-types/events.d.ts +46 -0
  19. package/dist-types/registry.d.ts +36 -0
  20. package/dist-types/resolve.d.ts +1 -1
  21. package/dist-types/vendors/_shared/install-builders.d.ts +1 -1
  22. package/dist-types/vendors/ads-and-pixels/pinterest-tag.d.ts +295 -0
  23. package/dist-types/vendors/analytics/adobe-analytics.d.ts +1 -1
  24. package/dist-types/vendors/analytics/google-tag.d.ts +3 -1
  25. package/dist-types/vendors/analytics/matomo-analytics.d.ts +1 -1
  26. package/dist-types/vendors/analytics/one-dollar-stats.d.ts +39 -0
  27. package/dist-types/vendors/analytics/segment.d.ts +7 -1
  28. package/dist-types/vendors/functional/front-chat.d.ts +62 -0
  29. package/dist-types/vendors/tag-managers/cloudflare-zaraz.d.ts +39 -0
  30. package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +3 -1
  31. package/docs/README.md +7 -0
  32. package/docs/customization/overview.md +4 -3
  33. package/docs/customization/recipes.md +4 -2
  34. package/docs/customization/tokens.md +66 -3
  35. package/docs/frameworks/javascript/script-loader.md +53 -0
  36. package/docs/frameworks/next/script-loader.md +60 -12
  37. package/docs/frameworks/react/script-loader.md +14 -0
  38. package/docs/guides/consent-state.md +327 -0
  39. package/docs/guides/deployment-modes.md +12 -0
  40. package/docs/guides/shared-consent-controls.md +158 -0
  41. package/docs/integrations/adobe-analytics.md +1 -1
  42. package/docs/integrations/ahrefs-analytics.md +1 -1
  43. package/docs/integrations/amplitude.md +1 -1
  44. package/docs/integrations/building-integrations.md +5 -0
  45. package/docs/integrations/clear-on-revocation.md +167 -0
  46. package/docs/integrations/clearbit.md +1 -1
  47. package/docs/integrations/cloudflare-web-analytics.md +1 -1
  48. package/docs/integrations/cloudflare-zaraz.md +399 -0
  49. package/docs/integrations/crisp.md +1 -1
  50. package/docs/integrations/databuddy.md +1 -1
  51. package/docs/integrations/fathom-analytics.md +1 -1
  52. package/docs/integrations/front-chat.md +322 -0
  53. package/docs/integrations/google-maps.md +21 -21
  54. package/docs/integrations/google-tag-manager.md +1 -1
  55. package/docs/integrations/google-tag.md +1 -1
  56. package/docs/integrations/granular-consent.md +210 -0
  57. package/docs/integrations/heap.md +1 -1
  58. package/docs/integrations/hightouch.md +1 -1
  59. package/docs/integrations/hotjar.md +1 -1
  60. package/docs/integrations/intercom.md +1 -1
  61. package/docs/integrations/linkedin-insights.md +1 -1
  62. package/docs/integrations/logrocket.md +1 -1
  63. package/docs/integrations/matomo-analytics.md +1 -1
  64. package/docs/integrations/meta-pixel.md +1 -1
  65. package/docs/integrations/microsoft-clarity.md +1 -1
  66. package/docs/integrations/microsoft-uet.md +1 -1
  67. package/docs/integrations/mixpanel-analytics.md +1 -1
  68. package/docs/integrations/one-dollar-stats.md +305 -0
  69. package/docs/integrations/openai-pixel.md +1 -1
  70. package/docs/integrations/overview.md +22 -18
  71. package/docs/integrations/pinterest-tag.md +321 -0
  72. package/docs/integrations/pirsch.md +1 -1
  73. package/docs/integrations/plausible-analytics.md +1 -1
  74. package/docs/integrations/posthog.md +1 -1
  75. package/docs/integrations/promptwatch.md +1 -1
  76. package/docs/integrations/reddit-pixel.md +1 -1
  77. package/docs/integrations/rudderstack.md +1 -1
  78. package/docs/integrations/rybbit-analytics.md +1 -1
  79. package/docs/integrations/segment.md +1 -1
  80. package/docs/integrations/snapchat-pixel.md +1 -1
  81. package/docs/integrations/tiktok-pixel.md +1 -1
  82. package/docs/integrations/umami-analytics.md +1 -1
  83. package/docs/integrations/vercel-analytics.md +1 -1
  84. package/docs/integrations/x-pixel.md +1 -1
  85. package/docs/integrations/youtube.md +27 -22
  86. package/docs/upgrade-v3.md +176 -1
  87. package/package.json +30 -2
  88. package/readme.json +0 -19
package/AGENTS.md CHANGED
@@ -30,6 +30,7 @@ These docs describe v3. Start with Inth hosted setup, identify the framework, ro
30
30
  - [Understand consent state](./docs/guides/consent-state.md): Distinguish policy resolution, effective permissions, explicit choices, notices and privacy signals.
31
31
  - [Data fetching and transports](./docs/guides/data-fetching.md): Choose cached manifests, backend init or offline policy resolution, and understand where consent records are saved.
32
32
  - [Choose a deployment mode](./docs/guides/deployment-modes.md): Choose who runs your consent backend, then select manifest, init or offline resolution for your deployment.
33
+ - [Share consent controls across frameworks](./docs/guides/shared-consent-controls.md): Use the same c15t script lifecycle, external consent source, and event controls in every framework.
33
34
  - [Troubleshoot consent](./docs/guides/troubleshooting.md): Diagnose missing banners, early vendor requests, lost choices and hydration differences.
34
35
  - [Verify consent before shipping](./docs/guides/verify-consent.md): Test requests, policy resolution, persistence, navigation and preference changes in a production build.
35
36
 
@@ -47,14 +48,18 @@ These docs describe v3. Start with Inth hosted setup, identify the framework, ro
47
48
  - [Ahrefs Analytics](./docs/integrations/ahrefs-analytics.md): Configure Ahrefs Analytics with c15t v3, understand measurement permission and verify loading and revocation.
48
49
  - [Amplitude](./docs/integrations/amplitude.md): Configure Amplitude with c15t v3, understand measurement permission and verify loading and revocation.
49
50
  - [Custom integrations](./docs/integrations/building-integrations.md): Define loading, initialization and consent-change behavior for a vendor without a helper.
51
+ - [Clear on revocation](./docs/integrations/clear-on-revocation.md): Remove configured first-party cookies and Web Storage keys when their consent category is denied.
50
52
  - [Clearbit](./docs/integrations/clearbit.md): Configure Clearbit with c15t v3, understand marketing permission and verify loading and revocation.
51
53
  - [Cloudflare Web Analytics](./docs/integrations/cloudflare-web-analytics.md): Configure Cloudflare Web Analytics with c15t v3, understand measurement permission and verify loading and revocation.
54
+ - [Cloudflare Zaraz](./docs/integrations/cloudflare-zaraz.md): Synchronize c15t permissions with Zaraz purposes while Cloudflare manages your tools.
52
55
  - [Crisp](./docs/integrations/crisp.md): Configure Crisp with c15t v3, understand functionality permission and verify loading and revocation.
53
56
  - [Databuddy](./docs/integrations/databuddy.md): Configure Databuddy's initial and updated consent state with c15t v3.
54
57
  - [Fathom Analytics](./docs/integrations/fathom-analytics.md): Configure Fathom Analytics with c15t v3, understand measurement permission and verify loading and revocation.
58
+ - [Front Chat](./docs/integrations/front-chat.md): Load the Front Chat widget with functionality permission, forward CSP nonces and clear the session on revocation.
55
59
  - [Google Maps](./docs/integrations/google-maps.md): Prevent a map iframe from mounting before the required permission.
56
60
  - [Google Tag](./docs/integrations/google-tag.md): Configure gtag with c15t Consent Mode signals and understand its loading behavior.
57
61
  - [Google Tag Manager](./docs/integrations/google-tag-manager.md): Load GTM with c15t consent signals and verify the tags inside your container.
62
+ - [Granular consent](./docs/integrations/granular-consent.md): Let visitors grant a category and still turn one vendor off, without adopting IAB TCF.
58
63
  - [Heap](./docs/integrations/heap.md): Configure Heap with c15t v3, understand measurement permission and verify loading and revocation.
59
64
  - [Hightouch](./docs/integrations/hightouch.md): Configure Hightouch with c15t v3, understand measurement permission and verify loading and revocation.
60
65
  - [Hotjar](./docs/integrations/hotjar.md): Configure Hotjar with c15t v3, understand measurement permission and verify loading and revocation.
@@ -66,8 +71,10 @@ These docs describe v3. Start with Inth hosted setup, identify the framework, ro
66
71
  - [Microsoft Clarity](./docs/integrations/microsoft-clarity.md): Configure Microsoft Clarity with c15t v3, understand measurement permission and verify loading and revocation.
67
72
  - [Microsoft UET](./docs/integrations/microsoft-uet.md): Configure Microsoft UET with c15t v3, understand marketing permission and verify loading and revocation.
68
73
  - [Mixpanel](./docs/integrations/mixpanel-analytics.md): Configure Mixpanel with c15t v3, understand measurement permission and verify loading and revocation.
74
+ - [OneDollarStats](./docs/integrations/one-dollar-stats.md): Load the OneDollarStats tracker with measurement permission, forward its settings and verify loading and revocation.
69
75
  - [OpenAI Pixel](./docs/integrations/openai-pixel.md): Configure the OpenAI Measurement Pixel for ChatGPT Ads with c15t v3, manage marketing permission and verify conversion delivery.
70
76
  - [Overview](./docs/integrations/overview.md): Find all c15t integrations for analytics, tag managers, advertising, chat and embedded content.
77
+ - [Pinterest Tag](./docs/integrations/pinterest-tag.md): Configure the Pinterest Tag with c15t v3, track typed events and verify marketing permission, revocation and reload.
71
78
  - [Pirsch](./docs/integrations/pirsch.md): Configure Pirsch with c15t v3, understand measurement permission and verify loading and revocation.
72
79
  - [Plausible Analytics](./docs/integrations/plausible-analytics.md): Configure Plausible Analytics with c15t v3, understand measurement permission and verify loading and revocation.
73
80
  - [PostHog](./docs/integrations/posthog.md): Choose PostHog loading and cookieless behavior, configure the region, and synchronize v3 permissions.
package/README.md CHANGED
@@ -37,10 +37,11 @@ For further information, guides, and examples visit the [reference documentation
37
37
  ## Integrations
38
38
 
39
39
  - **Google Tag Manager**: Loads with Google Consent Mode v2 defaults set to denied; GTM-managed tags fire only once matching consent is granted ([guide](https://c15t.com/docs/integrations/google-tag-manager))
40
+ - **Cloudflare Zaraz**: Maps c15t effective permissions to Zaraz purpose IDs for tools managed in Cloudflare ([guide](https://c15t.com/docs/integrations/cloudflare-zaraz))
40
41
  - **Google Analytics 4 + Google Ads (gtag.js)**: Consent Mode v2 defaults and consent updates when users make a choice ([guide](https://c15t.com/docs/integrations/google-tag))
41
- - **Conversion pixels**: Meta Pixel, OpenAI Pixel, TikTok Pixel, LinkedIn Insights, Microsoft UET (Microsoft Ads), X Pixel, Reddit Pixel, Snapchat Pixel
42
- - **Analytics**: PostHog, Amplitude, Heap, Segment, RudderStack, Hightouch, Mixpanel, Microsoft Clarity, Hotjar, Plausible, Fathom, Matomo, Umami, Vercel Analytics
43
- - **Chat widgets**: Intercom, Crisp
42
+ - **Conversion pixels**: Meta Pixel, OpenAI Pixel, Pinterest Tag, TikTok Pixel, LinkedIn Insights, Microsoft UET (Microsoft Ads), X Pixel, Reddit Pixel, Snapchat Pixel
43
+ - **Analytics**: PostHog, Amplitude, Heap, Segment, RudderStack, Hightouch, Mixpanel, Microsoft Clarity, Hotjar, Plausible, Fathom, Matomo, Umami, Vercel Analytics, OneDollarStats
44
+ - **Chat widgets**: Intercom, Crisp, Front Chat
44
45
 
45
46
  ## Example
46
47
 
@@ -9,12 +9,13 @@ const e2e_test_utils_muteSubscription = function(source) {
9
9
  subscribe: ()=>()=>{}
10
10
  };
11
11
  };
12
- const e2e_test_utils_reconcileScripts = function(scripts, consents) {
12
+ const e2e_test_utils_reconcileScripts = function(scripts, consents, options = {}) {
13
13
  const before = loader ? loader.getLoadedScriptIds() : [];
14
14
  kernel.commands.save(consents);
15
15
  if (loader) loader.updateScripts(scripts);
16
16
  else loader = createScriptLoader({
17
17
  kernel: e2e_test_utils_muteSubscription(kernel),
18
+ nonce: options.nonce,
18
19
  scripts
19
20
  });
20
21
  const after = loader.getLoadedScriptIds();
@@ -23,8 +24,8 @@ const e2e_test_utils_reconcileScripts = function(scripts, consents) {
23
24
  unloaded: before.filter((id)=>!after.includes(id))
24
25
  };
25
26
  };
26
- const e2e_test_utils_loadScripts = function(scripts, consents) {
27
- return e2e_test_utils_reconcileScripts(scripts, consents).loaded;
27
+ const e2e_test_utils_loadScripts = function(scripts, consents, options = {}) {
28
+ return e2e_test_utils_reconcileScripts(scripts, consents, options).loaded;
28
29
  };
29
30
  const e2e_test_utils_updateScripts = function(scripts, consents) {
30
31
  return e2e_test_utils_reconcileScripts(scripts, consents);
@@ -110,6 +111,7 @@ const e2e_test_utils_resetVendorGlobals = function() {
110
111
  'pirschClearSession',
111
112
  'pirschInit',
112
113
  'pirschNotFound',
114
+ 'pintrk',
113
115
  'plausible',
114
116
  'posthog',
115
117
  'rdt',
@@ -292,6 +292,16 @@ const runtime_partitionConsentIds = function(mapping, consents) {
292
292
  deniedConsentIds
293
293
  };
294
294
  };
295
+ const ALL_DENIED = {
296
+ experience: false,
297
+ functionality: false,
298
+ marketing: false,
299
+ measurement: false,
300
+ necessary: true
301
+ };
302
+ const runtime_signalConsents = function(info) {
303
+ return info.vendor?.granted === false ? ALL_DENIED : info.consents;
304
+ };
295
305
  const runtime_getConsentSignalSteps = function(resolvedManifest, mode, consents) {
296
306
  if (!resolvedManifest.consentMapping || !resolvedManifest.consentSignal) return [];
297
307
  switch(resolvedManifest.consentSignal){
@@ -346,7 +356,8 @@ const runtime_resolvedManifestToScript = function(resolvedManifest) {
346
356
  defer: resolvedManifest.loadScript?.defer,
347
357
  id: resolvedManifest.vendor,
348
358
  persistAfterConsentRevoked: resolvedManifest.persistAfterConsentRevoked,
349
- src: resolvedManifest.loadScript?.src
359
+ src: resolvedManifest.loadScript?.src,
360
+ vendor: resolvedManifest.vendor
350
361
  };
351
362
  if (resolvedManifest.bootstrapSteps.length > 0 || resolvedManifest.setupSteps.length > 0 || resolvedManifest.onBeforeLoadGrantedSteps.length > 0 || resolvedManifest.onBeforeLoadDeniedSteps.length > 0 || hasConsentMapping) script.onBeforeLoad = (info)=>{
352
363
  const baseContext = {
@@ -359,7 +370,7 @@ const runtime_resolvedManifestToScript = function(resolvedManifest) {
359
370
  ...baseContext,
360
371
  phase: 'bootstrap'
361
372
  });
362
- runtime_executePhaseSteps(runtime_getConsentSignalSteps(resolvedManifest, 'default', info.consents), {
373
+ runtime_executePhaseSteps(runtime_getConsentSignalSteps(resolvedManifest, 'default', runtime_signalConsents(info)), {
363
374
  ...baseContext,
364
375
  phase: 'consent-default'
365
376
  });
@@ -415,7 +426,7 @@ const runtime_resolvedManifestToScript = function(resolvedManifest) {
415
426
  hasConsent: info.hasConsent,
416
427
  scriptId: resolvedManifest.vendor
417
428
  };
418
- runtime_executePhaseSteps(runtime_getConsentSignalSteps(resolvedManifest, 'update', info.consents), {
429
+ runtime_executePhaseSteps(runtime_getConsentSignalSteps(resolvedManifest, 'update', runtime_signalConsents(info)), {
419
430
  ...baseContext,
420
431
  phase: 'consent-update'
421
432
  });
package/dist/events.js ADDED
@@ -0,0 +1,218 @@
1
+ import { evaluateConsent, getEffectiveGateState } from "@c15t/core";
2
+ const createEventDispatcher = (options)=>{
3
+ let previousPath;
4
+ const globals = options.globals ?? ("u" < typeof window ? {} : window);
5
+ const call = (path, args)=>{
6
+ let owner = globals;
7
+ const keys = 'string' == typeof path ? path.split('.') : [
8
+ ...path
9
+ ];
10
+ const method = keys.pop();
11
+ for (const key of keys){
12
+ if (!owner || 'object' != typeof owner && 'function' != typeof owner) return;
13
+ owner = Reflect.get(owner, key);
14
+ }
15
+ if (!owner || !method || 'object' != typeof owner && 'function' != typeof owner) return;
16
+ const fn = Reflect.get(owner, method);
17
+ if ('function' == typeof fn) Reflect.apply(fn, owner, args);
18
+ };
19
+ const permitted = ()=>{
20
+ const snapshot = options.getSnapshot();
21
+ if (!getEffectiveGateState(snapshot).effectivePermissions.measurement) return [];
22
+ return options.scripts.filter((script)=>evaluateConsent(script, snapshot));
23
+ };
24
+ return {
25
+ pageview (path) {
26
+ const [next] = path.split('#');
27
+ const changed = void 0 !== previousPath && previousPath !== next;
28
+ previousPath = next;
29
+ if (!changed) return;
30
+ const sent = new Set();
31
+ for (const script of permitted()){
32
+ const vendor = script.vendor ?? script.id;
33
+ if (!(!vendor || sent.has(vendor)) && options.pageviews?.includes(vendor)) {
34
+ sent.add(vendor);
35
+ try {
36
+ if ('posthog' === vendor) call('posthog.capture', [
37
+ '$pageview'
38
+ ]);
39
+ if ('segment' === vendor) call('analytics.page', []);
40
+ if ('hightouch' === vendor) call('htevents.page', []);
41
+ } catch {}
42
+ }
43
+ }
44
+ },
45
+ track (event, properties = {}) {
46
+ const sent = new Set();
47
+ for (const script of permitted()){
48
+ const vendor = script.vendor ?? script.id;
49
+ if (!vendor || sent.has(vendor)) continue;
50
+ sent.add(vendor);
51
+ const props = {
52
+ ...properties
53
+ };
54
+ try {
55
+ switch(vendor){
56
+ case 'google-tag-manager':
57
+ call([
58
+ script.attributes?.['data-c15t-layer'] ?? 'dataLayer',
59
+ 'push'
60
+ ], [
61
+ {
62
+ ...props,
63
+ event
64
+ }
65
+ ]);
66
+ break;
67
+ case 'gtag':
68
+ call('gtag', [
69
+ 'event',
70
+ event,
71
+ props
72
+ ]);
73
+ break;
74
+ case 'posthog':
75
+ call('posthog.capture', [
76
+ event,
77
+ props
78
+ ]);
79
+ break;
80
+ case 'mixpanel':
81
+ case 'mixpanel-analytics':
82
+ call('mixpanel.track', [
83
+ event,
84
+ props
85
+ ]);
86
+ break;
87
+ case 'segment':
88
+ call('analytics.track', [
89
+ event,
90
+ props
91
+ ]);
92
+ break;
93
+ case 'hightouch':
94
+ call('htevents.track', [
95
+ event,
96
+ props
97
+ ]);
98
+ break;
99
+ case 'heap':
100
+ call('heap.track', [
101
+ event,
102
+ props
103
+ ]);
104
+ break;
105
+ case 'amplitude':
106
+ call('amplitude.track', [
107
+ event,
108
+ props
109
+ ]);
110
+ break;
111
+ case 'logrocket':
112
+ call('LogRocket.track', [
113
+ event,
114
+ props
115
+ ]);
116
+ break;
117
+ case 'adobe-analytics':
118
+ call('_satellite.track', [
119
+ event,
120
+ props
121
+ ]);
122
+ break;
123
+ case 'databuddy':
124
+ call('databuddy.track', [
125
+ event,
126
+ props
127
+ ]);
128
+ break;
129
+ case 'plausible-analytics':
130
+ call('plausible', [
131
+ event,
132
+ {
133
+ props
134
+ }
135
+ ]);
136
+ break;
137
+ case 'fathom-analytics':
138
+ call('fathom.trackEvent', [
139
+ event
140
+ ]);
141
+ break;
142
+ case 'pirsch':
143
+ call('pirsch', [
144
+ event,
145
+ {
146
+ meta: props
147
+ }
148
+ ]);
149
+ break;
150
+ case 'microsoft-clarity':
151
+ call('clarity', [
152
+ 'event',
153
+ event
154
+ ]);
155
+ break;
156
+ case 'hotjar':
157
+ call('hj', [
158
+ 'event',
159
+ event
160
+ ]);
161
+ break;
162
+ case 'vercel-analytics':
163
+ call('va', [
164
+ 'event',
165
+ {
166
+ data: props,
167
+ name: event
168
+ }
169
+ ]);
170
+ break;
171
+ case 'one-dollar-stats':
172
+ call('stonks.event', [
173
+ event,
174
+ Object.fromEntries(Object.entries(props).map(([key, value])=>[
175
+ key,
176
+ String(value)
177
+ ]))
178
+ ]);
179
+ break;
180
+ case 'umami':
181
+ case 'umami-analytics':
182
+ call('umami.track', [
183
+ event,
184
+ props
185
+ ]);
186
+ break;
187
+ case 'rybbit':
188
+ case 'rybbit-analytics':
189
+ call('rybbit.event', [
190
+ event,
191
+ props
192
+ ]);
193
+ break;
194
+ case 'rudderstack':
195
+ call('rudderanalytics.track', [
196
+ event,
197
+ props
198
+ ]);
199
+ break;
200
+ case 'matomo':
201
+ case 'matomo-analytics':
202
+ call('_paq.push', [
203
+ [
204
+ 'trackEvent',
205
+ 'custom',
206
+ event
207
+ ]
208
+ ]);
209
+ break;
210
+ default:
211
+ break;
212
+ }
213
+ } catch {}
214
+ }
215
+ }
216
+ };
217
+ };
218
+ export { createEventDispatcher };
package/dist/registry.js CHANGED
@@ -17,6 +17,16 @@ const BUILT_IN_INTEGRATION_CATEGORIES = [
17
17
  }
18
18
  ];
19
19
  const builtInScriptIntegrations = [
20
+ {
21
+ consentCategory: 'necessary',
22
+ docsSlug: 'cloudflare-zaraz',
23
+ hint: 'Consent bridge for tools managed by Zaraz',
24
+ integrationCategory: 'tag-manager',
25
+ key: 'cloudflareZaraz',
26
+ label: 'Cloudflare Zaraz',
27
+ packageSubpath: 'cloudflare-zaraz',
28
+ vendor: 'cloudflare-zaraz'
29
+ },
20
30
  {
21
31
  consentCategory: 'necessary',
22
32
  docsSlug: 'google-tag-manager',
@@ -137,6 +147,16 @@ const builtInScriptIntegrations = [
137
147
  packageSubpath: 'mixpanel-analytics',
138
148
  vendor: 'mixpanel-analytics'
139
149
  },
150
+ {
151
+ consentCategory: 'measurement',
152
+ docsSlug: 'one-dollar-stats',
153
+ hint: 'Website analytics with no API key',
154
+ integrationCategory: 'analytics',
155
+ key: 'oneDollarStats',
156
+ label: 'OneDollarStats',
157
+ packageSubpath: 'one-dollar-stats',
158
+ vendor: 'one-dollar-stats'
159
+ },
140
160
  {
141
161
  consentCategory: 'measurement',
142
162
  docsSlug: 'hotjar',
@@ -277,6 +297,16 @@ const builtInScriptIntegrations = [
277
297
  packageSubpath: 'crisp',
278
298
  vendor: 'crisp'
279
299
  },
300
+ {
301
+ consentCategory: 'functionality',
302
+ docsSlug: 'front-chat',
303
+ hint: 'Live chat widget',
304
+ integrationCategory: 'functional',
305
+ key: 'frontChat',
306
+ label: 'Front Chat',
307
+ packageSubpath: 'front-chat',
308
+ vendor: 'front-chat'
309
+ },
280
310
  {
281
311
  consentCategory: 'functionality',
282
312
  docsSlug: 'intercom',
@@ -307,6 +337,16 @@ const builtInScriptIntegrations = [
307
337
  packageSubpath: 'openai-pixel',
308
338
  vendor: 'openai-pixel'
309
339
  },
340
+ {
341
+ consentCategory: 'marketing',
342
+ docsSlug: 'pinterest-tag',
343
+ hint: 'Pinterest ads tracking',
344
+ integrationCategory: 'ads-and-pixels',
345
+ key: 'pinterestTag',
346
+ label: 'Pinterest Tag',
347
+ packageSubpath: 'pinterest-tag',
348
+ vendor: 'pinterest-tag'
349
+ },
310
350
  {
311
351
  consentCategory: 'marketing',
312
352
  docsSlug: 'reddit-pixel',
@@ -0,0 +1,123 @@
1
+ import { resolveManifest } from "../../resolve.js";
2
+ import { vendorManifestContract } from "../../types.js";
3
+ import { resolveScriptUrl } from "../_shared/script-url.js";
4
+ const pinterestTagManifest = {
5
+ ...vendorManifestContract,
6
+ bootstrap: [
7
+ {
8
+ ifUndefined: true,
9
+ name: 'pintrk',
10
+ properties: {
11
+ version: '3.0'
12
+ },
13
+ queue: {
14
+ property: 'queue'
15
+ },
16
+ queueFormat: 'array',
17
+ type: 'defineStubFunction'
18
+ }
19
+ ],
20
+ category: 'marketing',
21
+ install: [
22
+ {
23
+ args: [
24
+ 'load',
25
+ '{{tagId}}'
26
+ ],
27
+ global: 'pintrk',
28
+ type: 'callGlobal'
29
+ },
30
+ {
31
+ args: [
32
+ 'setconsent',
33
+ true
34
+ ],
35
+ global: 'pintrk',
36
+ type: 'callGlobal'
37
+ },
38
+ {
39
+ args: [
40
+ 'page'
41
+ ],
42
+ global: 'pintrk',
43
+ type: 'callGlobal'
44
+ },
45
+ {
46
+ async: true,
47
+ src: "{{scriptUrl}}",
48
+ type: 'loadScript'
49
+ }
50
+ ],
51
+ onConsentDenied: [
52
+ {
53
+ args: [
54
+ 'setconsent',
55
+ false
56
+ ],
57
+ global: 'pintrk',
58
+ type: 'callGlobal'
59
+ }
60
+ ],
61
+ onConsentGranted: [
62
+ {
63
+ args: [
64
+ 'setconsent',
65
+ true
66
+ ],
67
+ global: 'pintrk',
68
+ type: 'callGlobal'
69
+ }
70
+ ],
71
+ persistAfterConsentRevoked: true,
72
+ vendor: 'pinterest-tag'
73
+ };
74
+ const pinterest_tag_pinterestTag = function({ tagId, loadOptions, trackPageVisit = true, scriptUrl }) {
75
+ const loadArgs = [
76
+ 'load',
77
+ '{{tagId}}'
78
+ ];
79
+ if (void 0 !== loadOptions) loadArgs.push('{{loadOptions}}');
80
+ const install = [
81
+ {
82
+ args: loadArgs,
83
+ global: 'pintrk',
84
+ type: 'callGlobal'
85
+ },
86
+ {
87
+ args: [
88
+ 'setconsent',
89
+ true
90
+ ],
91
+ global: 'pintrk',
92
+ type: 'callGlobal'
93
+ }
94
+ ];
95
+ if (trackPageVisit) install.push({
96
+ args: [
97
+ 'page'
98
+ ],
99
+ global: 'pintrk',
100
+ type: 'callGlobal'
101
+ });
102
+ install.push({
103
+ async: true,
104
+ src: "{{scriptUrl}}",
105
+ type: 'loadScript'
106
+ });
107
+ const manifest = {
108
+ ...pinterestTagManifest,
109
+ install
110
+ };
111
+ return resolveManifest(manifest, {
112
+ loadOptions,
113
+ scriptUrl: resolveScriptUrl(scriptUrl, 'https://s.pinimg.com/ct/core.js'),
114
+ tagId
115
+ });
116
+ };
117
+ const pinterestTagEvent = (eventName, eventData, callback)=>{
118
+ if ("u" < typeof window || 'function' != typeof window.pintrk) return;
119
+ if (void 0 !== callback) return void window.pintrk('track', eventName, eventData ?? {}, callback);
120
+ if (void 0 === eventData) return void window.pintrk('track', eventName);
121
+ window.pintrk('track', eventName, eventData);
122
+ };
123
+ export { pinterestTagEvent, pinterestTagManifest, pinterest_tag_pinterestTag as pinterestTag };
@@ -47,10 +47,22 @@ const gtagManifest = {
47
47
  persistAfterConsentRevoked: true,
48
48
  vendor: 'gtag'
49
49
  };
50
- const google_tag_gtag = function({ id, category, consentMapping, script }) {
51
- const manifest = withOptionalConsentMapping(gtagManifest, consentMapping);
50
+ const google_tag_gtag = function({ id, config, category, consentMapping, script }) {
51
+ const base = void 0 === config ? gtagManifest : {
52
+ ...gtagManifest,
53
+ install: gtagManifest.install.map((step)=>'callGlobal' === step.type && 'config' === step.args[0] ? {
54
+ ...step,
55
+ args: [
56
+ 'config',
57
+ '{{id}}',
58
+ '{{config}}'
59
+ ]
60
+ } : step)
61
+ };
62
+ const manifest = withOptionalConsentMapping(base, consentMapping);
52
63
  const resolved = resolveManifest(manifest, {
53
64
  category,
65
+ config,
54
66
  id
55
67
  });
56
68
  if (!script) return resolved;
@@ -48,7 +48,10 @@ const microsoft_clarity_getClarityConsentPayload = function(consents, defaultCon
48
48
  return fallback;
49
49
  };
50
50
  const microsoft_clarity_syncClarityConsent = function(info, defaultConsent) {
51
- window.clarity?.('consentv2', microsoft_clarity_getClarityConsentPayload(info.consents, defaultConsent));
51
+ window.clarity?.('consentv2', info.vendor?.granted === false ? {
52
+ ad_Storage: 'denied',
53
+ analytics_Storage: 'denied'
54
+ } : microsoft_clarity_getClarityConsentPayload(info.consents, defaultConsent));
52
55
  };
53
56
  const clarityManifest = {
54
57
  ...vendorManifestContract,
@@ -0,0 +1,30 @@
1
+ import { resolveManifest } from "../../resolve.js";
2
+ import { vendorManifestContract } from "../../types.js";
3
+ const ONE_DOLLAR_STATS_SCRIPT_SRC = 'https://assets.onedollarstats.com/stonks.js';
4
+ const oneDollarStatsManifest = {
5
+ ...vendorManifestContract,
6
+ category: 'measurement',
7
+ install: [
8
+ {
9
+ defer: true,
10
+ src: ONE_DOLLAR_STATS_SCRIPT_SRC,
11
+ type: 'loadScript'
12
+ }
13
+ ],
14
+ vendor: 'one-dollar-stats'
15
+ };
16
+ const SETTING_NAME = /^[a-z][a-z0-9-]*$/u;
17
+ const one_dollar_stats_oneDollarStats = function(options = {}) {
18
+ if (void 0 !== options.hostname && ('string' != typeof options.hostname || !/^[\p{L}\p{N}-]+(?:\.[\p{L}\p{N}-]+)*(?::\d+)?$/u.test(options.hostname))) throw new Error('oneDollarStats: hostname must be a bare host name like docs.example.com, without a scheme, path, query, or fragment');
19
+ const attributes = {};
20
+ for (const [setting, value] of Object.entries(options))if (void 0 !== value) {
21
+ if (!SETTING_NAME.test(setting)) throw new Error(`oneDollarStats: ${setting} is not a valid setting name; use lowercase letters, digits and hyphens`);
22
+ if ('string' != typeof value) throw new Error(`oneDollarStats: ${setting} must be a string`);
23
+ if ('hash-routing' !== setting || 'false' !== value) attributes[`data-${setting}`] = value;
24
+ }
25
+ return {
26
+ ...resolveManifest(oneDollarStatsManifest),
27
+ attributes
28
+ };
29
+ };
30
+ export { ONE_DOLLAR_STATS_SCRIPT_SRC, oneDollarStatsManifest, one_dollar_stats_oneDollarStats as oneDollarStats };
@@ -25,6 +25,14 @@ const segmentManifest = {
25
25
  ],
26
26
  category: 'measurement',
27
27
  install: [
28
+ {
29
+ path: [
30
+ 'analytics',
31
+ '_loadOptions'
32
+ ],
33
+ type: 'setGlobalPath',
34
+ value: '{{loadOptions}}'
35
+ },
28
36
  {
29
37
  global: 'analytics',
30
38
  method: 'page',
@@ -38,7 +46,7 @@ const segmentManifest = {
38
46
  ],
39
47
  vendor: 'segment'
40
48
  };
41
- const segment_segment = function({ writeKey, trackPageView = true, scriptUrl }) {
49
+ const segment_segment = function({ writeKey, loadOptions = {}, trackPageView = true, scriptUrl }) {
42
50
  let normalizedWriteKey = '';
43
51
  if ('string' == typeof writeKey) normalizedWriteKey = writeKey.trim();
44
52
  if (0 === normalizedWriteKey.length) throw new Error('segment: missing or invalid writeKey');
@@ -50,6 +58,7 @@ const segment_segment = function({ writeKey, trackPageView = true, scriptUrl })
50
58
  install: segmentManifest.install.filter((step)=>!('callGlobal' === step.type && 'analytics' === step.global && 'page' === step.method))
51
59
  };
52
60
  return resolveManifest(manifest, {
61
+ loadOptions,
53
62
  scriptUrl: resolveScriptUrl(scriptUrl, defaultScriptUrl)
54
63
  });
55
64
  };