@@ -8,72 +8,132 @@ import { hasConsent, onConsentChange } from "@/lib/analytics/consent-manager"
88const  GTM_ID  =  "AW-17391954825" 
99
1010/** 
11-  * Google Analytics Provider 
12-  * Only loads Google Tag Manager after user gives  consent 
11+  * Google Analytics Provider with Consent Mode v2  
12+  * Implements cookieless pings and advanced  consent management  
1313 */ 
1414export  function  GoogleAnalyticsProvider ( {  children } : {  children : React . ReactNode  } )  { 
1515	const  [ shouldLoad ,  setShouldLoad ]  =  useState ( false ) 
1616
1717	useEffect ( ( )  =>  { 
18+ 		// Initialize consent defaults BEFORE loading gtag.js (required for Consent Mode v2) 
19+ 		initializeConsentDefaults ( ) 
20+ 
1821		// Check initial consent status 
1922		if  ( hasConsent ( ) )  { 
2023			setShouldLoad ( true ) 
21- 			initializeGoogleAnalytics ( ) 
24+ 			updateConsentGranted ( ) 
2225		} 
2326
2427		// Listen for consent changes 
2528		const  unsubscribe  =  onConsentChange ( ( consented )  =>  { 
26- 			if  ( consented  &&  ! shouldLoad )  { 
27- 				setShouldLoad ( true ) 
28- 				initializeGoogleAnalytics ( ) 
29+ 			if  ( consented )  { 
30+ 				if  ( ! shouldLoad )  { 
31+ 					setShouldLoad ( true ) 
32+ 				} 
33+ 				updateConsentGranted ( ) 
34+ 			}  else  { 
35+ 				updateConsentDenied ( ) 
2936			} 
3037		} ) 
3138
3239		return  unsubscribe 
3340	} ,  [ shouldLoad ] ) 
3441
35- 	const  initializeGoogleAnalytics  =  ( )  =>  { 
36- 		// Initialize the dataLayer and  gtag function  
42+ 	const  initializeConsentDefaults  =  ( )  =>  { 
43+ 		// Set up consent defaults before  gtag loads (Consent Mode v2 requirement)  
3744		if  ( typeof  window  !==  "undefined" )  { 
3845			window . dataLayer  =  window . dataLayer  ||  [ ] 
3946			window . gtag  =  function  ( ...args : GtagArgs )  { 
4047				window . dataLayer . push ( args ) 
4148			} 
42- 			window . gtag ( "js" ,  new  Date ( ) ) 
43- 			window . gtag ( "config" ,  GTM_ID ) 
49+ 
50+ 			// Set default consent state to 'denied' with cookieless pings enabled 
51+ 			window . gtag ( "consent" ,  "default" ,  { 
52+ 				ad_storage : "denied" , 
53+ 				ad_user_data : "denied" , 
54+ 				ad_personalization : "denied" , 
55+ 				analytics_storage : "denied" , 
56+ 				functionality_storage : "denied" , 
57+ 				personalization_storage : "denied" , 
58+ 				security_storage : "granted" ,  // Always granted for security 
59+ 				wait_for_update : 500 ,  // Wait 500ms for consent before sending data 
60+ 			} ) 
61+ 
62+ 			// Enable cookieless pings for Google Ads 
63+ 			window . gtag ( "set" ,  "url_passthrough" ,  true ) 
4464		} 
4565	} 
4666
47- 	// Only render Google Analytics scripts if consent is given 
48- 	if  ( ! shouldLoad )  { 
49- 		return  < > { children } </ > 
67+ 	const  updateConsentGranted  =  ( )  =>  { 
68+ 		// User accepted cookies - update consent to granted 
69+ 		if  ( typeof  window  !==  "undefined"  &&  window . gtag )  { 
70+ 			window . gtag ( "consent" ,  "update" ,  { 
71+ 				ad_storage : "granted" , 
72+ 				ad_user_data : "granted" , 
73+ 				ad_personalization : "granted" , 
74+ 				analytics_storage : "granted" , 
75+ 				functionality_storage : "granted" , 
76+ 				personalization_storage : "granted" , 
77+ 			} ) 
78+ 		} 
5079	} 
5180
81+ 	const  updateConsentDenied  =  ( )  =>  { 
82+ 		// User declined cookies - keep consent denied (cookieless pings still work) 
83+ 		if  ( typeof  window  !==  "undefined"  &&  window . gtag )  { 
84+ 			window . gtag ( "consent" ,  "update" ,  { 
85+ 				ad_storage : "denied" , 
86+ 				ad_user_data : "denied" , 
87+ 				ad_personalization : "denied" , 
88+ 				analytics_storage : "denied" , 
89+ 				functionality_storage : "denied" , 
90+ 				personalization_storage : "denied" , 
91+ 			} ) 
92+ 		} 
93+ 	} 
94+ 
95+ 	// Always render scripts (Consent Mode v2 needs gtag loaded even without consent) 
96+ 	// Cookieless pings will work with denied consent 
97+ 
5298	return  ( 
5399		< > 
54- 			{ /* Google tag (gtag.js) - Only loads after consent  */ } 
100+ 			{ /* Google tag (gtag.js) - Loads immediately for Consent Mode v2  */ } 
55101			< Script 
56102				src = { `https://www.googletagmanager.com/gtag/js?id=${ GTM_ID }  ` } 
57103				strategy = "afterInteractive" 
58104				onLoad = { ( )  =>  { 
59- 					console . log ( "Google Analytics loaded with consent" ) 
105+ 					// Initialize gtag config after script loads 
106+ 					if  ( typeof  window  !==  "undefined"  &&  window . gtag )  { 
107+ 						window . gtag ( "js" ,  new  Date ( ) ) 
108+ 						window . gtag ( "config" ,  GTM_ID ) 
109+ 					} 
60110				} } 
61111			/> 
62- 			< Script  id = "google-analytics-init"  strategy = "afterInteractive" > 
63- 				{ ` 
64- 					window.dataLayer = window.dataLayer || []; 
65- 					function gtag(){dataLayer.push(arguments);} 
66- 					gtag('js', new Date()); 
67- 					gtag('config', '${ GTM_ID }  '); 
68- 				` } 
69- 			</ Script > 
70112			{ children } 
71113		</ > 
72114	) 
73115} 
74116
75- // Type definitions for Google Analytics 
76- type  GtagArgs  =  [ "js" ,  Date ]  |  [ "config" ,  string ,  GtagConfig ?]  |  [ "event" ,  string ,  GtagEventParameters ?] 
117+ // Type definitions for Google Analytics with Consent Mode v2 
118+ type  ConsentState  =  "granted"  |  "denied" 
119+ 
120+ interface  ConsentParams  { 
121+ 	ad_storage ?: ConsentState 
122+ 	ad_user_data ?: ConsentState 
123+ 	ad_personalization ?: ConsentState 
124+ 	analytics_storage ?: ConsentState 
125+ 	functionality_storage ?: ConsentState 
126+ 	personalization_storage ?: ConsentState 
127+ 	security_storage ?: ConsentState 
128+ 	wait_for_update ?: number 
129+ } 
130+ 
131+ type  GtagArgs  = 
132+ 	|  [ "js" ,  Date ] 
133+ 	|  [ "config" ,  string ,  GtagConfig ?] 
134+ 	|  [ "event" ,  string ,  GtagEventParameters ?] 
135+ 	|  [ "consent" ,  "default"  |  "update" ,  ConsentParams ] 
136+ 	|  [ "set" ,  string ,  unknown ] 
77137
78138interface  GtagConfig  { 
79139	[ key : string ] : unknown 
0 commit comments