Google Tag Manager (GTM) provides centralized management of tracking tags on Storyblok-powered websites. This guide covers GTM implementation for Nuxt.js, Next.js, and custom implementations.
Prerequisites
Before you begin:
- Have a Google Tag Manager account created
- Know your GTM Container ID (format:
GTM-XXXXXXX) - Have a Storyblok space set up
- Be using Nuxt.js, Next.js, or another JavaScript framework
Create GTM Container
- Log in to Google Tag Manager
- Click Create Account (if new) or Add Container
- Enter:
- Account Name: Your company name
- Container Name: Your website name
- Target Platform: Web
- Accept Terms of Service
- Copy your Container ID (GTM-XXXXXXX)
Method 1: Nuxt.js with Storyblok
Step 1: Install GTM Module
npm install @nuxtjs/gtm
Step 2: Configure nuxt.config.ts
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@storyblok/nuxt',
'@nuxtjs/gtm',
],
storyblok: {
accessToken: process.env.STORYBLOK_TOKEN,
},
gtm: {
id: process.env.NUXT_PUBLIC_GTM_ID,
enabled: process.env.NODE_ENV === 'production',
debug: process.env.NODE_ENV === 'development',
loadScript: true,
enableRouterSync: true,
},
runtimeConfig: {
public: {
gtmId: process.env.NUXT_PUBLIC_GTM_ID,
},
},
});
Step 3: Environment Variables
Create .env:
STORYBLOK_TOKEN=your-storyblok-token
NUXT_PUBLIC_GTM_ID=GTM-XXXXXXX
Method 2: Next.js with Storyblok
Step 1: Create GTM Component
Create components/GoogleTagManager.js:
'use client';
import Script from 'next/script';
export default function GoogleTagManager({ gtmId }) {
return (
<>
<Script id="google-tag-manager" strategy="afterInteractive">
{`
(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}');
`}
</Script>
</>
);
}
Step 2: Create GTM NoScript Component
// components/GoogleTagManagerNoScript.js
export default function GoogleTagManagerNoScript({ gtmId }) {
return (
<noscript>
<iframe
src={`https://www.googletagmanager.com/ns.html?id=${gtmId}`}
height="0"
width="0"
style={{ display: 'none', visibility: 'hidden' }}
/>
</noscript>
);
}
Step 3: Add to Root Layout
// app/layout.js
import { storyblokInit, apiPlugin } from '@storyblok/react';
import GoogleTagManager from '@/components/GoogleTagManager';
import GoogleTagManagerNoScript from '@/components/GoogleTagManagerNoScript';
storyblokInit({
accessToken: process.env.NEXT_PUBLIC_STORYBLOK_TOKEN,
use: [apiPlugin],
});
const GTM_ID = process.env.NEXT_PUBLIC_GTM_ID;
export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
{GTM_ID && <GoogleTagManager gtmId={GTM_ID} />}
</head>
<body>
{GTM_ID && <GoogleTagManagerNoScript gtmId={GTM_ID} />}
{children}
</body>
</html>
);
}
Initialize Data Layer for Storyblok
Nuxt 3
Create plugins/storyblok-data-layer.client.ts:
// plugins/storyblok-data-layer.client.ts
export default defineNuxtPlugin(() => {
const route = useRoute();
// Initialize dataLayer
window.dataLayer = window.dataLayer || [];
// Track Storyblok stories
const pushStoryData = (story: any) => {
window.dataLayer.push({
event: 'storyblok_story_loaded',
storyblok: {
storyId: story.id,
storyName: story.name,
storySlug: story.slug,
component: story.content.component,
createdAt: story.created_at,
publishedAt: story.published_at,
},
});
};
return {
provide: {
pushStoryData,
},
};
});
Usage in page:
<!-- pages/[...slug].vue -->
<script setup>
const { slug } = useRoute().params;
const story = await useAsyncStoryblok(slug.join('/'));
const { $pushStoryData } = useNuxtApp();
onMounted(() => {
if (story.value) {
$pushStoryData(story.value);
}
});
</script>
Track Client-Side Navigation
Nuxt 3
The @nuxtjs/gtm module automatically tracks route changes.
Next.js
Create components/GTMPageView.js:
'use client';
import { useEffect } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';
export function GTMPageView() {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
if (typeof window.dataLayer !== 'undefined') {
window.dataLayer.push({
event: 'pageview',
page: pathname + searchParams.toString(),
});
}
}, [pathname, searchParams]);
return null;
}
Configure GTM Container
Basic GA4 Tag Setup
- In GTM, go to Tags > New
- Tag Configuration:
- Tag Type: Google Analytics: GA4 Configuration
- Measurement ID:
G-XXXXXXXXXX
- Triggering:
- Trigger: All Pages
- Save
Create Data Layer Variables
- Go to Variables > New
- Variable Configuration:
- Variable Type: Data Layer Variable
- Create these variables:
| Variable Name | Data Layer Variable Name |
|---|---|
| Storyblok Story ID | storyblok.storyId |
| Storyblok Component | storyblok.component |
| Storyblok Story Name | storyblok.storyName |
Testing & Validation
1. GTM Preview Mode
- In GTM, click Preview
- Enter your Storyblok site URL
- Click Connect
- Verify container loads and tags fire
2. Browser Console
// Check dataLayer
console.log(window.dataLayer);