Skip to content

Commit 003a8be

Browse files
committed
fix: wrap GTM script in consent-checking client component for GDPR compliance
1 parent a5dc952 commit 003a8be

File tree

3 files changed

+73
-30
lines changed

3 files changed

+73
-30
lines changed

apps/web-roo-code/src/app/layout.tsx

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React from "react"
22
import type { Metadata } from "next"
3-
import Script from "next/script"
43
import { Inter } from "next/font/google"
54
import { SEO } from "@/lib/seo"
65
import { ogImageUrl } from "@/lib/og"
@@ -98,30 +97,6 @@ export default function RootLayout({ children }: { children: React.ReactNode })
9897
/>
9998
</head>
10099
<body className={inter.className}>
101-
{/* Google Tag Manager Script */}
102-
<Script
103-
id="google-tag-manager"
104-
strategy="afterInteractive"
105-
dangerouslySetInnerHTML={{
106-
__html: `
107-
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
108-
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
109-
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
110-
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
111-
})(window,document,'script','dataLayer','GTM-M2JZHV8N');
112-
`,
113-
}}
114-
/>
115-
{/* Google Tag Manager (noscript) */}
116-
<noscript>
117-
<iframe
118-
src="https://www.googletagmanager.com/ns.html?id=GTM-M2JZHV8N"
119-
height="0"
120-
width="0"
121-
style={{ display: "none", visibility: "hidden" }}
122-
/>
123-
</noscript>
124-
{/* End Google Tag Manager (noscript) */}
125100
<div itemScope itemType="https://schema.org/WebSite">
126101
<link itemProp="url" href={SEO.url} />
127102
<meta itemProp="name" content={SEO.name} />
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"use client"
2+
3+
import { useEffect, useState } from "react"
4+
import Script from "next/script"
5+
import { hasConsent, onConsentChange } from "@/lib/analytics/consent-manager"
6+
7+
// Google Tag Manager Container ID
8+
const GTM_ID = "GTM-M2JZHV8N"
9+
10+
/**
11+
* Google Tag Manager Provider
12+
* Loads GTM only after user consent is given, following GDPR requirements
13+
*/
14+
export function GoogleTagManagerProvider({ children }: { children: React.ReactNode }) {
15+
const [shouldLoad, setShouldLoad] = useState(false)
16+
17+
useEffect(() => {
18+
// Check initial consent status
19+
if (hasConsent()) {
20+
setShouldLoad(true)
21+
}
22+
23+
// Listen for consent changes
24+
const unsubscribe = onConsentChange((consented) => {
25+
if (consented) {
26+
setShouldLoad(true)
27+
}
28+
})
29+
30+
return unsubscribe
31+
}, [])
32+
33+
return (
34+
<>
35+
{shouldLoad && (
36+
<>
37+
{/* Google Tag Manager Script */}
38+
<Script
39+
id="google-tag-manager"
40+
strategy="afterInteractive"
41+
dangerouslySetInnerHTML={{
42+
__html: `
43+
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
44+
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
45+
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
46+
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
47+
})(window,document,'script','dataLayer','${GTM_ID}');
48+
`,
49+
}}
50+
/>
51+
{/* Google Tag Manager (noscript) */}
52+
<noscript>
53+
<iframe
54+
src={`https://www.googletagmanager.com/ns.html?id=${GTM_ID}`}
55+
height="0"
56+
width="0"
57+
style={{ display: "none", visibility: "hidden" }}
58+
/>
59+
</noscript>
60+
</>
61+
)}
62+
{children}
63+
</>
64+
)
65+
}

apps/web-roo-code/src/components/providers/providers.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,21 @@
33
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
44
import { ThemeProvider } from "next-themes"
55

6+
import { GoogleTagManagerProvider } from "./google-tag-manager-provider"
67
import { PostHogProvider } from "./posthog-provider"
78

89
const queryClient = new QueryClient()
910

1011
export const Providers = ({ children }: { children: React.ReactNode }) => {
1112
return (
1213
<QueryClientProvider client={queryClient}>
13-
<PostHogProvider>
14-
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem={false}>
15-
{children}
16-
</ThemeProvider>
17-
</PostHogProvider>
14+
<GoogleTagManagerProvider>
15+
<PostHogProvider>
16+
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem={false}>
17+
{children}
18+
</ThemeProvider>
19+
</PostHogProvider>
20+
</GoogleTagManagerProvider>
1821
</QueryClientProvider>
1922
)
2023
}

0 commit comments

Comments
 (0)