The Technical SEO Audit Guide

Next.js SEO Audit Checklist for 2026

An auditor's checklist for Next.js 14+ sites built on the App Router. Covers metadata, rendering strategies, dynamic routes, and the technical pitfalls that don't show up in generic SEO guides.

Published April 15, 2026
12 min read

Next.js SEO audit checklist for 2026

Next.js 14+ introduced a metadata API that quietly fixed one of the framework's oldest SEO complaints — and introduced a new one. The generateMetadata export gives you server-side control over every tag in <head>, which is exactly what SEOs have wanted from React frameworks since 2016. The catch is that metadata generation runs separately from your page component, which means metadata and page content can diverge if you're not careful.

This checklist is for anyone auditing a Next.js site — whether you built it, inherited it, or are evaluating it for a client. It covers the App Router specifically (Next.js 13.4+, with 14.x and 15.x as the current production versions). If the site is still on the Pages Router, most of these items still apply, but the implementation details differ — and you should be asking why the migration hasn't happened yet.

The checklist assumes you know what canonical tags, structured data, and Core Web Vitals are. It doesn't assume you know the App Router's API surface.

Metadata and head management

1. Verify generateMetadata is used correctly

In the App Router, metadata is defined via the metadata export (static) or generateMetadata function (dynamic) in layout.tsx or page.tsx files. Check that:

  • Every page-level route has metadata defined — either through the page's own export or inherited from a parent layout
  • Dynamic routes use generateMetadata with the route params to generate unique titles and descriptions per page
  • The generateMetadata function fetches the same data the page component uses (or a subset of it) — if they fetch different data, metadata and content will diverge
// Good: metadata derives from the same data source as the page
export async function generateMetadata({
  params,
}: {
  params: { slug: string }
}): Promise<Metadata> {
  const post = await getPost(params.slug)
  return {
    title: post.title,
    description: post.excerpt,
  }
}

2. Check for missing or duplicate title tags

Crawl the rendered HTML (not the source code — server components render on the server, so you need the final output). Verify every page has:

  • A unique <title> tag
  • The title under 60 characters
  • The primary keyword or topic in the title

Common Next.js pitfall: layouts define a default title, and pages don't override it. This results in every page in that layout segment sharing the same title — which looks like mass duplication to search engines.

3. Audit meta descriptions

Check every page for a meta description. In Next.js, these are set via the description field in the metadata export. Missing descriptions are common on dynamically generated pages where the developer set up generateMetadata for the title but forgot the description.

4. Verify the canonical tag

Next.js App Router generates a self-referencing canonical tag automatically when you use the metadata API. Check that:

  • Every page has a canonical tag
  • The canonical URL is absolute (includes the full domain)
  • The canonical URL matches the page's actual URL (watch for trailing slash mismatches)
  • Pages with query parameters canonicalize to the parameter-free version
// Setting canonical explicitly when needed
export const metadata: Metadata = {
  alternates: {
    canonical: "https://example.com/specific-path",
  },
}

5. Check Open Graph and Twitter card tags

Social sharing metadata is defined in the same metadata export. Verify that key pages (homepage, blog posts, product pages) have:

  • og:title, og:description, og:image
  • twitter:card, twitter:title, twitter:description
  • OG images that are the correct dimensions (1200x630 for standard, 1200x1200 for square)

Next.js 14+ supports the opengraph-image.tsx convention for dynamically generated OG images. If the site uses this, verify the images render correctly — they're generated at request time and can fail silently.

Rendering strategy

Rendering strategy is the single biggest SEO variable in a Next.js site. The wrong choice doesn't break SEO — it just makes it harder than it needs to be.

6. Identify the rendering strategy per route

Next.js App Router supports multiple rendering strategies within the same site:

  • Static (SSG): Pages rendered at build time. Best for content that doesn't change between deployments.
  • ISR (Incremental Static Regeneration): Statically generated, but revalidated on a schedule or on-demand. Best for content that updates periodically.
  • SSR (Server-Side Rendering): Rendered on every request. Best for personalized or real-time content.
  • Client-side only: Rendered in the browser. Not ideal for content that needs to be indexed.

