Install Google Tag Manager on Directus Sites | OpsBlu Docs

Install Google Tag Manager on Directus Sites

Complete guide to installing GTM on Directus-powered sites using Next.js, Vue, React, and other frontend frameworks.

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

  1. 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

For general GTM concepts, see Google Tag Manager Guide.