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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/AGENTS.md +129 -63
  2. package/README.md +8 -29
  3. package/SKILL.md +33 -0
  4. package/dist/adobe-analytics.js +2 -0
  5. package/dist/ahrefs-analytics.js +2 -0
  6. package/dist/amplitude.js +2 -0
  7. package/dist/clearbit.js +2 -0
  8. package/dist/cloudflare-web-analytics.js +2 -0
  9. package/dist/cloudflare-zaraz.js +2 -0
  10. package/dist/crisp.js +2 -0
  11. package/dist/databuddy.js +2 -0
  12. package/dist/e2e-test-utils.js +2 -139
  13. package/dist/engine/compile.js +2 -89
  14. package/dist/engine/runtime.js +2 -448
  15. package/dist/events.js +2 -218
  16. package/dist/fathom-analytics.js +2 -0
  17. package/dist/front-chat.js +2 -0
  18. package/dist/google-tag-manager.js +2 -0
  19. package/dist/google-tag.js +2 -0
  20. package/dist/heap.js +2 -0
  21. package/dist/hightouch.js +2 -0
  22. package/dist/hotjar.js +2 -0
  23. package/dist/intercom.js +2 -0
  24. package/dist/klaviyo.js +2 -0
  25. package/dist/linkedin-insights.js +2 -0
  26. package/dist/logrocket.js +2 -0
  27. package/dist/matomo-analytics.js +2 -0
  28. package/dist/meta-pixel.js +2 -0
  29. package/dist/microsoft-clarity.js +2 -0
  30. package/dist/microsoft-uet.js +2 -0
  31. package/dist/mixpanel-analytics.js +2 -0
  32. package/dist/one-dollar-stats.js +2 -0
  33. package/dist/openai-pixel.js +2 -0
  34. package/dist/pinterest-tag.js +2 -0
  35. package/dist/pirsch.js +2 -0
  36. package/dist/plausible-analytics.js +2 -0
  37. package/dist/posthog.js +2 -0
  38. package/dist/promptwatch.js +2 -0
  39. package/dist/reddit-pixel.js +2 -0
  40. package/dist/registry.js +2 -422
  41. package/dist/resolve.js +2 -33
  42. package/dist/rudderstack.js +2 -0
  43. package/dist/rybbit-analytics.js +2 -0
  44. package/dist/segment.js +2 -0
  45. package/dist/snapchat-pixel.js +2 -0
  46. package/dist/tiktok-pixel.js +2 -0
  47. package/dist/types.js +2 -16
  48. package/dist/umami-analytics.js +2 -0
  49. package/dist/vendors/_shared/attributes.js +2 -14
  50. package/dist/vendors/_shared/google-consent.js +2 -27
  51. package/dist/vendors/_shared/install-builders.js +2 -21
  52. package/dist/vendors/_shared/required-id.js +2 -0
  53. package/dist/vendors/_shared/script-url.js +2 -28
  54. package/dist/vendors/ads-and-pixels/linkedin-insights.js +2 -48
  55. package/dist/vendors/ads-and-pixels/meta-pixel.js +2 -153
  56. package/dist/vendors/ads-and-pixels/microsoft-uet.js +2 -110
  57. package/dist/vendors/ads-and-pixels/openai-pixel.js +2 -88
  58. package/dist/vendors/ads-and-pixels/pinterest-tag.js +2 -123
  59. package/dist/vendors/ads-and-pixels/reddit-pixel.js +2 -107
  60. package/dist/vendors/ads-and-pixels/snapchat-pixel.js +2 -87
  61. package/dist/vendors/ads-and-pixels/tiktok-pixel.js +2 -89
  62. package/dist/vendors/ads-and-pixels/x-pixel.js +2 -48
  63. package/dist/vendors/analytics/adobe-analytics.js +2 -49
  64. package/dist/vendors/analytics/ahrefs-analytics.js +2 -27
  65. package/dist/vendors/analytics/amplitude.js +2 -134
  66. package/dist/vendors/analytics/clearbit.js +2 -28
  67. package/dist/vendors/analytics/cloudflare-web-analytics.js +2 -32
  68. package/dist/vendors/analytics/databuddy.js +2 -103
  69. package/dist/vendors/analytics/fathom-analytics.js +2 -35
  70. package/dist/vendors/analytics/google-tag.js +2 -78
  71. package/dist/vendors/analytics/heap.js +2 -134
  72. package/dist/vendors/analytics/hightouch.js +2 -109
  73. package/dist/vendors/analytics/hotjar.js +2 -44
  74. package/dist/vendors/analytics/logrocket.js +2 -58
  75. package/dist/vendors/analytics/matomo-analytics.js +2 -191
  76. package/dist/vendors/analytics/microsoft-clarity.js +2 -100
  77. package/dist/vendors/analytics/mixpanel-analytics.js +2 -93
  78. package/dist/vendors/analytics/one-dollar-stats.js +2 -30
  79. package/dist/vendors/analytics/pirsch.js +2 -67
  80. package/dist/vendors/analytics/plausible-analytics.js +2 -81
  81. package/dist/vendors/analytics/posthog.js +2 -200
  82. package/dist/vendors/analytics/promptwatch.js +2 -29
  83. package/dist/vendors/analytics/rudderstack.js +2 -183
  84. package/dist/vendors/analytics/rybbit-analytics.js +2 -63
  85. package/dist/vendors/analytics/segment.js +2 -65
  86. package/dist/vendors/analytics/umami-analytics.js +2 -39
  87. package/dist/vendors/analytics/vercel-analytics.js +2 -53
  88. package/dist/vendors/email-and-sms/klaviyo.js +2 -0
  89. package/dist/vendors/functional/crisp.js +2 -100
  90. package/dist/vendors/functional/front-chat.js +2 -64
  91. package/dist/vendors/functional/intercom.js +2 -45
  92. package/dist/vendors/tag-managers/cloudflare-zaraz.js +2 -98
  93. package/dist/vendors/tag-managers/google-tag-manager.js +2 -73
  94. package/dist/vercel-analytics.js +2 -0
  95. package/dist/x-pixel.js +2 -0
  96. package/dist-types/adobe-analytics.d.ts +2 -0
  97. package/dist-types/ahrefs-analytics.d.ts +2 -0
  98. package/dist-types/amplitude.d.ts +2 -0
  99. package/dist-types/clearbit.d.ts +2 -0
  100. package/dist-types/cloudflare-web-analytics.d.ts +2 -0
  101. package/dist-types/cloudflare-zaraz.d.ts +2 -0
  102. package/dist-types/crisp.d.ts +2 -0
  103. package/dist-types/databuddy.d.ts +2 -0
  104. package/dist-types/e2e-test-utils.d.ts +2 -0
  105. package/dist-types/engine/compile.d.ts +2 -3
  106. package/dist-types/engine/runtime.d.ts +2 -3
  107. package/dist-types/events.d.ts +2 -46
  108. package/dist-types/fathom-analytics.d.ts +2 -0
  109. package/dist-types/front-chat.d.ts +2 -0
  110. package/dist-types/google-tag-manager.d.ts +2 -0
  111. package/dist-types/google-tag.d.ts +2 -0
  112. package/dist-types/heap.d.ts +2 -0
  113. package/dist-types/hightouch.d.ts +2 -0
  114. package/dist-types/hotjar.d.ts +2 -0
  115. package/dist-types/intercom.d.ts +2 -0
  116. package/dist-types/klaviyo.d.ts +2 -0
  117. package/dist-types/linkedin-insights.d.ts +2 -0
  118. package/dist-types/logrocket.d.ts +2 -0
  119. package/dist-types/matomo-analytics.d.ts +2 -0
  120. package/dist-types/meta-pixel.d.ts +2 -0
  121. package/dist-types/microsoft-clarity.d.ts +2 -0
  122. package/dist-types/microsoft-uet.d.ts +2 -0
  123. package/dist-types/mixpanel-analytics.d.ts +2 -0
  124. package/dist-types/one-dollar-stats.d.ts +2 -0
  125. package/dist-types/openai-pixel.d.ts +2 -0
  126. package/dist-types/pinterest-tag.d.ts +2 -0
  127. package/dist-types/pirsch.d.ts +2 -0
  128. package/dist-types/plausible-analytics.d.ts +2 -0
  129. package/dist-types/posthog.d.ts +2 -0
  130. package/dist-types/promptwatch.d.ts +2 -0
  131. package/dist-types/reddit-pixel.d.ts +2 -0
  132. package/dist-types/registry.d.ts +2 -485
  133. package/dist-types/resolve.d.ts +2 -9
  134. package/dist-types/rudderstack.d.ts +2 -0
  135. package/dist-types/rybbit-analytics.d.ts +2 -0
  136. package/dist-types/segment.d.ts +2 -0
  137. package/dist-types/snapchat-pixel.d.ts +2 -0
  138. package/dist-types/tiktok-pixel.d.ts +2 -0
  139. package/dist-types/types.d.ts +2 -314
  140. package/dist-types/umami-analytics.d.ts +2 -0
  141. package/dist-types/vendors/_shared/attributes.d.ts +2 -35
  142. package/dist-types/vendors/_shared/google-consent.d.ts +2 -47
  143. package/dist-types/vendors/_shared/install-builders.d.ts +2 -30
  144. package/dist-types/vendors/_shared/required-id.d.ts +2 -0
  145. package/dist-types/vendors/_shared/script-url.d.ts +2 -75
  146. package/dist-types/vendors/ads-and-pixels/linkedin-insights.d.ts +2 -92
  147. package/dist-types/vendors/ads-and-pixels/meta-pixel.d.ts +2 -289
  148. package/dist-types/vendors/ads-and-pixels/microsoft-uet.d.ts +2 -105
  149. package/dist-types/vendors/ads-and-pixels/openai-pixel.d.ts +2 -211
  150. package/dist-types/vendors/ads-and-pixels/pinterest-tag.d.ts +2 -295
  151. package/dist-types/vendors/ads-and-pixels/reddit-pixel.d.ts +2 -210
  152. package/dist-types/vendors/ads-and-pixels/snapchat-pixel.d.ts +2 -171
  153. package/dist-types/vendors/ads-and-pixels/tiktok-pixel.d.ts +2 -106
  154. package/dist-types/vendors/ads-and-pixels/x-pixel.d.ts +2 -183
  155. package/dist-types/vendors/analytics/adobe-analytics.d.ts +2 -75
  156. package/dist-types/vendors/analytics/ahrefs-analytics.d.ts +2 -62
  157. package/dist-types/vendors/analytics/amplitude.d.ts +2 -234
  158. package/dist-types/vendors/analytics/clearbit.d.ts +2 -60
  159. package/dist-types/vendors/analytics/cloudflare-web-analytics.d.ts +2 -67
  160. package/dist-types/vendors/analytics/databuddy.d.ts +2 -147
  161. package/dist-types/vendors/analytics/fathom-analytics.d.ts +2 -90
  162. package/dist-types/vendors/analytics/google-tag.d.ts +2 -95
  163. package/dist-types/vendors/analytics/heap.d.ts +2 -316
  164. package/dist-types/vendors/analytics/hightouch.d.ts +2 -285
  165. package/dist-types/vendors/analytics/hotjar.d.ts +2 -73
  166. package/dist-types/vendors/analytics/logrocket.d.ts +2 -101
  167. package/dist-types/vendors/analytics/matomo-analytics.d.ts +2 -41
  168. package/dist-types/vendors/analytics/microsoft-clarity.d.ts +2 -97
  169. package/dist-types/vendors/analytics/mixpanel-analytics.d.ts +2 -113
  170. package/dist-types/vendors/analytics/one-dollar-stats.d.ts +2 -39
  171. package/dist-types/vendors/analytics/pirsch.d.ts +2 -96
  172. package/dist-types/vendors/analytics/plausible-analytics.d.ts +2 -122
  173. package/dist-types/vendors/analytics/posthog.d.ts +2 -175
  174. package/dist-types/vendors/analytics/promptwatch.d.ts +2 -36
  175. package/dist-types/vendors/analytics/rudderstack.d.ts +2 -330
  176. package/dist-types/vendors/analytics/rybbit-analytics.d.ts +2 -82
  177. package/dist-types/vendors/analytics/segment.d.ts +2 -164
  178. package/dist-types/vendors/analytics/umami-analytics.d.ts +2 -93
  179. package/dist-types/vendors/analytics/vercel-analytics.d.ts +2 -66
  180. package/dist-types/vendors/email-and-sms/klaviyo.d.ts +2 -0
  181. package/dist-types/vendors/functional/crisp.d.ts +2 -78
  182. package/dist-types/vendors/functional/front-chat.d.ts +2 -62
  183. package/dist-types/vendors/functional/intercom.d.ts +2 -135
  184. package/dist-types/vendors/tag-managers/cloudflare-zaraz.d.ts +2 -39
  185. package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +2 -96
  186. package/dist-types/vercel-analytics.d.ts +2 -0
  187. package/dist-types/x-pixel.d.ts +2 -0
  188. package/docs/README.md +129 -63
  189. package/docs/assets/v3/bottom-bar.png +0 -0
  190. package/docs/assets/v3/brand-card.png +0 -0
  191. package/docs/assets/v3/brand-preferences.png +0 -0
  192. package/docs/assets/v3/choice-wall.png +0 -0
  193. package/docs/assets/v3/headless-bar-html.png +0 -0
  194. package/docs/assets/v3/headless-bar-mobile.png +0 -0
  195. package/docs/assets/v3/headless-bar.png +0 -0
  196. package/docs/assets/v3/slim-bar.png +0 -0
  197. package/docs/concepts/choose-your-setup.md +87 -0
  198. package/docs/concepts/consent-categories.md +84 -0
  199. package/docs/{guides → concepts}/consent-state.md +89 -105
  200. package/docs/{guides → concepts}/data-fetching.md +31 -27
  201. package/docs/concepts/how-consent-works.md +123 -0
  202. package/docs/concepts/policies.md +71 -0
  203. package/docs/customization/class-names.md +202 -0
  204. package/docs/customization/dark-mode.md +157 -0
  205. package/docs/customization/motion.md +119 -0
  206. package/docs/customization/overview.md +67 -34
  207. package/docs/customization/recipes.md +839 -49
  208. package/docs/customization/slots.md +216 -35
  209. package/docs/customization/stylesheets.md +147 -0
  210. package/docs/customization/tailwind.md +842 -0
  211. package/docs/customization/tokens.md +163 -96
  212. package/docs/customization/translations.md +60 -3
  213. package/docs/frameworks/astro/embeds.md +160 -0
  214. package/docs/frameworks/astro/network-blocker.md +86 -0
  215. package/docs/frameworks/astro/scripts.md +155 -0
  216. package/docs/frameworks/html/embeds.md +142 -0
  217. package/docs/frameworks/html/network-blocker.md +105 -0
  218. package/docs/frameworks/html/scripts.md +164 -0
  219. package/docs/frameworks/javascript/scripts.md +137 -0
  220. package/docs/frameworks/next/embeds.md +90 -0
  221. package/docs/frameworks/next/network-blocker.md +153 -0
  222. package/docs/frameworks/next/scripts.md +196 -0
  223. package/docs/frameworks/nuxt/embeds.md +81 -0
  224. package/docs/frameworks/nuxt/network-blocker.md +97 -0
  225. package/docs/frameworks/nuxt/scripts.md +89 -0
  226. package/docs/frameworks/react/embeds.md +89 -0
  227. package/docs/frameworks/react/network-blocker.md +140 -0
  228. package/docs/frameworks/react/scripts.md +115 -0
  229. package/docs/frameworks/svelte/embeds.md +96 -0
  230. package/docs/frameworks/svelte/network-blocker.md +141 -0
  231. package/docs/frameworks/svelte/scripts.md +144 -0
  232. package/docs/frameworks/sveltekit/embeds.md +103 -0
  233. package/docs/frameworks/sveltekit/network-blocker.md +159 -0
  234. package/docs/frameworks/sveltekit/scripts.md +172 -0
  235. package/docs/frameworks/tanstack-start/embeds.md +96 -0
  236. package/docs/frameworks/tanstack-start/network-blocker.md +145 -0
  237. package/docs/frameworks/tanstack-start/scripts.md +103 -0
  238. package/docs/frameworks/vue/embeds.md +84 -0
  239. package/docs/frameworks/vue/network-blocker.md +99 -0
  240. package/docs/frameworks/vue/scripts.md +93 -0
  241. package/docs/guides/banner-experiments.md +654 -0
  242. package/docs/guides/troubleshooting.md +120 -47
  243. package/docs/guides/verify-consent.md +81 -49
  244. package/docs/integrations/adobe-analytics.md +167 -159
  245. package/docs/integrations/ahrefs-analytics.md +152 -154
  246. package/docs/integrations/amplitude.md +162 -156
  247. package/docs/integrations/building-integrations.md +136 -37
  248. package/docs/integrations/clearbit.md +154 -154
  249. package/docs/integrations/cloudflare-web-analytics.md +156 -156
  250. package/docs/integrations/cloudflare-zaraz.md +209 -261
  251. package/docs/integrations/crisp.md +164 -158
  252. package/docs/integrations/databuddy.md +157 -173
  253. package/docs/integrations/fathom-analytics.md +158 -156
  254. package/docs/integrations/front-chat.md +167 -167
  255. package/docs/integrations/google-maps.md +118 -83
  256. package/docs/integrations/google-tag-manager.md +178 -163
  257. package/docs/integrations/google-tag.md +163 -160
  258. package/docs/integrations/heap.md +163 -155
  259. package/docs/integrations/hightouch.md +161 -157
  260. package/docs/integrations/hotjar.md +159 -155
  261. package/docs/integrations/intercom.md +183 -153
  262. package/docs/integrations/klaviyo.md +486 -0
  263. package/docs/integrations/linkedin-insights.md +174 -150
  264. package/docs/integrations/logrocket.md +160 -156
  265. package/docs/integrations/matomo-analytics.md +188 -178
  266. package/docs/integrations/meta-pixel.md +188 -150
  267. package/docs/integrations/microsoft-clarity.md +163 -155
  268. package/docs/integrations/microsoft-uet.md +148 -154
  269. package/docs/integrations/mixpanel-analytics.md +155 -160
  270. package/docs/integrations/one-dollar-stats.md +166 -165
  271. package/docs/integrations/openai-pixel.md +204 -301
  272. package/docs/integrations/overview.md +137 -80
  273. package/docs/integrations/pinterest-tag.md +191 -183
  274. package/docs/integrations/pirsch.md +169 -159
  275. package/docs/integrations/plausible-analytics.md +172 -158
  276. package/docs/integrations/posthog.md +313 -240
  277. package/docs/integrations/promptwatch.md +154 -154
  278. package/docs/integrations/reddit-pixel.md +185 -157
  279. package/docs/integrations/rudderstack.md +201 -186
  280. package/docs/integrations/rybbit-analytics.md +171 -160
  281. package/docs/integrations/segment.md +182 -154
  282. package/docs/integrations/snapchat-pixel.md +186 -156
  283. package/docs/integrations/tiktok-pixel.md +171 -150
  284. package/docs/integrations/umami-analytics.md +163 -158
  285. package/docs/integrations/vercel-analytics.md +166 -157
  286. package/docs/integrations/x-pixel.md +176 -150
  287. package/docs/integrations/youtube.md +121 -86
  288. package/docs/upgrade-v3.md +496 -467
  289. package/package.json +10 -257
  290. package/dist-types/__tests__/helpers.d.ts +0 -141
  291. package/docs/assets/v3/brand-bar.png +0 -0
  292. package/docs/assets/v3/mobile-card.png +0 -0
  293. package/docs/assets/v3/preferences.png +0 -0
  294. package/docs/frameworks/javascript/script-loader.md +0 -100
  295. package/docs/frameworks/next/script-loader.md +0 -216
  296. package/docs/frameworks/react/script-loader.md +0 -69
  297. package/docs/guides/deployment-modes.md +0 -75
  298. package/docs/guides/shared-consent-controls.md +0 -158
  299. package/docs/integrations/clear-on-revocation.md +0 -167
  300. package/docs/integrations/granular-consent.md +0 -210
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  title: Google Maps
3
- description: Prevent a map iframe from mounting before the required permission.
3
+ description: Gate a Google Maps iframe embed with c15t v3 so the map loads only
4
+ after the visitor allows its consent category, in Next.js, TanStack Start,
5
+ React, Nuxt, Vue, Astro, Svelte, SvelteKit, HTML or JavaScript.
6
+ icon: google-maps
4
7
  group: integrations
