Install Google Tag Manager on your DatoCMS-powered website to centralize tag management and tracking. Since DatoCMS is headless, GTM is implemented in your frontend framework.
Prerequisites
- GTM account with container ID (format:
GTM-XXXXXX) - DatoCMS project with GraphQL API access
- Developer access to frontend codebase
- Basic understanding of data layer concepts
Step 1: Create GTM Container
If you don't have a GTM container:
- Go to tagmanager.google.com
- Click Create Account
- Enter:
- Account Name: Your company/project name
- Country: Your location
- Container Name: Your website domain
- Target Platform: Web
- Accept Terms of Service
- Copy your Container ID (GTM-XXXXXX)
Step 2: Install GTM in Frontend
Next.js (App Router)
1. Create GTM Component
Create app/components/GoogleTagManager.tsx:
'use client'
import Script from 'next/script'
export function GoogleTagManager() {
const GTM_ID = process.env.NEXT_PUBLIC_GTM_ID
if (!GTM_ID) {
console.warn('GTM ID not found')
return null
}
return (
<>
{/* GTM Script */}
<Script
id="gtm-script"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${GTM_ID}');
`,
}}
/>
</>
)
}
export function GoogleTagManagerNoScript() {
const GTM_ID = process.env.NEXT_PUBLIC_GTM_ID
if (!GTM_ID) return null
return (
<noscript>
<iframe
src={`https://www.googletagmanager.com/ns.html?id=${GTM_ID}`}
height="0"
width="0"
style={{ display: 'none', visibility: 'hidden' }}
/>
</noscript>
)
}
2. Add to Root Layout
Update app/layout.tsx:
import { GoogleTagManager, GoogleTagManagerNoScript } from './components/GoogleTagManager'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<GoogleTagManager />
</head>
<body>
<GoogleTagManagerNoScript />
{children}
</body>
</html>
)
}
3. Set Environment Variable
Create .env.local:
NEXT_PUBLIC_GTM_ID=GTM-XXXXXX
NEXT_PUBLIC_DATOCMS_API_TOKEN=your-token
Next.js (Pages Router)
1. Update _document.tsx
// pages/_document.tsx
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
const GTM_ID = process.env.NEXT_PUBLIC_GTM_ID
return (
<Html>
<Head>
<script
dangerouslySetInnerHTML={{
__html: `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${GTM_ID}');
`,
}}
/>
</Head>
<body>
<noscript>
<iframe
src={`https://www.googletagmanager.com/ns.html?id=${GTM_ID}`}
height="0"
width="0"
style={{ display: 'none', visibility: 'hidden' }}
/>
</noscript>
<Main />
<NextScript />
</body>
</Html>
)
}
Gatsby
1. Install Plugin
npm install gatsby-plugin-google-tagmanager
2. Configure Plugin
Update gatsby-config.js:
module.exports = {
plugins: [
{
resolve: 'gatsby-source-datocms',
options: {
apiToken: process.env.DATOCMS_API_TOKEN,
},
},
{
resolve: 'gatsby-plugin-google-tagmanager',
options: {
id: process.env.GTM_ID,
includeInDevelopment: false,
defaultDataLayer: { platform: 'gatsby' },
enableWebVitalsTracking: true,
},
},
],
}
3. Environment Variables
Create .env.production:
GTM_ID=GTM-XXXXXX
DATOCMS_API_TOKEN=your-token
Nuxt.js
1. Install Module
npm install @nuxtjs/gtm
2. Configure in nuxt.config.js
export default {
modules: [
'@nuxtjs/gtm'
],
gtm: {
id: process.env.GTM_ID,
enabled: true,
debug: process.env.NODE_ENV !== 'production',
pageTracking: true,
pageViewEventName: 'nuxtRoute',
},
publicRuntimeConfig: {
gtmId: process.env.GTM_ID,
},
}
React SPA (Vite, CRA)
1. Add GTM Script
Update public/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXX');</script>
<!-- End Google Tag Manager -->
</head>
<body>
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
<div id="root"></div>
</body>
</html>
Step 3: Push DatoCMS Data to Data Layer
Create Data Layer Helper
// lib/gtm.ts
export function pushToDataLayer(data: Record<string, any>) {
if (typeof window !== 'undefined') {
window.dataLayer = window.dataLayer || []
window.dataLayer.push(data)
}
}
export function trackDatoCMSPageView(record: any) {
pushToDataLayer({
event: 'datocms_page_view',
contentId: record.id,
contentType: record._modelApiKey,
contentTitle: record.title,
contentSlug: record.slug,
locale: record._locales?.[0] || 'en',
publishedAt: record._publishedAt,
updatedAt: record._updatedAt,
})
}
Use in Components
// app/blog/[slug]/page.tsx
import { trackDatoCMSPageView } from '@/lib/gtm'
export default async function BlogPost({ params }) {
const { data } = await fetchDatoCMSContent(params.slug)
return (
<>
<DataLayerPush record={data.blogPost} />
<article>{/* Content */}</article>
</>
)
}
// components/DataLayerPush.tsx
'use client'
import { useEffect } from 'react'
import { trackDatoCMSPageView } from '@/lib/gtm'
export function DataLayerPush({ record }: { record: any }) {
useEffect(() => {
trackDatoCMSPageView(record)
}, [record])
return null
}
Step 4: Configure GTM Container
Create Variables
In GTM, create these Data Layer Variables:
DL - contentId
- Variable Type: Data Layer Variable
- Data Layer Variable Name:
contentId
DL - contentType
- Variable Type: Data Layer Variable
- Data Layer Variable Name:
contentType
DL - contentTitle
- Variable Type: Data Layer Variable
- Data Layer Variable Name:
contentTitle
DL - locale
- Variable Type: Data Layer Variable
- Data Layer Variable Name:
locale
Create Triggers
DatoCMS Page View
- Trigger Type: Custom Event
- Event name:
datocms_page_view
All Pages
- Trigger Type: Page View
- This trigger fires on: All Pages
Create Tags
GA4 Configuration Tag
- Tag Type: Google Analytics: GA4 Configuration
- Measurement ID:
G-XXXXXXXXXX - Triggering: All Pages
DatoCMS Content View Event
- Tag Type: Google Analytics: GA4 Event
- Event Name:
content_view - Event Parameters:
content_id:\{\{DL - contentId\}\}content_type:\{\{DL - contentType\}\}content_title:\{\{DL - contentTitle\}\}
- Triggering: DatoCMS Page View
Step 5: Test GTM Installation
Use GTM Preview Mode
- In GTM, click Preview
- Enter your website URL
- Click Connect
- Navigate your DatoCMS site
- Verify:
- GTM container loads
- Data layer receives DatoCMS data
- Tags fire correctly
- Variables populate
Check Data Layer
In browser console:
// View data layer
console.table(window.dataLayer)
// Check specific event
window.dataLayer.filter(item => item.event === 'datocms_page_view')
Verify in Network Tab
- Open Chrome DevTools → Network
- Filter by
google-analytics.comorgtm - Verify GTM container loads
- Check tag requests fire
Advanced Configuration
Exclude Preview Mode
Don't track DatoCMS preview sessions:
const isPreview = searchParams.get('preview') === 'true'
if (!isPreview) {
trackDatoCMSPageView(record)
}
Multi-Environment Setup
const GTM_ID =
process.env.VERCEL_ENV === 'production'
? process.env.NEXT_PUBLIC_GTM_PRODUCTION_ID
: process.env.NEXT_PUBLIC_GTM_STAGING_ID
Server-Side Tagging
For advanced tracking, use GTM Server-Side:
// Send data to GTM server
await fetch(process.env.GTM_SERVER_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event: 'datocms_content_view',
contentId: record.id,
}),
})
Troubleshooting
For common issues, see:
- Events Not Firing - Debug tracking issues
- GTM Data Layer - Data layer configuration
Next Steps
- Configure Data Layer - Advanced data layer setup
- Set up GA4 - Add Google Analytics
- Install Meta Pixel - Facebook tracking