Set Up Google Analytics 4 and Search Console for Next.js
Add consent-aware GA4 measurement and configure Search Console ownership, sitemaps, inspection, and indexing checks for a Next.js site.
On this page
Google Analytics 4 and Google Search Console answer different questions. GA4 measures visits and events observed by a tag in the browser. Search Console reports how Google Search crawls, indexes, and surfaces verified site URLs. Installing one does not configure the other.
Google Tag Manager is a third tool: it manages when GA4 and other tags fire. A small site can load the Google tag directly without Tag Manager. Use Tag Manager when centralized tag, trigger, variable, consent, and publishing workflows justify the additional layer.
Separate the three products
| Product | Main purpose | Typical identifier |
|---|---|---|
| Google Analytics 4 | Measure users, page views, events, acquisition, and engagement | Measurement ID beginning G- |
| Google Search Console | Verify ownership and inspect search crawling, indexing, and performance | Domain or URL-prefix property |
| Google Tag Manager | Configure and publish tags and triggers through a container | Container ID beginning GTM- |
A GA measurement ID and a GTM container ID are client-visible configuration, not authentication secrets, but property access and API/service credentials still need protection. Do not publish screenshots containing account email addresses, property details, or verification tokens.
Create the GA4 property and web stream
In Google Analytics Admin, create or select the intended property, add a Web data stream for the canonical production site, and copy its measurement ID. Decide whether Preview deployments should send to a separate property/stream or send nothing. Localhost and changing preview URLs usually should not pollute production reporting.
Store the production measurement ID as a public deployment variable, for example:
NEXT_PUBLIC_GA_ID=G-EXAMPLE123This is a sanitized format. In Next.js, NEXT_PUBLIC_ values are included in browser bundles and frozen at build time, so changing the value requires another production deployment. The Vercel deployment guide covers Preview/Production scoping and redeployment.
Load GA4 with the current Next.js component
Current Next.js documentation provides GoogleAnalytics through @next/third-parties/google. Install the package version compatible with the project's Next.js version:
npm install @next/third-partiesLoad it once in the root App Router layout, only when production configuration and consent allow measurement:
import { GoogleAnalytics } from "@next/third-parties/google";
export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
const gaId = process.env.NEXT_PUBLIC_GA_ID;
const analyticsEnabled =
process.env.VERCEL_ENV === "production" &&
typeof gaId === "string";
return (
<html lang="en">
<body>{children}</body>
{analyticsEnabled ? <GoogleAnalytics gaId={gaId} /> : null}
</html>
);
}The example prevents Vercel Preview deployments from loading GA, but VERCEL_ENV is Vercel-specific. Use the deployment platform's verified environment signal or a dedicated public enable flag. Validate the ID format and do not fall back to a hard-coded real property.
If consent is required, do not render the component unconditionally. Load it only after consent for a basic consent implementation, or implement Google's documented Consent Mode defaults and updates. Google states that Consent Mode communicates consent choices to tags; it does not provide the banner or determine which laws apply. Obtain privacy/legal guidance for the site's users and jurisdictions.
Next.js also supports loading third-party scripts with next/script. Use one installation path—not GoogleAnalytics, a hand-written gtag.js snippet, and GTM simultaneously.
Track App Router navigation once
Next.js's current third-party library guide says GA can automatically track page views when browser history changes if Enhanced Measurement and “Page changes based on browser history events” are enabled in the GA stream.
Choose one approach:
- Enable the documented history-based Enhanced Measurement and verify client-side navigation.
- Or disable the automatic page-view behavior and send one manual page view from a client navigation observer.
Do not keep both. Duplicate tracking commonly comes from a direct Google tag plus a GTM GA tag, or automatic history events plus custom page_view events.
For custom interactions, send only reviewed, non-sensitive event parameters:
"use client";
import { sendGAEvent } from "@next/third-parties/google";
export function DownloadExampleButton() {
return (
<button
onClick={() =>
sendGAEvent("event", "example_download", {
content_type: "code_sample",
})
}
>
Download example
</button>
);
}Never send names, email addresses, form contents, authorization values, database identifiers, uploaded-document details, or full URLs containing sensitive query parameters.
When Google Tag Manager is useful
Google describes Tag Manager as a system for configuring tags, triggers, variables, and a data layer without redeploying site code for each tag change. If GTM is installed, configure GA4 through the container rather than also mounting the direct GA component.
Use preview/debug mode, require appropriate publishing access, name container versions clearly, and review every custom HTML tag. GTM can change production measurement without an application deployment, which is convenient and also a governance risk.
Verify GA4 without inventing results
After a consented production visit:
- Inspect browser network requests and confirm only one Google tag path is active.
- Navigate between multiple App Router pages without full reloads.
- Open GA4 Reports → Realtime and look for the test page/event.
- Use DebugView or Tag Assistant for controlled debugging where appropriate.
- Confirm denied consent prevents or modifies measurement according to the implemented mode.
GA4's Realtime report covers activity from the last 5 and 30 minutes, but limited acquisition processing and attribution apply. Google documents normal report processing as potentially taking 24–48 hours and notes that reports can change during processing. Do not diagnose a fresh installation solely from a standard report immediately after deployment.
Exclude or label internal traffic deliberately. Google warns that an active exclude data filter permanently removes matching data from processing, so test the filter before activation. IP-based internal rules can be difficult for remote teams, dynamic addresses, VPNs, and privacy relays.
Add the site to Search Console
Search Console supports two common property scopes:
- A Domain property includes protocols and subdomains and requires DNS verification.
- A URL-prefix property covers only the entered protocol/host/path prefix and supports several verification methods.
For a canonical custom domain, a Domain property usually provides the broadest view. Add the property, copy the DNS TXT verification value, add it through the authoritative DNS provider, wait for it to resolve, then verify. Keep the TXT record: Search Console periodically checks ownership.
If DNS access is unavailable, use a supported URL-prefix method such as an HTML meta tag. Next.js Metadata can place the verification value in the document head:
import type { Metadata } from "next";
export const metadata: Metadata = {
metadataBase: new URL("https://example.test"),
verification: {
google: process.env.GOOGLE_SITE_VERIFICATION,
},
};example.test is a reserved example. The verification value is not an API credential, but storing environment-specific configuration outside source helps avoid mixing properties. Deploy, view the live homepage source, and confirm the meta tag exists before selecting Verify.
Publish robots.txt and a sitemap
Next.js App Router supports metadata route files for both resources:
// app/robots.ts
import type { MetadataRoute } from "next";
export default function robots(): MetadataRoute.Robots {
return {
rules: { userAgent: "*", allow: "/", disallow: "/private/" },
sitemap: "https://example.test/sitemap.xml",
};
}// app/sitemap.ts
import type { MetadataRoute } from "next";
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: "https://example.test/",
lastModified: new Date("2026-08-12"),
},
];
}Generate canonical Production URLs only. Do not list private, preview, duplicate, redirected, error, or noindex pages. A sitemap tells Google about preferred URLs; it does not force crawling, indexing, or ranking. robots.txt controls crawling access but is not a secure access-control system—private pages still need authentication.
Open /robots.txt and /sitemap.xml on the production domain, check their HTTP status and content, then submit the sitemap URL in Search Console's Sitemaps report.
Inspect and request indexing
Use URL Inspection with the complete canonical URL to see Google's indexed version, user-declared and Google-selected canonical, crawl state, and referring sitemap. If a page has changed, run Test live URL, fix detected access or indexing problems, then request indexing when appropriate.
Google explicitly says an indexing request does not guarantee inclusion. For many new or updated pages, keep the sitemap current rather than submitting every URL manually. Search Console data takes time to accrue and its indexed report is not the same as the live page.
The Page Indexing report groups indexed and excluded URLs with reasons such as redirects, duplicates, noindex, blocked crawling, discovered-not-indexed, or crawled-not-indexed. Investigate patterns and representative URLs; do not assume every excluded URL is an error.
Common mistakes
- Treating GA4 traffic measurement as proof that Google indexed a page.
- Loading GA directly and again through GTM.
- Sending manual page views while Enhanced Measurement sends history-based views.
- Collecting production analytics from localhost and every Preview URL.
- Loading analytics before required consent or assuming Consent Mode supplies a banner.
- Submitting Preview URLs or redirects in the production sitemap.
- Blocking a URL in
robots.txtand expecting that to protect private content. - Removing the Search Console verification record immediately after verification.
- Expecting sitemap submission or URL inspection to guarantee rankings or immediate indexing.
Verification checklist
- GA4, Search Console, and GTM responsibilities are documented separately.
- One GA installation path loads only in the intended environment and consent state.
- App Router navigations produce one page view, not zero or duplicates.
- Analytics events contain no personal, credential, form, or private-document data.
- Internal-traffic filters were tested before permanent activation.
- Search Console ownership covers the canonical domain and remains verifiable.
- Production
robots.txtandsitemap.xmlreturn correct canonical URLs. - Realtime, delayed GA reports, URL Inspection, and Page Indexing are interpreted with their documented delays and limits.
References
Documentation checked on 2026-08-12:
- Next.js: third-party libraries and Google Analytics
- Next.js metadata files, sitemap, and robots conventions
- Google Analytics: Realtime report
- Google Analytics: data freshness
- Google Analytics: internal traffic filters
- Google Analytics: Consent Mode
- Google Tag Manager introduction
- Search Console: verify site ownership
- Search Console: URL Inspection
- Google Search Central: build and submit a sitemap
Related writing
- Deploy a Next.js Application on VercelImport a Next.js repository into Vercel, configure builds and environments, connect a domain, inspect logs, and verify production behavior.
- Edge runtime explained — locality, isolation, and the limits of v8 snippetsWhat shifts when handlers run closer to users: cold starts, memory ceilings, cryptography constraints, and why edge does not magically delete physics.
- Migrate WordPress Content to PostgreSQLExport WordPress content and media, map it into PostgreSQL, build an idempotent importer, and preserve URLs and SEO signals.