How to use Gatsby's Script API with Google Analytics
In this post I’ll be explaining how to add Google’s “new” Google Analytics Property (GA4) to your Gatsby Site using the new Gatsby Script API.
I’ll be demonstrating how to use the off-main-thread
strategy which is powered by
Builder’io’s Partytown. I wrote about this once before on
the Gatsby Blog, but that
was before the release of Gatsby 4.15.0. From
4.15.0 onwards Gatsby takes care of all of the nitty-gritty for you so there’s
considerably less config required.
This post focuses on the Google Analytics 4 Property rather than the more recognizable Universal Analytics (UA) property. Here’s a little note from Google about why you should use GA4 rather than UA.
Universal Analytics will no longer process new data in standard properties beginning July 1, 2023. Prepare now by setting up and switching over to a Google Analytics 4 property
Below are links to a minimal example repository on GitHub, and a Gatsby Cloud preview URL.
- https://gatsbyscriptcomponentgoogleana.gatsbyjs.io/
- https://github.com/PaulieScanlon/gatsby-script-component-google-analytics
I won’t go through the steps to create a GA4 Property in this post, but here’s a link to Google’s docs that should help you on your way.
Getting Started
Upgrade
The Script API was released as part of Gatsby 4.15.0, make sure you’re on at least this version or upgrade to the latest version of Gatsby. Here’s a link to the Gatsby Changelog Prototype where you can see all the released versions and more details about each release.
npm install gatsby@latest
Remove Plugin
It’s likely you’ll have been using gatsby-plugin-google-analytics
, but after upgrading Gatsby you can uninstall it,
and remove it from the plugins array in gatsby-config
.
// gatsby-config.js
module.exports = {
plugins: [
...
- {
- resolve: 'gatsby-plugin-google-analytics',
- options: {
- trackingId: 'UA-12345678-9'
- }
- }
],
};
Partytown Proxy
Since you’re in gatsby-config.js
you’ll need to add the following.
I’ve explained in more detail how Partytown proxies requests from Web Workers and how this usually ends up with unfathomable CORS errors in this post: How to Add Google Analytics gtag to Gatsby Using Partytown 🎉
// gatsby-config.js
module.exports = {
plugins: [
...
],
+ partytownProxiedURLs: [`https://www.googletagmanager.com/gtag/js?id=${process.env.GATSBY_GA_MEASUREMENT_ID}`]
};
Adding Scripts
This next bit entirely depends on how you’ve setup your Gatsby Site.
Shared Component
It’s quite common however to have a “shared” React component that is returned by wrapRootElement
in both
gatsby-browser.js
and gatsby-ssr.js
. There’s a little more in the Gatsby Docs here:
Usage in Gatsby SSR and Browser APIs
In the example repo I’ve called this Component RootElement, and it looks a bit like this.
// src/components/root-element.js
import React, { Fragment } from 'react';
import { Script } from 'gatsby';
const RootElement = ({ children }) => {
return (
<Fragment>
<Script
src={`https://www.googletagmanager.com/gtag/js?id=${process.env.GATSBY_GA_MEASUREMENT_ID}`}
strategy='off-main-thread'
forward={[`gtag`]}
/>
<Script
id='gtag-config'
strategy='off-main-thread'
dangerouslySetInnerHTML={{
__html: `window.dataLayer = window.dataLayer || [];
window.gtag = function gtag(){ window.dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${process.env.GATSBY_GA_MEASUREMENT_ID}', { send_page_view: false })`,
}}
/>
<div>{children}</div>
</Fragment>
);
};
export default RootElement;
The RootElement
Component is returned by wrapRootElement
in both gatsby-browser.js
and gatsby-ssr.js
which looks
a bit like this.
// gatsby-browser.js
import React from 'react';
import RootElement from './src/components/root-element';
export const wrapRootElement = ({ element }) => {
return <RootElement>{element}</RootElement>;
};
// gatsby-ssr.js
import React from 'react';
import RootElement from './src/components/root-element';
export const wrapRootElement = ({ element }) => {
return <RootElement>{element}</RootElement>;
};
If you don’t ensure that gatsby-browser.js
and gatsby-ssr
return the same DOM elements you’ll likely see a React
error like this.
Hydration failed because the initial UI does not match what was rendered on the server
You can read more about what that error means in the React Docs: Error Decoder
Page Views
You’ll notice from the above that in the gtag
config send_page_view
is set to false
. This is just for the
initial setup but naturally you’ll want to fire off page_view
events… because that’s what Google Analytics is all
about amirite?
Send Page Views
onRouteUpdate
is one of Gatsby Browser’s API’s and fires whenever a route change is detected. This API has a
destructured parameter for the current location. This is perfect for sending to Google’s page_view
and will show up in
your Analytics Dashboard.
Here’s how I’ve implemented it in gatsby-browser.js
. You can see the complete src
from the example repo here:
gatsby-browser.js
// gatsby-browser.js
import React from 'react';
import RootElement from './src/components/root-element';
+ export const onRouteUpdate = ({ location }) => {
+ if (process.env.NODE_ENV !== 'production') {
+ return null;
+ }
+ const pagePath = location ? location.pathname + location.search + location.hash : undefined;
+ setTimeout(() => {
+ if (typeof window.gtag === 'function') {
+ window.gtag('event', 'page_view', { page_path: pagePath });
+ }
+ }, 100);
+ return true;
+ };
export const wrapRootElement = ({ element }) => {
return <RootElement>{element}</RootElement>;
};
Google Admin Dashboard
This tripped me up but, make sure you’ve added your site URL to the Data Streams section of your Google Analytics
Dashboard otherwise Google won’t be “listening” out of page_view
events.
And Finally
Here’s a little screenshot of my Google Analytics Realtime Overview, et voila, there I am on the map. It works, lovely stuff.
Hi friends 👋
— Paul Scanlon (@PaulieScanlon) July 26, 2022
Here's a short post on how to use the @GatsbyJS Script API + off-main-thread strategy powered by @builderio's Partytown 🎉 with Google's "new" GA4 Analytics script.
(what a mouthful that is!)
Hope you find it helpful! 😃https://t.co/Nc63x46wf5
Further Reading
- Scripts and the Head: What Goes Where?
- Gatsby Script API
- How to Add Google Analytics gtag to Gatsby Using Partytown 🎉
- Using Gatsby Script Component to Decrease Page Load Times