@@ -60,6 +60,10 @@ pub struct GoogleTagManagerConfig {
6060 #[ serde( default = "default_upstream" ) ]
6161 #[ validate( url) ]
6262 pub upstream_url : String ,
63+ /// Cache max-age in seconds for the rewritten GTM script (default: 900 to match Google's default).
64+ #[ serde( default = "default_cache_max_age" ) ]
65+ #[ validate( range( min = 60 , max = 86400 ) ) ]
66+ pub cache_max_age : u32 ,
6367}
6468
6569impl IntegrationConfig for GoogleTagManagerConfig {
@@ -76,6 +80,10 @@ fn default_upstream() -> String {
7680 DEFAULT_UPSTREAM . to_string ( )
7781}
7882
83+ fn default_cache_max_age ( ) -> u32 {
84+ 900 // Match Google's default
85+ }
86+
7987pub struct GoogleTagManagerIntegration {
8088 config : GoogleTagManagerConfig ,
8189}
@@ -196,6 +204,8 @@ impl IntegrationProxy for GoogleTagManagerIntegration {
196204 log:: debug!( "Proxying to upstream: {}" , target_url) ;
197205
198206 let mut proxy_config = ProxyRequestConfig :: new ( & target_url) ;
207+ // Do not forward the synthetic ID to external Google services.
208+ proxy_config. forward_synthetic_id = false ;
199209
200210 // If we are fetching gtm.js, we intend to rewrite the body.
201211 // We must ensure the upstream returns uncompressed content.
@@ -225,7 +235,10 @@ impl IntegrationProxy for GoogleTagManagerIntegration {
225235 fastly:: http:: header:: CONTENT_TYPE ,
226236 "application/javascript; charset=utf-8" ,
227237 )
228- . with_header ( fastly:: http:: header:: CACHE_CONTROL , "public, max-age=3600" ) ;
238+ . with_header (
239+ fastly:: http:: header:: CACHE_CONTROL ,
240+ format ! ( "public, max-age={}" , self . config. cache_max_age) ,
241+ ) ;
229242 }
230243
231244 Ok ( response)
@@ -322,6 +335,7 @@ mod tests {
322335 enabled : true ,
323336 container_id : "GTM-TEST" . to_string ( ) ,
324337 upstream_url : "https://www.googletagmanager.com" . to_string ( ) ,
338+ cache_max_age : default_cache_max_age ( ) ,
325339 } ;
326340 let integration = GoogleTagManagerIntegration :: new ( config) ;
327341
@@ -377,6 +391,7 @@ mod tests {
377391 enabled : true ,
378392 container_id : "GTM-TEST" . to_string ( ) ,
379393 upstream_url : "https://www.googletagmanager.com" . to_string ( ) ,
394+ cache_max_age : default_cache_max_age ( ) ,
380395 } ;
381396 let integration = GoogleTagManagerIntegration :: new ( config) ;
382397 let doc_state = IntegrationDocumentState :: default ( ) ;
@@ -430,6 +445,7 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
430445 enabled : default_enabled ( ) ,
431446 container_id : "GTM-DEFAULT" . to_string ( ) ,
432447 upstream_url : default_upstream ( ) ,
448+ cache_max_age : default_cache_max_age ( ) ,
433449 } ;
434450
435451 assert ! ( !config. enabled) ;
@@ -443,6 +459,7 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
443459 enabled : true ,
444460 container_id : "GTM-123" . to_string ( ) ,
445461 upstream_url : "" . to_string ( ) , // Empty string should fallback to default in accessor
462+ cache_max_age : default_cache_max_age ( ) ,
446463 } ;
447464 let integration_default = GoogleTagManagerIntegration :: new ( config_default) ;
448465 assert_eq ! (
@@ -455,6 +472,7 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
455472 enabled : true ,
456473 container_id : "GTM-123" . to_string ( ) ,
457474 upstream_url : "https://gtm.example.com" . to_string ( ) ,
475+ cache_max_age : default_cache_max_age ( ) ,
458476 } ;
459477 let integration_custom = GoogleTagManagerIntegration :: new ( config_custom) ;
460478 assert_eq ! ( integration_custom. upstream_url( ) , "https://gtm.example.com" ) ;
@@ -466,6 +484,7 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
466484 enabled : true ,
467485 container_id : "GTM-TEST" . to_string ( ) ,
468486 upstream_url : default_upstream ( ) ,
487+ cache_max_age : default_cache_max_age ( ) ,
469488 } ;
470489 let integration = GoogleTagManagerIntegration :: new ( config) ;
471490 let routes = integration. routes ( ) ;
0 commit comments