Google Tag Manager (GTM) simplifies managing tracking codes on your Directus-powered site. Since Directus is headless, GTM is installed on your frontend application.
Before You Begin
- Create GTM Container
- Go to Google Tag Manager
- Create a new container
- Select "Web" as target platform
- Note your Container ID (format:
GTM-XXXXXXX)
Method 1: Next.js + Directus
App Router (Next.js 13+)
// app/components/GoogleTagManager.tsx
'use client';
import Script from 'next/script';
export default function GoogleTagManager({ gtmId }: { gtmId: string }) {
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','${gtmId}');
`,
}}
/>
</>
);
}
export function GoogleTagManagerNoScript({ gtmId }: { gtmId: string }) {
return (
<noscript>
<iframe
src={`https://www.googletagmanager.com/ns.html?id=${gtmId}`}
height="0"
width="0"
style={{ display: 'none', visibility: 'hidden' }}
/>
</noscript>
);
}
Add to layout:
// app/layout.tsx
import GoogleTagManager, { GoogleTagManagerNoScript } from '@/components/GoogleTagManager';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<GoogleTagManager gtmId={process.env.NEXT_PUBLIC_GTM_ID!} />
</head>
<body>
<GoogleTagManagerNoScript gtmId={process.env.NEXT_PUBLIC_GTM_ID!} />
{children}
</body>
</html>
);
}
Initialize Data Layer
// app/components/DataLayerInit.tsx
'use client';
import { useEffect } from 'react';
export function DataLayerInit({ initialData }: { initialData?: any }) {
useEffect(() => {
window.dataLayer = window.dataLayer || [];
if (initialData) {
window.dataLayer.push(initialData);
}
}, [initialData]);
return null;
}
Method 2: Vue/Nuxt + Directus
// plugins/gtm.client.ts
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig();
if (!config.public.gtmId) return;
// Initialize data layer
window.dataLayer = window.dataLayer || [];
// Load GTM
(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', config.public.gtmId);
});
Data Layer with Directus Content
Push Directus Item Data
// utils/dataLayer.ts
export function pushDirectusItem(item: any) {
if (typeof window === 'undefined') return;
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'directus_content_view',
content: {
type: item.__collection,
id: item.id,
title: item.title || item.name,
status: item.status,
date_created: item.date_created,
user_created: item.user_created?.id,
},
});
}
// Usage
'use client';
import { useEffect } from 'react';
import { pushDirectusItem } from '@/utils/dataLayer';
export function ArticlePage({ article }) {
useEffect(() => {
pushDirectusItem(article);
}, [article]);
return <article>{/* Content */}</article>;
}
Next Steps
- Set up Data Layer - Configure custom data layer
- Configure GA4 in GTM - Add Google Analytics via GTM
- Troubleshoot Events - Debug tracking issues
For general GTM concepts, see Google Tag Manager Guide.