5
8
  ---
6
9
 
@@ -11,7 +14,8 @@ application; this example uses functionality permission.
11
14
 
12
15
  ```ts title="src/embed-config.ts"
13
16
  export const embedCategory = 'functionality' as const;
14
- export const embedURL = 'https://www.google.com/maps/embed?pb=YOUR_EMBED_PARAMETERS';
17
+ export const embedURL =
18
+ 'https://www.google.com/maps/embed?pb=YOUR_EMBED_PARAMETERS';
15
19
  export const embedTitle = 'Map showing our office location';
16
20
  export const embedAspectRatio = '4 / 3';
17
21
  ```
@@ -107,64 +111,66 @@ on revocation. Keep your existing consent styles and preferences dialog.
107
111
 
108
112
  **Nuxt**
109
113
 
110
- Use the reactive snapshot from the existing consent runtime. The Nuxt module auto-imports the consent composables.
114
+ The Nuxt module registers `ConsentGate` and `ConsentPreferencesLink`, so
115
+ this component imports only the embed configuration.
111
116
 
112
117
  ```vue title="app/components/ConsentEmbed.vue"
113
118
  <script setup lang="ts">
114
119
  import { embedCategory, embedURL, embedTitle, embedAspectRatio } from '../../src/embed-config';
115
-
116
- const snapshot = useConsentSnapshot();
117
- const activeUI = useConsentActiveUI();
118
120
  </script>
119
121
 
120
122
  <template>
121
- <iframe
122
- v-if="snapshot.effectivePermissions[embedCategory]"
123
- :src="embedURL"
124
- :title="embedTitle"
125
- loading="lazy"
126
- allowfullscreen
127
- :style="{ width: '100%', aspectRatio: embedAspectRatio, minHeight: '200px', border: 0 }"
128
- />
129
- <button v-else type="button" @click="activeUI = 'manager'">
130
- Open privacy settings to view this content
131
- </button>
123
+ <ConsentGate :category="embedCategory">
124
+ <iframe
125
+ :src="embedURL"
126
+ :title="embedTitle"
127
+ loading="lazy"
128
+ allowfullscreen
129
+ :style="{ width: '100%', aspectRatio: embedAspectRatio, minHeight: '200px', border: 0 }"
130
+ />
131
+ <template #placeholder>
132
+ <p>Allow {{ embedCategory }} to load this content.</p>
133
+ <ConsentPreferencesLink>Open privacy settings</ConsentPreferencesLink>
134
+ </template>
135
+ </ConsentGate>
132
136
  </template>
133
137
  ```
