Optimize Google Analytics with Tag Manager in Next.js 15

Master Google Analytics integration with Next.js 15.5.5 and Google Tag Manager to ensure GDPR compliance and avoid…

·Matija Žiberna·
Optimize Google Analytics with Tag Manager in Next.js 15

⚡ Next.js Implementation Guides

In-depth Next.js guides covering App Router, RSC, ISR, and deployment. Get code examples, optimization checklists, and prompts to accelerate development.

No spam. Unsubscribe anytime.

When you set up Google Analytics tracking in Next.js 15.5.5 with Google Tag Manager, you get two cryptic IDs: a GTM ID like GTM-PSB7763V and a GA4 Measurement ID like G-RKCKVVHE9N. Most developers copy-paste both into their code without understanding what either one does or how they connect. The result is confusion, duplicate tracking, and reports that don't make sense.

Here's the truth: these IDs represent two different things, and conflating them breaks your analytics. The GTM ID is your container—the hub that orchestrates all tracking. The GA4 Measurement ID is just one destination that receives data from that hub. Google Analytics isn't special; it's one tool in a system. Once you understand this architecture, the whole setup clicks into place.

I discovered this distinction the hard way after doubling up both the direct GA snippet and Google Tag Manager on our site, which tanked our reports with duplicate events. After rebuilding with a clear mental model—GTM as the brain, Analytics as one of its hands—everything worked. If you're building with Next.js 15.5.5 and already have a GDPR-friendly consent layer, this guide walks you through the cleaner approach: let Google Tag Manager be the single script your app loads, and let the container decide what gets sent where.

Why the Two IDs Exist (And Why It Matters)

GTM ID: Your Connection to the Hub

Think of Google Tag Manager as a data switchboard in the cloud. Your website sends events to GTM using the GTM ID, and the container sitting behind that ID decides where to route that data. When you load GTM-PSB7763V on your site, you're telling your browser: "Connect to this specific container." That container is configured in the GTM interface to listen for events.

Once it receives data, it has rules we call triggers—things like "when a user lands on the checkout page, send this data to Google Analytics." Google Analytics is one possible destination. Facebook Pixel is another. Segment, TikTok, Hotjar—they're all just destinations that plug into the same GTM hub.

GA4 Measurement ID: A Configuration Inside GTM

The GA4 Measurement ID (G-RKCKVVHE9N) doesn't live in your Next.js code at all—it lives inside that GTM container. When you open GTM and create a "Google Tag," you paste that ID into a form, and GTM handles sending data to Analytics on your behalf.

Your site never talks directly to GA4. Your site talks to GTM, and GTM routes the conversation.

Why Two Snippets Break Everything

This is why loading both the GTM snippet and the GA4 snippet causes chaos. You'd be sending the same event twice: once directly to Analytics, and once through GTM. GTM never gets a chance to be the hub because you've split the traffic.

The solution is beautifully simple: load only the GTM ID in Next.js. Strip out the direct GA snippet. Let GTM own the connection to Analytics, and you'll have a single, clean pipeline.

Implementation: Make GTM the Single Source of Truth

Step 1: Load GTM Instead of Direct GA

Strip the direct GA snippet from your App Router layout and give GTM complete ownership. In my case the consent-aware loader lives in src/app/layout.tsx.

// File: src/app/layout.tsx
<GA4Consent gtmId="GTM-PSB7763V" />

The component behind that call sits at src/components/analytics/ga4-consent.tsx. It waits for our cookie banner to flip consent to true, then injects the standard Google Tag Manager bootstrap snippet plus the <noscript> iframe. Because we no longer pass a gaId, the direct gtag.js loader never runs, and duplicate page views disappear.

The consent handler also pushes a default_consent_granted event into dataLayer, so GTM reads analytics storage as granted without extra plumbing.

Step 2: Configure GA4 Inside GTM

With the app ready, move into Google Tag Manager and wire GA4 to the container.

  1. Open https://tagmanager.google.com
  2. Select the workspace for GTM-PSB7763V
  3. Add a new tag and rename it to something obvious like "Google Tag – GA4"
  4. Choose the Google Tag type
  5. Paste your existing measurement ID G-RKCKVVHE9N
  6. Leave the advanced configuration alone unless you have a reason to tweak data layer variables
  7. Add the default "All Pages" trigger

Step 3: Test Before Publishing

Hit Preview and feed in your staging URL. GTM's debug overlay will show the consent event followed by the Google Tag firing exactly once. This is the moment you know the plumbing is correct.

Step 4: Publish the Container

When everything looks right, click Submit → Publish so the live container matches your workspace. At this point Google Tag Manager is bootstrapping gtag.js for you, sending page views to the same GA4 property you relied on before.

Fire up the revived Tag Assistant extension and you'll see the container GTM-PSB7763V, the Google Tag ID GT-WBKDQQKB, and the GA4 property G-RKCKVVHE9N all tied together. A quick glance at GA Realtime confirms you're getting single hits per page view.

You now understand the architecture: GTM is the hub, Analytics is one destination plugged into that hub. By loading only the GTM ID in Next.js 15.5.5 and stripping the direct GA snippet, you've eliminated duplication, stayed compliant with your consent layer, and kept the GA4 property history intact. More importantly, you've built a system that scales. Next week, when a stakeholder asks you to add Facebook Pixel or TikTok tracking, you won't touch your codebase—you'll just create a new tag in GTM and add another destination to the hub.

Now that GTM is wired up and passing data to Analytics, the next logical step is learning how to implement custom tags and triggers to track specific user engagement. If you want a deep dive into the GTM interface and how to build out more sophisticated tracking beyond page views, check out How to Use Google Tag Manager Web Interface.

This is the power of thinking in terms of containers and destinations instead of separate tracking codes. Let me know in the comments if you have questions, and subscribe for more practical development guides. Thanks, Matija

0

Comments

Leave a Comment

Your email will not be published

10-2000 characters

• Comments are automatically approved and will appear immediately

• Your name and email will be saved for future comments

• Be respectful and constructive in your feedback

• No spam, self-promotion, or off-topic content

Matija Žiberna
Matija Žiberna
Full-stack developer, co-founder

I'm Matija Žiberna, a self-taught full-stack developer and co-founder passionate about building products, writing clean code, and figuring out how to turn ideas into businesses. I write about web development with Next.js, lessons from entrepreneurship, and the journey of learning by doing. My goal is to provide value through code—whether it's through tools, content, or real-world software.