mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
feat: implement Google Consent Mode v2 with cookieless pings (#8987)
* feat: implement Google Consent Mode v2 with cookieless pings - Add consent defaults before gtag.js loads (required for Consent Mode v2) - Enable cookieless pings with url_passthrough for Google Ads - Implement consent update logic for all consent categories - Support both granted and denied consent states - Maintain backward compatibility with existing consent manager * fix: remove shouldLoad from useEffect dependency array to prevent re-initialization loop --------- Co-authored-by: Roo Code <roomote@roocode.com>
This commit is contained in:
parent
5b753f5855
commit
5fb36d9c85
1 changed files with 87 additions and 26 deletions
|
|
@ -8,72 +8,133 @@ import { hasConsent, onConsentChange } from "@/lib/analytics/consent-manager"
|
|||
const GTM_ID = "AW-17391954825"
|
||||
|
||||
/**
|
||||
* Google Analytics Provider
|
||||
* Only loads Google Tag Manager after user gives consent
|
||||
* Google Analytics Provider with Consent Mode v2
|
||||
* Implements cookieless pings and advanced consent management
|
||||
*/
|
||||
export function GoogleAnalyticsProvider({ children }: { children: React.ReactNode }) {
|
||||
const [shouldLoad, setShouldLoad] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize consent defaults BEFORE loading gtag.js (required for Consent Mode v2)
|
||||
initializeConsentDefaults()
|
||||
|
||||
// Check initial consent status
|
||||
if (hasConsent()) {
|
||||
setShouldLoad(true)
|
||||
initializeGoogleAnalytics()
|
||||
updateConsentGranted()
|
||||
}
|
||||
|
||||
// Listen for consent changes
|
||||
const unsubscribe = onConsentChange((consented) => {
|
||||
if (consented && !shouldLoad) {
|
||||
setShouldLoad(true)
|
||||
initializeGoogleAnalytics()
|
||||
if (consented) {
|
||||
if (!shouldLoad) {
|
||||
setShouldLoad(true)
|
||||
}
|
||||
updateConsentGranted()
|
||||
} else {
|
||||
updateConsentDenied()
|
||||
}
|
||||
})
|
||||
|
||||
return unsubscribe
|
||||
}, [shouldLoad])
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- shouldLoad intentionally omitted to prevent re-initialization loop
|
||||
}, [])
|
||||
|
||||
const initializeGoogleAnalytics = () => {
|
||||
// Initialize the dataLayer and gtag function
|
||||
const initializeConsentDefaults = () => {
|
||||
// Set up consent defaults before gtag loads (Consent Mode v2 requirement)
|
||||
if (typeof window !== "undefined") {
|
||||
window.dataLayer = window.dataLayer || []
|
||||
window.gtag = function (...args: GtagArgs) {
|
||||
window.dataLayer.push(args)
|
||||
}
|
||||
window.gtag("js", new Date())
|
||||
window.gtag("config", GTM_ID)
|
||||
|
||||
// Set default consent state to 'denied' with cookieless pings enabled
|
||||
window.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", // Always granted for security
|
||||
wait_for_update: 500, // Wait 500ms for consent before sending data
|
||||
})
|
||||
|
||||
// Enable cookieless pings for Google Ads
|
||||
window.gtag("set", "url_passthrough", true)
|
||||
}
|
||||
}
|
||||
|
||||
// Only render Google Analytics scripts if consent is given
|
||||
if (!shouldLoad) {
|
||||
return <>{children}</>
|
||||
const updateConsentGranted = () => {
|
||||
// User accepted cookies - update consent to granted
|
||||
if (typeof window !== "undefined" && window.gtag) {
|
||||
window.gtag("consent", "update", {
|
||||
ad_storage: "granted",
|
||||
ad_user_data: "granted",
|
||||
ad_personalization: "granted",
|
||||
analytics_storage: "granted",
|
||||
functionality_storage: "granted",
|
||||
personalization_storage: "granted",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const updateConsentDenied = () => {
|
||||
// User declined cookies - keep consent denied (cookieless pings still work)
|
||||
if (typeof window !== "undefined" && window.gtag) {
|
||||
window.gtag("consent", "update", {
|
||||
ad_storage: "denied",
|
||||
ad_user_data: "denied",
|
||||
ad_personalization: "denied",
|
||||
analytics_storage: "denied",
|
||||
functionality_storage: "denied",
|
||||
personalization_storage: "denied",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Always render scripts (Consent Mode v2 needs gtag loaded even without consent)
|
||||
// Cookieless pings will work with denied consent
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Google tag (gtag.js) - Only loads after consent */}
|
||||
{/* Google tag (gtag.js) - Loads immediately for Consent Mode v2 */}
|
||||
<Script
|
||||
src={`https://www.googletagmanager.com/gtag/js?id=${GTM_ID}`}
|
||||
strategy="afterInteractive"
|
||||
onLoad={() => {
|
||||
console.log("Google Analytics loaded with consent")
|
||||
// Initialize gtag config after script loads
|
||||
if (typeof window !== "undefined" && window.gtag) {
|
||||
window.gtag("js", new Date())
|
||||
window.gtag("config", GTM_ID)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Script id="google-analytics-init" strategy="afterInteractive">
|
||||
{`
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', '${GTM_ID}');
|
||||
`}
|
||||
</Script>
|
||||
{children}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
// Type definitions for Google Analytics
|
||||
type GtagArgs = ["js", Date] | ["config", string, GtagConfig?] | ["event", string, GtagEventParameters?]
|
||||
// Type definitions for Google Analytics with Consent Mode v2
|
||||
type ConsentState = "granted" | "denied"
|
||||
|
||||
interface ConsentParams {
|
||||
ad_storage?: ConsentState
|
||||
ad_user_data?: ConsentState
|
||||
ad_personalization?: ConsentState
|
||||
analytics_storage?: ConsentState
|
||||
functionality_storage?: ConsentState
|
||||
personalization_storage?: ConsentState
|
||||
security_storage?: ConsentState
|
||||
wait_for_update?: number
|
||||
}
|
||||
|
||||
type GtagArgs =
|
||||
| ["js", Date]
|
||||
| ["config", string, GtagConfig?]
|
||||
| ["event", string, GtagEventParameters?]
|
||||
| ["consent", "default" | "update", ConsentParams]
|
||||
| ["set", string, unknown]
|
||||
|
||||
interface GtagConfig {
|
||||
[key: string]: unknown
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue