Google Tag Manager (GTM) provides a flexible way to manage tracking tags on your DatoCMS-powered website. Since DatoCMS is headless, GTM is implemented in your frontend framework.
Why Use GTM with DatoCMS
Centralized Tag Management:
- Manage all tracking tags in one place
- Deploy tags without code changes
- Version control for tag configurations
- Easy A/B testing setup
DatoCMS-Specific Benefits:
- Track content models without hardcoding
- Dynamic data layer from GraphQL queries
- Flexible event tracking for modular content
- Multi-locale tracking support
Team Collaboration:
- Marketing team can manage tags independently
- Developers set up data layer once
- Non-technical users can add tracking
- Reduced dependency on development team
How GTM Works with DatoCMS
- Frontend Framework → Fetches content from DatoCMS GraphQL API
- Data Layer → Pushes DatoCMS content metadata
- GTM Container → Reads data layer
- Tags → Fire based on data layer values and triggers
- Analytics Platforms → Receive tracking data
GTM Container Setup
Install GTM container in your DatoCMS frontend:
<!-- Google Tag Manager (in <head>) -->
<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 -->
<!-- Google Tag Manager (noscript) (after <body>) -->
<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) -->
Data Layer Structure for DatoCMS
Basic Page Load
window.dataLayer = window.dataLayer || [];
dataLayer.push({
'event': 'datocms_page_view',
'contentId': record.id,
'contentType': record._modelApiKey,
'contentTitle': record.title,
'contentSlug': record.slug,
'publishedAt': record._publishedAt,
'updatedAt': record._updatedAt,
'locale': record._locales?.[0] || 'en',
});
Content with Categories/Tags
dataLayer.push({
'event': 'datocms_content_loaded',
'content': {
'id': post.id,
'type': post._modelApiKey,
'title': post.title,
'category': post.category?.title,
'tags': post.tags?.map(t => t.title).join(','),
'author': post.author?.name,
}
});
E-commerce Products
dataLayer.push({
'event': 'datocms_product_view',
'ecommerce': {
'items': [{
'item_id': product.id,
'item_name': product.title,
'item_category': product.category?.title,
'price': product.price,
'item_brand': product.brand?.name,
}]
}
});
Common GTM Tags for DatoCMS
GA4 Configuration Tag
Tag Type: Google Analytics: GA4 Configuration Trigger: All Pages Configuration:
- Measurement ID:
G-XXXXXXXXXX - Fields to Set:
content_id:\{\{DL - contentId\}\}content_type:\{\{DL - contentType\}\}
GA4 Event Tag
Tag Type: Google Analytics: GA4 Event
Trigger: Custom Event - datocms_content_view
Event Name: content_view
Event Parameters:
content_id:\{\{DL - contentId\}\}content_type:\{\{DL - contentType\}\}content_title:\{\{DL - contentTitle\}\}
Meta Pixel Tag
Tag Type: Custom HTML Trigger: All Pages HTML:
<script>
fbq('track', 'PageView', {
content_id: {{DL - contentId}},
content_type: {{DL - contentType}},
});
</script>
Framework-Specific Implementation
Next.js (App Router)
// app/components/GTM.tsx
'use client'
import Script from 'next/script'
export function GoogleTagManager() {
const GTM_ID = process.env.NEXT_PUBLIC_GTM_ID
if (!GTM_ID) return null
return (
<>
<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}');
`,
}}
/>
</>
)
}
// app/components/GTMDataLayer.tsx
'use client'
import { useEffect } from 'react'
export function GTMDataLayer({ record }: { record: any }) {
useEffect(() => {
window.dataLayer = window.dataLayer || []
window.dataLayer.push({
event: 'datocms_page_view',
contentId: record.id,
contentType: record._modelApiKey,
contentTitle: record.title,
})
}, [record])
return null
}
Gatsby
// gatsby-config.js
module.exports = {
plugins: [
{
resolve: 'gatsby-plugin-google-tagmanager',
options: {
id: process.env.GTM_ID,
includeInDevelopment: false,
defaultDataLayer: { platform: 'gatsby' },
},
},
],
}
// In component
useEffect(() => {
if (typeof window !== 'undefined') {
window.dataLayer.push({
event: 'datocms_content_view',
contentId: post.originalId,
contentType: 'blog_post',
})
}
}, [post])
GTM Variables
Create these variables in GTM:
DL - contentId
- Type: Data Layer Variable
- Data Layer Variable Name:
contentId
DL - contentType
- Type: Data Layer Variable
- Data Layer Variable Name:
contentType
DL - contentTitle
- Type: Data Layer Variable
- Data Layer Variable Name:
contentTitle
DL - locale
- Type: Data Layer Variable
- Data Layer Variable Name:
locale
GTM Triggers
DatoCMS Content View
- Type: Custom Event
- Event name:
datocms_content_view
Specific Content Type
- Type: Custom Event
- Event name:
datocms_page_view - Fires on: Some Custom Events
- Condition:
contentTypeequalsblog_post
Multi-locale Trigger
- Type: Custom Event
- Event name:
datocms_page_view - Condition:
localeequalsen
Testing GTM with DatoCMS
- Preview Mode: Use GTM Preview mode to see data layer
- Check Data Layer: Verify DatoCMS data is pushed correctly
- Test Tags: Ensure tags fire on correct triggers
- Verify Events: Check events in GA4 DebugView
Best Practices
- Consistent Data Layer: Use same structure across all pages
- Content ID: Always include DatoCMS record ID
- Model Type: Track content model for segmentation
- Preview Exclusion: Don't track DatoCMS preview mode
- Version Control: Document GTM container changes
Next Steps
- GTM Setup Guide - Install GTM
- Data Layer Configuration - Set up data layer
- Troubleshoot Tracking - Debug issues