For each route segment, determine which strategy is in use. In the App Router, this is controlled by:

  • export const dynamic = 'force-static' or 'force-dynamic'
  • export const revalidate = 3600 (ISR with time-based revalidation)
  • The presence of cookies(), headers(), or searchParams (forces dynamic rendering)

7. Verify that indexable content renders server-side

Content that must be indexed by search engines should render on the server — either statically or via SSR. Client-side-only content (rendered after JavaScript execution) is riskier. Google can render JavaScript, but it's slower, less reliable, and subject to a rendering queue.

Check the page with JavaScript disabled or use the "View Page Source" to see the initial HTML. If the main content is missing from the source, it's being rendered client-side.

8. Audit 'use client' boundaries

The 'use client' directive pushes a component and everything it imports to the client bundle. Check that:

  • Interactive components (forms, buttons, state-dependent UI) use 'use client'
  • Content-heavy components (article body, product descriptions, metadata-generating components) do NOT use 'use client'
  • The boundary is as low in the component tree as possible — wrap the interactive widget, not the entire page

A common mistake: marking an entire page as 'use client' because it contains a single interactive element. This forces the full page content into the client bundle and delays rendering.

9. Check ISR revalidation intervals

If the site uses ISR, verify the revalidation intervals make sense for the content type:

  • Blog posts: revalidate every 1–24 hours (content changes infrequently)
  • Product pages: revalidate every 1–5 minutes (prices and stock change)
  • Landing pages: revalidate on-demand via revalidatePath() or revalidateTag() after CMS publishes

An ISR interval of 0 effectively becomes SSR. An interval of false is fully static. Both are valid — the question is whether the chosen interval matches the content's update frequency.

10. Audit dynamic route generateStaticParams

For dynamic routes (/blog/[slug], /products/[id]), check whether generateStaticParams is defined. This function tells Next.js which paths to pre-render at build time.

  • If generateStaticParams is missing, pages are generated on-demand at request time (fine, but slower for the first visitor)
  • If it's defined but incomplete (only returning some slugs), unlisted pages are generated on first request
  • If dynamicParams = false is set, unlisted slugs return a 404 — make sure this is intentional

Technical SEO fundamentals

11. Audit the sitemap

Next.js supports sitemap generation via app/sitemap.ts (or app/sitemap.xml/route.ts). Check that:

  • The sitemap exists and is accessible at /sitemap.xml
  • It includes all indexable pages (not just the ones defined in generateStaticParams)
  • It excludes non-indexable pages (noindex pages, auth-gated pages, utility pages)
  • lastmod dates are accurate and update when content changes
  • For large sites, a sitemap index is used with multiple sitemap files
// app/sitemap.ts
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const posts = await getAllPosts()
  return posts.map((post) => ({
    url: `https://example.com/blog/${post.slug}`,
    lastModified: post.updatedAt,
    changeFrequency: "weekly",
    priority: 0.7,
  }))
}

12. Check robots.txt

Next.js supports robots.txt via app/robots.ts. Verify:

  • The file exists at /robots.txt
  • Important paths are not disallowed
  • The sitemap URL is referenced
  • Staging or preview environments have Disallow: / to prevent accidental indexing

13. Validate structured data

Check whether the site implements structured data (JSON-LD). In Next.js, this is typically rendered as a <script type="application/ld+json"> tag within a page or layout component.

  • Verify the JSON-LD is valid using Google's Rich Results Test
  • Check that it's rendered in the initial HTML (server-side), not injected via client-side JavaScript
  • Common schemas for Next.js sites: Article, Product, BreadcrumbList, Organization, WebSite

14. Audit redirects

Next.js handles redirects in next.config.js (static redirects) and via redirect() in server components or middleware (dynamic redirects). Check for:

  • Redirect chains (a redirect pointing to another redirect)
  • Redirect loops
  • 302 (temporary) redirects that should be 301 (permanent)
  • Missing redirects for old URLs after a restructure

