Translated from the original Japanese article
Tech 2 min read
Integrating Google Analytics (GA4) into an Astro Site with Partytown
Contents
I added Google Analytics 4 (GA4) to this Astro site. By using Partytown, which Astro officially recommends, the analytics script runs in a Web Worker and has minimal impact on the main thread.
What Partytown Is
Partytown is a library that moves third-party scripts into a Web Worker. By separating heavy scripts such as Google Analytics and Google Tag Manager from the main thread, it improves page performance.
Astro provides an official integration as @astrojs/partytown.
Setup
1. Install the package
pnpm add @astrojs/partytown
2. Configure astro.config.mjs
import partytown from '@astrojs/partytown';
export default defineConfig({
integrations: [
partytown({
config: {
forward: ['dataLayer.push'],
},
}),
],
});
The forward option specifies which functions should be forwarded from the main thread to the Web Worker. GA4 uses dataLayer.push, so it needs to be included here.
3. Add the GA4 script to BaseLayout
<!-- Google Analytics (GA4) with Partytown -->
{import.meta.env.PROD && (
<>
<script type="text/partytown" src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script type="text/partytown">
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
</script>
</>
)}
Points to note:
type="text/partytown"makes the script execute in a Web Workerimport.meta.env.PRODensures the script only runs in production so local traffic is not counted
Verification
- Run
pnpm build && pnpm preview - Open the browser developer tools and confirm that
gtag.jsis loaded in the Network tab - Check the Google Analytics realtime report to confirm visits are being recorded
Why Use Partytown?
You could embed GA4 directly, but Partytown is preferable for these reasons:
- Performance: It does not block the main thread, so Core Web Vitals, especially TBT and FID, improve
- Official support: Astro provides it as an official integration, so maintenance is ongoing
- Simple setup: You only need to add
type="text/partytown"