Integrating Google Analytics (Tag Manager) with Astro

2 min

Introduction

If you’d like to dive straight into the solution, feel free to skip ahead.

I’ve always kept an eye on my blog traffic using Google Analytics, analyzing various referrers and metrics. With static site generators like Hexo and Hugo, hooking up Google Analytics was a breeze—you just drop the JavaScript snippet into the head tag and you’re good to go. Recently, I migrated my blog to Astro. Technically, the old method still works—just report events by executing JS in the head—but this comes at the cost of performance. As we all know, Astro is obsessed with razor-sharp frontend performance and as close to zero JS execution as possible. Executing JS for event reporting is directly at odds with that philosophy.

Awesome Performance!
Awesome Performance!

So I did some surfing and most of the guides I found recommended Partytown: a tool that offloads scripts from the main thread, ensuring they don’t block your page load and keeping performance intact. Many of these guides included some sample code. Naturally, I embedded similar demo code into my blog. Here’s what happened:

Analytics reporting flatlined.

It was pretty frustrating. I spent ages troubleshooting but couldn’t figure out what was wrong. Every example I found online used the same approach as I did. Kind of makes you wonder—did nobody actually test their own tutorials? None of them worked for me.

With no other choice, I shelved the effort for a couple of months and switched to Umami for site analytics in the meantime.

Recently, that unresolved issue started nagging at me again, so I resumed my search. Finally, buried in a GitHub thread, I stumbled on an actual solution.

Solution

First, install @astrojs/partytown using your preferred package manager.

In your <head> tag, add the following code:

<script is:inline src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXX" type="text/partytown"></script>
<script is:inline type="text/partytown">
  window.dataLayer = window.dataLayer || [];
  window.gtag = function () {
        dataLayer.push(arguments);
    };
  window.gtag('js', new Date());
  window.gtag('config', 'G-XXXXXXXXX');
</script>

A few key points:

  • is:inline instructs Astro to execute the script on the client side.
  • type="text/partytown" tells Partytown to handle the script, keeping it off the main thread.
  • The gtag function must be assigned to the window object as a function variable, not a function declaration (peculiar, but necessary).

Next, add this configuration in your Astro config file (such as astro.config.ts or astro.config.mjs):

import partytown from '@astrojs/partytown'

export default defineConfig({
  // ...
  integrations: [partytown({ config: { forward: ['dataLayer.push', 'gtag'] } })],
});

Worth noting: most guides miss the crucial step of forwarding 'gtag' in the array.

That’s it! After you commit and deploy, Google Analytics should start receiving data from your site as expected.