Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 47 additions & 45 deletions packages/ui/src/components/google-tag-manager.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,60 @@
/**
* Consent-gated Google Tag Manager loader.
*
* Split into two parts on purpose:
*
* 1. An inline bootstrap that always runs. It only initialises `dataLayer`
* (a plain in-memory array) and pushes the page section + GTM start event.
* This sets no cookies and makes no network requests, so it is safe to run
* before consent.
* 2. The GTM library itself, loaded as an EXTERNAL `src` script tagged for
* CookieYes' analytics category. CookieYes only reliably re-activates
* external `src` scripts after consent — an inline `type="text/plain"` GTM
* bootstrap is left inert and never executes, so it must NOT be used here.
* This mirrors the working external-`src` pattern used for Tolt/PromptWatch.
* See https://www.cookieyes.com/documentation/implement-prior-consent-using-cookieyes/
*
* Nothing contacts Google until CookieYes activates the external script once the
* visitor grants analytics consent (GDPR/ePrivacy compliant). No `<noscript>`
* iframe fallback is rendered, as it would load GTM regardless of consent.
*
* One container serves the whole prisma.io domain; each zone passes its
* `section` so every hit carries a `site_section` dimension and can be segmented
* (website vs blog vs docs) in GA4.
*/

import type { SiteSection } from "../lib/analytics";

// Public, client-side container ID (Prisma Main › prisma.io). Ships in the HTML
// to every visitor by design, so it is intentionally hardcoded, not an env var.
// Public, client-side container ID (Prisma Main › prisma.io).
const GTM_CONTAINER_ID = "GTM-KRTRXXQ6";

type GoogleTagManagerProps = {
section: SiteSection;
};

export function GoogleTagManager({ section }: GoogleTagManagerProps) {
const bootstrap = `
const html = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
analytics_storage: 'denied',
functionality_storage: 'denied',
personalization_storage: 'denied',
security_storage: 'granted',
wait_for_update: 2000
});
gtag('set', 'ads_data_redaction', true);
gtag('set', 'url_passthrough', true);
window.dataLayer.push({ site_section: ${JSON.stringify(section)} });
window.dataLayer.push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });`.trim();

return (
<>
{/* Always runs: dataLayer setup only — no cookies, no network requests. */}
<script id="gtm-datalayer" dangerouslySetInnerHTML={{ __html: bootstrap }} />
{/* Consent-gated: CookieYes activates this external script after analytics
consent, which then loads the container and starts firing tags. */}
<script
id="gtm-loader"
type="text/plain"
data-cookieyes="cookieyes-analytics"
data-cookieyes-category="analytics"
async
src={`https://www.googletagmanager.com/gtm.js?id=${GTM_CONTAINER_ID}`}
/>
</>
);
// Bridge CookieYes consent
(function(){
function update(accepted){
accepted = accepted || [];
var ads = accepted.indexOf('advertisement') !== -1 ? 'granted' : 'denied';
gtag('consent', 'update', {
analytics_storage: accepted.indexOf('analytics') !== -1 ? 'granted' : 'denied',
ad_storage: ads,
ad_user_data: ads,
ad_personalization: ads
});
}
// Fires when the visitor changes consent.
document.addEventListener('cookieyes_consent_update', function(e){
update(e && e.detail && e.detail.accepted);
});
// Applies stored consent for returning visitors once CookieYes is ready.
document.addEventListener('cookieyes_banner_load', function(){
if (typeof getCkyConsent === 'function') {
var cats = (getCkyConsent() || {}).categories || {};
update(Object.keys(cats).filter(function(k){ return cats[k]; }));
}
});
})();

(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${GTM_CONTAINER_ID}');`.trim();

return <script id="gtm-loader" dangerouslySetInnerHTML={{ __html: html }} />;
}
Loading