How I Integrated Google Analytics into My Next.js Portfolio (The Simple Way)

Introduction
If you’re like me, building your personal portfolio isn’t just about showcasing projects-it’s also about understanding who’s visiting, where they’re coming from, and what they’re checking out.
For that, Google Analytics is still one of the simplest and most powerful tools out there.
When I set up analytics for my portfolio (built with Next.js App Router), I wanted two things:
- A clean, minimal integration (no extra libraries unless absolutely needed)
- Environment-based configuration (so analytics only runs in production)
Let me walk you through how I did it.
❓Why Add Google Analytics to Your Portfolio?
A lot of developers skip analytics on personal sites because they think:
“It’s just a portfolio, who cares about stats?”
But I believe in tracking the little wins too!
Even if it’s just to see if your latest blog post brought in some traffic, or if recruiters are spending time on your project pages.
⚙️ Setting Things Up: Google Analytics in Next.js (App Router)
Here’s the method I used - directly injecting the Google Analytics script into layout.tsx
using Next.js Script
component.
No external plugins. No fancy wrappers. Just straightforward code.
🪪 Step 1: Get Your Google Analytics ID
If you don’t have it yet:
- Go to Google Analytics
- Set up a new property
- Copy the Measurement ID
It looks like:
G-XXXXXXXXXX
📂 Step 2: Store the Analytics ID in .env
In your .env.local
(for local development) and Vercel environment variables (for production):
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=G-XXXXXXXXXX
Using
NEXT_PUBLIC_
makes the variable accessible on the client side. That’s important because the Google Analytics script runs in the browser.
🧩 Step 3: Inject the Script in layout.tsx
Here’s exactly how I did it:
import { Inter } from "next/font/google"; import Script from "next/script"; import ClientWrapper from "@/components/Common/ClientWrapper"; const inter = Inter({ subsets: ["latin"] }); const GA_ID = process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID!; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en" suppressHydrationWarning> <head> <meta name="viewport" content="width=device-width, initial-scale=1" /> {/* Google Analytics Script */} <Script strategy="afterInteractive" src={`https://www.googletagmanager.com/gtag/js?id=${GA_ID}`} /> <Script id="google-analytics" strategy="afterInteractive" dangerouslySetInnerHTML={{ __html: ` window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', '${GA_ID}', { page_path: window.location.pathname, }); `, }} /> </head> <body className={`dark:bg-black ${inter.className}`}> <ClientWrapper>{children}</ClientWrapper> </body> </html> ); }
🚀 Why Use next/script?
strategy="afterInteractive"
ensures the script loads after the page is interactive, so it doesn’t block rendering.- Using
dangerouslySetInnerHTML
is safe here because this is the exact snippet Google provides. No user-generated content is involved.
🔒 Step 4: Keep It Production-Only (Optional)
Since you’ve set the Analytics ID via environment variables, this code is already safe for production use.
In local development, ifNEXT_PUBLIC_GOOGLE_ANALYTICS_ID
is missing, Google Analytics simply won’t load.
No extra checks are needed.
☁️ Step 5: Push to Vercel
In Vercel:
- Go to your project dashboard
- Open Settings → Environment Variables
- Add:
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=G-XXXXXXXXXX
Now when you deploy, your site automatically uses the production GA ID.
🎯 The Result?
- Minimal code
- No third-party wrappers
- Analytics works seamlessly across all routes (thanks to placing it in
layout.tsx
)
💡 Final Thoughts: Keep It Simple
- A lot of blogs will tell you to install
next-ga
,react-ga
, or other wrappers. - For a portfolio site, that’s usually overkill.
- If you’re using Next.js App Router, injecting the GA script in
layout.tsx
is the cleanest approach.
🔍 What’s Next?
Once you’ve set up analytics, check out:
- Google Analytics Realtime Dashboard
- See which blog posts or projects get attention
- Use the data to improve your content

Happy building! 🚀