134
138
 
135
- Use `v-if` so a denied iframe is removed from the DOM. Hiding an existing
136
- iframe with `v-show` or CSS does not prevent its requests.
139
+ `ConsentGate` keeps the iframe out of the server HTML and the DOM while
140
+ permission is denied, and removes it on revocation. See
141
+ [Nuxt scripts and embeds](../frameworks/nuxt/scripts.md).
137
142
 
138
143
  **Vue**
139
144
 
140
- Use the reactive snapshot from the existing consent runtime. The c15t Vue plugin must already be installed on this app.
145
+ Render this component inside the app that installed the c15t Vue plugin.
141
146
 
142
147
  ```vue title="src/ConsentEmbed.vue"
143
148
  <script setup lang="ts">
144
- import { useConsentSnapshot, useConsentActiveUI } from 'c15t/vue/vue-plugin';
149
+ import ConsentGate from 'c15t/vue/runtime/components/consent-gate.vue';
150
+ import ConsentPreferencesLink from 'c15t/vue/runtime/components/consent-preferences-link.vue';
145
151
  import { embedCategory, embedURL, embedTitle, embedAspectRatio } from './embed-config';
146
-
147
- const snapshot = useConsentSnapshot();
148
- const activeUI = useConsentActiveUI();
149
152
  </script>
150
153
 
151
154
  <template>
152
- <iframe
153
- v-if="snapshot.effectivePermissions[embedCategory]"
154
- :src="embedURL"
155
- :title="embedTitle"
156
- loading="lazy"
157
- allowfullscreen
158
- :style="{ width: '100%', aspectRatio: embedAspectRatio, minHeight: '200px', border: 0 }"
159
- />
160
- <button v-else type="button" @click="activeUI = 'manager'">
161
- Open privacy settings to view this content
162
- </button>
155
+ <ConsentGate :category="embedCategory">
156
+ <iframe
157
+ :src="embedURL"
158
+ :title="embedTitle"
159
+ loading="lazy"
160
+ allowfullscreen
161
+ :style="{ width: '100%', aspectRatio: embedAspectRatio, minHeight: '200px', border: 0 }"
162
+ />
163
+ <template #placeholder>
164
+ <p>Allow {{ embedCategory }} to load this content.</p>
165
+ <ConsentPreferencesLink>Open privacy settings</ConsentPreferencesLink>
166
+ </template>
167
+ </ConsentGate>
163
168
  </template>
164
169
  ```
