Gatsby plugin to add Google Tag Manager onto a site with route tracking and Core Web Vitals support
npx @tessl/cli install tessl/npm-gatsby-plugin-google-tagmanager@5.15.0Gatsby plugin that provides seamless integration with Google Tag Manager (GTM) for Gatsby websites, enabling comprehensive analytics and tag management capabilities. The plugin automatically injects the required GTM scripts into the HTML head and body, supports both production and development environments with configurable inclusion, and provides advanced features like custom data layer configuration, environment-specific GTM settings, and Core Web Vitals tracking.
npm install gatsby-plugin-google-tagmanagerThis is a Gatsby plugin - it's not imported directly. Instead, it's configured in your gatsby-config.js file:
// gatsby-config.js
module.exports = {
plugins: [
{
resolve: "gatsby-plugin-google-tagmanager",
options: {
id: "YOUR_GOOGLE_TAGMANAGER_ID",
// Additional options...
},
},
],
};// gatsby-config.js
module.exports = {
plugins: [
{
resolve: "gatsby-plugin-google-tagmanager",
options: {
id: "GTM-XXXXXXX",
includeInDevelopment: false,
defaultDataLayer: { platform: "gatsby" },
enableWebVitalsTracking: true,
},
},
],
};The plugin integrates with Gatsby's lifecycle through several hooks:
The plugin operates by injecting Google Tag Manager's JavaScript snippet into the HTML head, optionally setting up a custom data layer, and providing automatic route change tracking for single-page application navigation.
Configure the plugin through the Gatsby plugin options system with comprehensive validation.
interface PluginOptions {
/** Google Tag Manager ID that can be found in your Tag Manager dashboard */
id?: string;
/** Include Google Tag Manager when running in development mode (default: false) */
includeInDevelopment?: boolean;
/** Data layer to be set before Google Tag Manager is loaded. Should be an object or a function (default: null) */
defaultDataLayer?: object | (() => object) | null;
/** Google Tag Manager environment auth string (default: undefined) */
gtmAuth?: string;
/** Google Tag Manager environment preview name (default: undefined) */
gtmPreview?: string;
/** Data layer name (default: "dataLayer") */
dataLayerName?: string;
/** Name of the event that is triggered on every Gatsby route change (default: "gatsby-route-change") */
routeChangeEventName?: string;
/** Enable Core Web Vitals tracking (default: false) */
enableWebVitalsTracking?: boolean;
/** The origin where GTM is hosted (default: "https://www.googletagmanager.com") */
selfHostedOrigin?: string;
/** The path where GTM is hosted (default: "gtm.js") */
selfHostedPath?: string;
}Configuration Examples:
// Basic configuration
{
resolve: "gatsby-plugin-google-tagmanager",
options: {
id: "GTM-XXXXXXX",
},
}
// Advanced configuration with custom data layer
{
resolve: "gatsby-plugin-google-tagmanager",
options: {
id: "GTM-XXXXXXX",
includeInDevelopment: true,
defaultDataLayer: { platform: "gatsby", version: "5.0" },
dataLayerName: "customDataLayer",
routeChangeEventName: "page-view",
enableWebVitalsTracking: true,
},
}
// Dynamic data layer with function
{
resolve: "gatsby-plugin-google-tagmanager",
options: {
id: "GTM-XXXXXXX",
defaultDataLayer: function () {
return {
pageType: window.pageType,
userAgent: window.navigator.userAgent,
};
},
},
}
// Self-hosted GTM configuration
{
resolve: "gatsby-plugin-google-tagmanager",
options: {
id: "GTM-XXXXXXX",
selfHostedOrigin: "https://your-domain.com",
selfHostedPath: "custom-gtm.js",
},
}
// GTM environment configuration
{
resolve: "gatsby-plugin-google-tagmanager",
options: {
id: "GTM-XXXXXXX",
gtmAuth: "YOUR_AUTH_STRING",
gtmPreview: "env-1",
},
}Automatic tracking of route changes in your Gatsby application through the browser API.
/**
* Gatsby browser lifecycle hook that fires route change events in GTM data layer
* Automatically called by Gatsby on route transitions
* @param _ - Gatsby API object (unused)
* @param pluginOptions - Plugin configuration options
*/
function onRouteUpdate(_: any, pluginOptions: PluginOptions): void;The plugin automatically fires a gatsby-route-change event (or custom event name from routeChangeEventName option) to the GTM data layer whenever users navigate between pages. This enables tracking of single-page application navigation in Google Tag Manager. The event is fired with a 50ms timeout to ensure the page title has been properly updated.
Data Layer Event Structure:
// Default event fired on route changes
{
event: "gatsby-route-change" // or custom routeChangeEventName
}Automatic injection of GTM tracking code during the build process.
/**
* Gatsby SSR lifecycle hook that injects GTM scripts into HTML
* Automatically called by Gatsby during build/SSR
* @param gatsbyApi - Gatsby SSR API object with setHeadComponents and setPreBodyComponents
* @param pluginOptions - Plugin configuration options
*/
function onRenderBody(
gatsbyApi: {
setHeadComponents: (components: React.ReactNode[]) => void;
setPreBodyComponents: (components: React.ReactNode[]) => void;
reporter: {
panic: (message: string) => never;
};
},
pluginOptions: PluginOptions
): void;The plugin automatically:
<head> using the standard Google Tag Manager templatedefaultDataLayer data before loading GTM<noscript> iframe fallback in the <body> for users with JavaScript disabledenableWebVitalsTracking is enabledgtmAuth and gtmPreview are both providedselfHostedOrigin for proper URL constructionOptional performance monitoring that sends Core Web Vitals metrics to GTM.
/**
* Gatsby browser lifecycle hook that initializes Web Vitals tracking
* Automatically called by Gatsby on initial page load
* @param _ - Gatsby API object (unused)
* @param pluginOptions - Plugin configuration options
*/
function onInitialClientRender(_: any, pluginOptions: PluginOptions): void;When enableWebVitalsTracking is set to true, the plugin automatically:
web-vitals/base library and includes a polyfill script for accurate measurement in non-Chromium browsersenableWebVitalsTracking setting valueWeb Vitals Data Layer Events:
// Example Core Web Vitals event sent to data layer
{
event: "core-web-vitals",
webVitalsMeasurement: {
name: "LCP", // Metric name: "LCP", "FID", or "CLS"
id: "unique-id", // Unique identifier for this page load
value: 1250 // Metric value (rounded integer, CLS multiplied by 1000)
}
}The plugin integrates with Gatsby's plugin system through standard lifecycle hooks.
/**
* Gatsby Node lifecycle hook for preprocessing plugin options
* Automatically called by Gatsby during build initialization
* @param args - Gatsby Node API arguments
* @param options - Raw plugin options from gatsby-config.js
*/
function onPreInit(args: any, options: PluginOptions): void;
/**
* Plugin options validation schema using Joi
* Automatically called by Gatsby to validate plugin configuration
* @param schemaUtils - Gatsby schema utilities containing Joi
* @returns Joi validation schema object
*/
function pluginOptionsSchema(schemaUtils: { Joi: any }): any;The plugin automatically handles:
defaultDataLayer options for serializationThe plugin includes comprehensive error handling:
NODE_ENV settings unless overriddenincludeInDevelopment: trueenableWebVitalsTracking settingThe plugin has minimal runtime dependencies: