Install Google Tag Manager with DatoCMS | OpsBlu Docs

Install Google Tag Manager with DatoCMS

Step-by-step guide to installing and configuring Google Tag Manager on DatoCMS-powered websites.

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:

  1. Go to tagmanager.google.com
  2. Click Create Account
  3. Enter:
    • Account Name: Your company/project name
    • Country: Your location
    • Container Name: Your website domain
    • Target Platform: Web
  4. Accept Terms of Service
  5. 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:

  1. DL - contentId

    • Variable Type: Data Layer Variable
    • Data Layer Variable Name: contentId
  2. DL - contentType

    • Variable Type: Data Layer Variable
    • Data Layer Variable Name: contentType
  3. DL - contentTitle

    • Variable Type: Data Layer Variable
    • Data Layer Variable Name: contentTitle
  4. DL - locale

    • Variable Type: Data Layer Variable
    • Data Layer Variable Name: locale

Create Triggers

  1. DatoCMS Page View

    • Trigger Type: Custom Event
    • Event name: datocms_page_view
  2. All Pages

    • Trigger Type: Page View
    • This trigger fires on: All Pages

Create Tags

  1. GA4 Configuration Tag

    • Tag Type: Google Analytics: GA4 Configuration
    • Measurement ID: G-XXXXXXXXXX
    • Triggering: All Pages
  2. 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

  1. In GTM, click Preview
  2. Enter your website URL
  3. Click Connect
  4. Navigate your DatoCMS site
  5. 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

  1. Open Chrome DevTools → Network
  2. Filter by google-analytics.com or gtm
  3. Verify GTM container loads
  4. 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:

Next Steps