165
170
 
166
- Use `v-if` so a denied iframe is removed from the DOM. Hiding an existing
167
- iframe with `v-show` or CSS does not prevent its requests.
171
+ `ConsentGate` keeps the iframe out of the DOM while permission is denied,
172
+ and removes it on revocation. See
173
+ [Vue scripts and embeds](../frameworks/vue/scripts.md).
168
174
 
169
175
  **Astro**
170
176
 
@@ -273,16 +279,37 @@ The Svelte `ConsentGate` waits until the browser is mounted and the category is
273
279
  allowed. Its default placeholder opens preferences. Revocation removes the
274
280
  iframe.
275
281
 
282
+ **HTML**
283
+
284
+ The c15t script tag gates iframes that name a category. Put the embed's URL
285
+ in `data-src` instead of `src`, using the values from the configuration on
286
+ this page:
287
+
288
+ ```html
289
+ <iframe
290
+ data-src="https://www.youtube-nocookie.com/embed/VIDEO_ID?playsinline=1"
291
+ data-category="measurement"
292
+ title="Product video"
293
+ loading="lazy"
294
+ allowfullscreen
295
+ ></iframe>
296
+ ```
297
+
298
+ c15t sets `src` once the category is allowed and removes it on revocation.
299
+ Without `src` the iframe loads nothing, so hide it with CSS and show a link
300
+ to `#c15t-preferences` in its place. See
301
+ [HTML embeds](../frameworks/html/embeds.md).
302
+
276
303
  **JavaScript**
