# Next.js SEO for AI agents

Next.js gives you Server Components, `generateMetadata` and typed route handlers, yet live Next.js sites routinely fail search and AI crawler checks because of top-level `'use client'` pages, missing `metadataBase` canonicals and unescaped JSON-LD.

- Install skills: `npx skills add subinternal/clickd`
- Ask your agent: "Audit our live Next.js site with clickd_brief and clickd_check (kind: "agent"), fix client-only pages, generateMetadata canonicals and JSON-LD in app/, and rescan."
- MCP tools used: `clickd_brief`, `clickd_check`, `clickd_schema_create`, `clickd_rescan`

## What breaks most often on Next.js

- **Top-level 'use client' route shells** (`content-in-html`): Marking `app/*/page.tsx` with `'use client'` and fetching copy in `useEffect` ships an empty HTML shell that non-JS AI crawlers cannot read.
- **Missing metadataBase and per-route canonicals** (`canonical`): Inheriting the root layout’s `metadata` without setting `alternates.canonical` per dynamic route leaves dozens of pages missing or sharing canonicals.
- **Unescaped JSON-LD script blocks** (`structured-data`): Rendering `<script type="application/ld+json">` without escaping `<` as `\u003c` risks broken markup or script injection when titles contain special characters.

## The Next.js agentic SEO loop

1. **Check non-JS HTML** (`clickd_check`): Run clickd_brief and clickd_check (kind: "agent") on your deployed Next.js routes to see what ships in raw HTML.
2. **Move copy to Server Components** (`technical-seo`): Keep `page.tsx` as an async Server Component and isolate interactive widgets into small leaf client components.
3. **Wire generateMetadata & sitemap.ts** (`page-system`): Set `metadataBase` in `app/layout.tsx`, export `generateMetadata` on dynamic routes, and build `app/sitemap.ts`.
4. **Deploy & rescan live** (`clickd_changes`): Ship to Vercel or your host, then call clickd_rescan and clickd_changes to verify every route passes.

## Worked pattern (app/services/[slug]/page.tsx)

Server-rendered copy, per-route canonical metadata, and escaped JSON-LD from one data lookup.

```
import type { Metadata } from 'next';
import { getService } from '@/lib/services';

export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
  const { slug } = await params;
  const svc = await getService(slug);
  return {
    title: `${svc.title} · Example Co`,
    description: svc.summary,
    alternates: { canonical: `https://example.com/services/${slug}` },
  };
}

export default async function ServicePage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const svc = await getService(slug);
  const ld = { '@context': 'https://schema.org', '@type': 'Service', name: svc.title, description: svc.summary };
  return (
    <main>
      <h1>{svc.title}</h1>
      <p>{svc.answerFirst}</p>
      <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(ld).replace(/</g, '\\u003c') }} />
    </main>
  );
}
```

## Prompts to run on Next.js

- **Audit SSR vs client components**: "Run clickd_check (kind: "agent") across our key Next.js routes and refactor any page fetching primary copy inside useEffect into an async Server Component."
- **Fix generateMetadata across app/**: "Find every Next.js route failing title, description or canonical rules in clickd_pages and wire generateMetadata with metadataBase."
- **Generate app/sitemap.ts & llms.txt**: "Build app/sitemap.ts and app/llms.txt/route.ts from our route data so every public page is listed automatically, then verify live."

## Paired skills

- [Technical SEO](https://clickd.com/skills/technical-seo): Audits and fixes crawlability, indexing, robots.txt, XML sitemaps, canonicals, redirect chains, server-rendered HTML and security headers in your site’s codebase, then checks every fix live with clickd.
- [Page system](https://clickd.com/skills/page-system): Builds a site’s page templates and shared components so crawlers and assistants read every page well, and proves each pattern with clickd. About structure and spacing, not color, type or brand.
- [Schema markup](https://clickd.com/skills/schema-markup): Generates, wires and validates JSON-LD structured data (Organization, LocalBusiness, Product, Service, Article, FAQPage and BreadcrumbList) from the visible facts on your pages, checked live with clickd.
- [llms.txt](https://clickd.com/skills/llms-txt): Adds a /llms.txt to a site, a plain text outline for AI assistants built from the site’s own pages and facts, with tests that catch a missing page, and checks it with clickd.

## Questions

### Does Next.js Server-Side Rendering guarantee AI crawlers can read my page?

Not automatically. In Next.js App Router, client components pre-render their initial synchronous JSX, so any text loaded inside `useEffect` or client-only queries is absent from initial HTML. `clickd_check` (`kind: "agent"`) tests the exact HTML delivered without JavaScript.

### Does this work with both Next.js App Router and Pages Router?

Yes. Your coding agent inspects your repository first (`app/` vs `pages/`) and uses `generateMetadata` on App Router or `getServerSideProps` / `getStaticProps` with `next/head` on Pages Router.