15. Verify the 404 page

Next.js App Router uses not-found.tsx to render 404 pages. Verify:

  • The 404 page returns a proper 404 HTTP status code (not a 200 with "page not found" text)
  • The page is useful: includes navigation, search, or links to popular content
  • Custom notFound() calls in dynamic routes return 404 for invalid slugs

16. Check for soft 404s

A soft 404 is a page that visually shows "not found" content but returns a 200 status code. This confuses search engines. In Next.js, this happens when:

  • A dynamic route catches an invalid slug but renders an empty page instead of calling notFound()
  • Error boundaries catch errors and render fallback content with a 200 status
  • Server components return null or empty content for missing data

Performance

17. Run site-wide Lighthouse tests

Don't test just the homepage. Run Lighthouse across every page template at minimum — homepage, listing pages, detail pages, blog posts, utility pages. Next.js sites often have dramatic performance variance between templates.

Pay special attention to:

  • Pages with heavy client-side JavaScript (check the bundle size via Next.js build output)
  • Pages with large images that aren't using the next/image component
  • Pages importing large client-side libraries unnecessarily

18. Verify next/image usage

The next/image component handles responsive images, lazy loading, and format optimization (WebP/AVIF) automatically. Check that:

  • All significant images use next/image instead of raw <img> tags
  • Images have width and height set (prevents CLS)
  • Above-the-fold images use priority={true} to disable lazy loading
  • The image optimization loader is configured correctly for your hosting provider

19. Check for JavaScript bundle bloat

Use the Next.js build output (next build) to check bundle sizes per route. Look for:

  • Routes with unexpectedly large client-side bundles
  • Shared chunks that include code not needed by most pages
  • Third-party libraries that could be replaced with lighter alternatives or loaded dynamically
# View bundle analysis
ANALYZE=true next build

20. Audit Core Web Vitals with field data

Lab data (Lighthouse) tells you what could happen. Field data (Chrome User Experience Report via Search Console) tells you what does happen. Check CrUX data for:

  • LCP: Are real users experiencing LCP under 2.5 seconds?
  • INP: Is the site responsive to interactions under 200ms?
  • CLS: Are layout shifts under 0.1?

If lab and field data disagree significantly, investigate — the discrepancy usually means something behaves differently under real-world conditions (slow networks, low-end devices, third-party scripts loading differently).

Internationalization and edge cases

21. Audit i18n implementation (if applicable)

Next.js App Router handles i18n via middleware-based locale detection and route segments (/en/, /fr/, etc.). If the site is multi-language, verify:

  • Each language version has unique metadata in the correct language
  • hreflang tags are implemented correctly (every language page references all other language versions)
  • The default locale doesn't create duplicate content with the root URL
  • The language switcher doesn't use client-side-only navigation (search engines need crawlable links)

22. Check middleware behavior

Next.js middleware runs on every request before routing. It's powerful but can create SEO problems:

  • Middleware that redirects bots differently than users violates Google's guidelines (cloaking)
  • Middleware that conditionally renders content based on user-agent can create indexing inconsistencies
  • Middleware-based A/B tests can fragment your pages from Google's perspective

Audit the middleware file (middleware.ts) for any request manipulation that might affect how search engines experience the site.

23. Verify trailing slash behavior

Next.js has a trailingSlash option in next.config.js. Whichever option you choose (true or false), it must be consistent:

  • All internal links should use the chosen format
  • The sitemap should use the chosen format
  • Canonical tags should use the chosen format
  • The other variant should redirect (301) to the chosen format

Inconsistent trailing slash behavior creates duplicate content. Google treats /about and /about/ as different URLs.

How Evergreen audits Next.js sites

Evergreen's crawler renders JavaScript-heavy sites the same way search engines do — it executes the JavaScript and captures the rendered output. This means it sees your Next.js site the way Google sees it, not the way your source code reads.

The content audit table shows every page with its metadata, rendering behavior, indexability status, and Lighthouse scores. For Next.js sites, this makes it straightforward to spot the common issues: pages where generateMetadata is missing, routes rendering client-side when they should be static, ISR pages with stale content, and performance outliers by template type.