277
304
 
278
- Use the shared browser helper below with your existing kernel. Put an
305
+ Use the shared browser helper below with your existing client. Put an
279
306
  empty container where the embed should appear:
280
307
 
281
308
  ```html
282
309
  <div id="consent-embed"></div>
283
310
  ```
284
311
 
285
- In your browser entry point, after creating the kernel:
312
+ In your browser entry point, after `init()`:
286
313
 
287
314
  ```ts
288
315
  import { mountConsentEmbed } from './consent-embed';
@@ -290,13 +317,16 @@ import { mountConsentEmbed } from './consent-embed';
290
317
  const container = document.querySelector<HTMLElement>('#consent-embed');
291
318
  if (!container) throw new Error('Missing consent embed container');
292
319
 
293
- const disposeEmbed = mountConsentEmbed(container, kernel, openPreferences);
320
+ const disposeEmbed = mountConsentEmbed(container, consent.kernel, () =>
321
+ consent.openDialog(),
322
+ );
294
323
  ```
295
324
 
296
- `kernel` is the instance from your quickstart. `openPreferences` is your
297
- application's function for showing its consent preferences UI. Call
298
- `disposeEmbed()` when the page or component is destroyed. The helper observes
299
- both the current snapshot and later changes.
325
+ `consent` is the client from `init()` in your quickstart. With
326
+ `createConsentRuntime`, pass `runtime.kernel` and your own function that
327
+ opens preferences. Call `disposeEmbed()` when the page or component is
328
+ destroyed. Iframe markup with `data-src` and `data-category` also works
329
+ without the helper, because both setups gate iframes by default.
300
330
 
