[{"data":1,"prerenderedAt":186},["ShallowReactive",2],{"content:\u002Fen\u002Ffiddling\u002Fastro-google-tag-manager":3,"surround:\u002Fen\u002Ffiddling\u002Fastro-google-tag-manager":175},{"id":4,"title":5,"authorship":6,"body":7,"categories":143,"date":145,"description":146,"draft":147,"extension":148,"image":149,"meta":150,"navigation":152,"path":153,"permalink":154,"published":154,"readingTime":155,"recommend":154,"references":154,"seo":160,"seoDescription":161,"seoTitle":154,"sitemap":162,"stem":166,"tags":167,"type":173,"__hash__":174},"content_en\u002Fposts\u002Ffiddling\u002Fastro-google-tag-manager.md","Adding Google Analytics to Astro with Tag Manager","human-only",{"type":8,"value":9,"toc":137},"minimark",[10,15,19,22,29,32,38,41,44,47,58,62,70,76,85,88,110,120,128,134],[11,12,14],"h3",{"id":13},"introduction","Introduction",[16,17,18],"p",{},"Skip straight to the solution if you would rather avoid the rambling.",[16,20,21],{},"I had always used Google Analytics to check my blog traffic and analyze things like referrers. Static blog frameworks such as Hexo and Hugo make integration easy: just add some JavaScript to the head. I recently moved the blog to Astro. The old approach still works—execute JavaScript in the head to report events—but it comes at a performance cost. As everyone knows, Astro aims for the best possible frontend performance and as close to zero JavaScript execution as possible. Reporting events with JavaScript takes a bite out of that.",[16,23,24],{},[25,26],"img",{"alt":27,"src":28},"A perfect performance score!","https:\u002F\u002Fblog-img.774352199.xyz\u002F2025\u002Fe1e778992ea6b393ed763a8642db3770.png",[16,30,31],{},"After some searching, most tutorials recommended partytown to run scripts off the main thread, keeping loading unblocked and performance intact. They all included example code, so I adapted one for my blog. Here was the result:",[16,33,34],{},[25,35],{"alt":36,"src":37},"","https:\u002F\u002Fblog-img.774352199.xyz\u002F2025\u002Fe5005b9f2321f6946761eef52156e777.png",[16,39,40],{},"Reported traffic dropped straight to zero.",[16,42,43],{},"I could barely believe it. A long debugging session followed, but I never found the cause. Every relevant example I could find online used the same approach as mine. Honestly, do these people ever test their tutorials? None of this worked.",[16,45,46],{},"I had to leave it alone for two months and temporarily switch to umami for analytics.",[16,48,49,50,57],{},"It came back to mind over the last couple of days, and I could not let it go. Another long search finally turned up a solution in an obscure ",[51,52,56],"a",{"href":53,"rel":54},"https:\u002F\u002Fgithub.com\u002FQwikDev\u002Fpartytown\u002Fissues\u002F382#issuecomment-1667675238",[55],"nofollow","corner of GitHub",".",[11,59,61],{"id":60},"solution","Solution",[16,63,64,65,69],{},"Install ",[66,67,68],"code",{"code":68},"@astrojs\u002Fpartytown"," with your package manager.",[16,71,72,73,57],{},"Add the following code to ",[66,74,75],{"code":75},"\u003Chead>",[77,78,83],"pre",{"className":79,"code":81,"language":82,"meta":36},[80],"language-html","\u003Cscript is:inline src=\"https:\u002F\u002Fwww.googletagmanager.com\u002Fgtag\u002Fjs?id=G-XXXXXXXXX\" type=\"text\u002Fpartytown\">\u003C\u002Fscript>\n\u003Cscript is:inline type=\"text\u002Fpartytown\">\n  window.dataLayer = window.dataLayer || [];\n  window.gtag = function () {\n        dataLayer.push(arguments);\n    };\n  window.gtag('js', new Date());\n  window.gtag('config', 'G-XXXXXXXXX');\n\u003C\u002Fscript>\n","html",[66,84,81],{"__ignoreMap":36},[16,86,87],{},"A few things to keep in mind:",[89,90,91,98,104],"ul",{},[92,93,94,97],"li",{},[66,95,96],{"code":96},"is:inline"," indicates that the script runs on the client.",[92,99,100,103],{},[66,101,102],{"code":102},"type=\"text\u002Fpartytown\""," tells partytown to execute the script off the main thread.",[92,105,106,109],{},[66,107,108],{"code":108},"gtag"," must be assigned as a function variable on the window object, rather than defined with a function declaration. Strange, I know.",[16,111,112,113,116,117,57],{},"Add the following to your Astro configuration file, usually ",[66,114,115],{"code":115},"astro.config.ts"," or ",[66,118,119],{"code":119},"astro.config.mjs",[77,121,126],{"className":122,"code":124,"language":125,"meta":36},[123],"language-js","import partytown from '@astrojs\u002Fpartytown'\n\nexport default defineConfig({\n  \u002F\u002F ...\n  integrations: [partytown({ config: { forward: ['dataLayer.push', 'gtag'] } })],\n});\n","js",[66,127,124],{"__ignoreMap":36},[16,129,130,131,133],{},"Most tutorials leave out the fact that ",[66,132,108],{"code":108}," also needs to go in the forward array.",[16,135,136],{},"Done! Once committed and deployed, Google Analytics can report statistics normally again.",{"title":36,"searchDepth":138,"depth":138,"links":139},4,[140,142],{"id":13,"depth":141,"text":14},3,{"id":60,"depth":141,"text":61},[144],"fiddling","2025-05-28 22:09:00","After moving my blog to Astro, the usual Google Analytics integration no longer fit its performance goals. Adding event-reporting JavaScript directly to the head works, but hurts page performance. I used partytown to move the scripts off the main thread so they would not interfere with loading. With a few adjustments to the example code, Google Analytics finally worked, balancing performance with analytics.",false,"md","https:\u002F\u002Fblog-img.774352199.xyz\u002FQ0w4RN.webp",{"slots":151},{},true,"\u002Ffiddling\u002Fastro-google-tag-manager",null,{"text":156,"minutes":157,"time":158,"words":159},"2 min read",1.785,107100,357,{"title":5,"description":146},"I fixed missing Google Analytics events in Astro with Partytown by defining window.gtag, setting script attributes, and adding gtag to the forward array.",{"loc":153,"images":163},[164,165],{"loc":28},{"loc":37},"posts\u002Ffiddling\u002Fastro-google-tag-manager",[168,169,170,171,172],"Astro","Google Analytics","Google Tag Manager","Partytown","Web analytics","tech","sA4bU-OxJZsoCNK_HT6MepbybKelXqsS-WTqdB8vMYs",[176,181],{"title":177,"path":178,"stem":179,"date":180,"type":173,"children":-1},"Connecting My Shanghai and Hangzhou Networks","\u002Ffiddling\u002Fcross-city-network-setup","posts\u002Ffiddling\u002Fcross-city-network-setup","2025-04-18 16:43:12",{"title":182,"path":183,"stem":184,"date":185,"type":173,"children":-1},"One Month After Switching to Android","\u002Ffiddling\u002Fone-month-using-android","posts\u002Ffiddling\u002Fone-month-using-android","2025-06-05 23:26:00",1789914049581]