The visual sitemap shows the site structure as the crawler discovers it — which may differ from what generateStaticParams defines. Pages that exist in the route tree but aren't linked anywhere are visible as disconnected nodes.

Audit your Next.js site in Evergreen → Start free

Frequently asked questions

Is Next.js good for SEO?

Yes — with caveats. Next.js provides server-side rendering, static generation, and a metadata API that gives you full control over SEO-critical elements. The framework itself is not a barrier to SEO. The problems come from implementation: incorrect rendering strategy choices, missing metadata on dynamic routes, and excessive client-side JavaScript. This checklist exists because the framework gives you the tools but doesn't enforce their correct usage.

Should I use SSR or SSG for SEO?

For content that doesn't change between requests (blog posts, documentation, marketing pages), use static generation (SSG) or ISR. Static pages are faster to serve and easier for search engines to process. For content that changes per request (personalized pages, real-time data), use SSR. The rendering strategy should match the content's update frequency, not a blanket preference.

How do I check if Google can render my Next.js pages?

Use Google Search Console's URL Inspection tool and click "Test Live URL." This shows you Google's rendered version of the page. Compare it to what you see in the browser. If content is missing from Google's render, it's likely behind a 'use client' boundary or loaded asynchronously after the initial server render.

Does the App Router have SEO advantages over the Pages Router?

The App Router's metadata API (generateMetadata) is more flexible and composable than the Pages Router's Head component. Layouts can define default metadata that pages override, which reduces the chance of missing metadata on new pages. Server Components also reduce client-side JavaScript by default, which helps performance. The App Router is the recommended approach for new Next.js projects — the Pages Router is still supported but no longer the default.

Your next step: see how your Next.js site performs → Create free account

Related Topics in The Technical SEO Audit Guide

The Technical SEO Checklist for 2026

A practical technical SEO checklist covering crawlability, indexation, Core Web Vitals, structured data, JavaScript rendering, and AI search visibility — updated for 2026.

How to Find and Fix All Broken Links on Your Site

A practical guide to finding, prioritizing, and fixing broken links across your website to improve user experience and SEO performance.

The Complete Website Audit Checklist for Agencies (2026)

A 25-point website audit checklist built for agencies managing multiple client sites. Covers structure, content, performance, and reporting workflows.

How to Run a Bulk Lighthouse Test on Your Entire Site

Stop testing one page at a time. Run Lighthouse across your entire site to find the pages dragging down performance — and fix them systematically.

How to Find Noindex Pages Blocking Your Rankings

Accidental noindex tags silently remove pages from Google. Here's how to find every noindex directive on your site — and tell the intentional ones from the mistakes.

Technical SEO Audit Guide for Headless Websites

Headless websites separate content from presentation, and that separation introduces SEO audit challenges that monolithic sites don't have. This guide covers the methodology for auditing any headless stack.

The Comprehensive Astro SEO Checklist

Astro ships fast HTML by default, but fast isn't the same as optimized. This checklist covers every SEO consideration specific to Astro 4.x+ — from Islands to View Transitions to content collections.

Lighthouse Score for Your Entire Site: Tools and Methods

Lighthouse tests one page at a time. Here are five ways to get scores for every page on your site — from free CLI tools to SaaS dashboards — and when each approach makes sense.

Automated SEO Monitoring: Set Up Daily Site Audits

One-off audits find problems after they've already cost you traffic. Continuous monitoring finds them as they happen. Here's how to set up daily automated SEO monitoring that catches regressions before rankings suffer.

Shareable SEO Reports: How to Send Audits Clients Actually Read

Most SEO reports are PDFs that clients download, glance at, and forget. Shareable URL-based reports stay current, require no login, and get acted on. Here's why and how.

JavaScript Rendering Audit Checklist

A checklist for auditing JavaScript-rendered pages: crawl accessibility, metadata after render, lazy-loaded content, and the tools to verify what Google actually sees.