301
331
  ## Browser helper for Astro and JavaScript
302
332
 
@@ -305,51 +335,56 @@ when permission allows it, keeps an existing player mounted across unrelated
305
335
  snapshot updates, and removes it on revocation.
306
336
 
307
337
  ```ts title="src/consent-embed.ts"
308
- import { embedCategory, embedURL, embedTitle, embedAspectRatio } from './embed-config';
338
+ import {
339
+ embedCategory,
340
+ embedURL,
341
+ embedTitle,
342
+ embedAspectRatio,
343
+ } from './embed-config';
309
344
 
310
345
  type EmbedKernel = {
311
- getSnapshot: () => {
312
- effectivePermissions: Record<typeof embedCategory, boolean>;
313
- };
314
- subscribe: (listener: () => void) => () => void;
346
+ getSnapshot: () => {
347
+ effectivePermissions: Record<typeof embedCategory, boolean>;
348
+ };
349
+ subscribe: (listener: () => void) => () => void;
315
350
  };
316
351
 
317
352
  export function mountConsentEmbed(
318
- container: HTMLElement,
319
- kernel: EmbedKernel,
320
- openPreferences: () => void,
353
+ container: HTMLElement,
354
+ kernel: EmbedKernel,
355
+ openPreferences: () => void
321
356
  ) {
322
- const render = () => {
323
- if (kernel.getSnapshot().effectivePermissions[embedCategory]) {
324
- if (container.querySelector('iframe')) return;
325
- const frame = document.createElement('iframe');
326
- frame.src = embedURL;
327
- frame.title = embedTitle;
328
- frame.loading = 'lazy';
329
- frame.allowFullscreen = true;
330
- Object.assign(frame.style, {
331
- width: '100%',
332
- aspectRatio: embedAspectRatio,
333
- minHeight: '200px',
334
- border: '0',
335
- });
336
- container.replaceChildren(frame);
337
- } else {
338
- if (container.querySelector('button')) return;
339
- const button = document.createElement('button');
340
- button.type = 'button';
341
- button.textContent = 'Open privacy settings to view this content';
342
- button.onclick = openPreferences;
343
- container.replaceChildren(button);
344
- }
345
- };
346
-
347
- render();
348
- const unsubscribe = kernel.subscribe(render);
349
- return () => {
350
- unsubscribe();
351
- container.replaceChildren();
352
- };
357
+ const render = () => {
358
+ if (kernel.getSnapshot().effectivePermissions[embedCategory]) {
359
+ if (container.querySelector('iframe')) return;
360
+ const frame = document.createElement('iframe');
361
+ frame.src = embedURL;
362
+ frame.title = embedTitle;
363
+ frame.loading = 'lazy';
364
+ frame.allowFullscreen = true;
365
+ Object.assign(frame.style, {
366
+ width: '100%',
367
+ aspectRatio: embedAspectRatio,
368
+ minHeight: '200px',
369
+ border: '0',
370
+ });
371
+ container.replaceChildren(frame);
372
+ } else {
373
+ if (container.querySelector('button')) return;
374
+ const button = document.createElement('button');
375
+ button.type = 'button';
376
+ button.textContent = 'Open privacy settings to view this content';
377
+ button.onclick = openPreferences;
378
+ container.replaceChildren(button);
379
+ }
380
+ };
381
+
382
+ render();
383
+ const unsubscribe = kernel.subscribe(render);
384
+ return () => {
385
+ unsubscribe();
386
+ container.replaceChildren();
387
+ };
353
388
  }
354
389
  ```
355
390