Use when asked to make a Next.js App Router application crawlable, indexable, and structurally optimized for search with green Core Web Vitals. Configures sitemaps, robots, metadata, structured data, canonicals, internal linking, and CWV budgets, then validates with build, curl, and Lighthouse evidence. Not for security-header configuration or remote mutations.
Scanned 9/2/2026
Install to Claude Code
npx -y skills add OutlineDriven/odin-claude-plugin --skill optimise-seo --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Optimise Seo?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/outlinedriven-optimise-seo)More formats (shields.io, HTML) on the badges page.
---
name: optimise-seo
description: 'Use when asked to make a Next.js App Router application crawlable, indexable, and structurally optimized for search with green Core Web Vitals. Configures sitemaps, robots, metadata, structured data, canonicals, internal linking, and CWV budgets, then validates with build, curl, and Lighthouse evidence. Not for security-header configuration or remote mutations.'
---
# Optimise SEO
## Contract
| Field | Bound contract |
|---|---|
| Trigger | Improve SEO, Next.js SEO, sitemap, robots, meta tags, structured data, canonical URL, hreflang, Core Web Vitals, crawlability, indexability. |
| Authority | Reversible-local: change only named local project source files (App Router pages and layouts, `app/sitemap.ts`, `app/robots.ts`, `app/manifest.ts`, `next.config.ts`, JSON-LD components, `public/` assets). No remote mutations. Audit-only mode reads a deployed origin without editing files. Record each file's prior content before the first edit and state that rollback path. |
| Side effect | Applies or recommends SEO and technical changes within the named scope. No visual redesigns, component styling, or layout changes; no content rewriting; no security-header configuration; llms.txt and AI-agent readability are out of scope. |
| Done | A pass or fail checklist with per-check command evidence: build, curl header and meta checks, and Lighthouse. Each item is marked pass with evidence or fail with a named blocker. Done does not require green Core Web Vitals when external gates are unreachable; those items are marked blocked. |
## Inputs
Required: the repo root of the Next.js App Router app to change (edit mode), or a deployed origin URL (audit-only mode); the canonical production host (apex or www).
Optional: the locale list (multi-locale steps are skipped without it); which routes are staging, admin, thin, or private; which findings to apply versus only recommend.
With neither a repo nor an origin URL, stop without running.
## Procedure
1. **Bound scope and route indexing policies.** Determine the mode: edit (repo root provided) or audit-only (deployed origin only). Enumerate routes and decide index intent for each: public routes default to `index, follow`; staging, admin, thin, and private routes get explicit `noindex` (`metadata.robots` for HTML routes; `X-Robots-Tag` headers for non-HTML or whole staging environments). Record the decision per route; do not touch styling or layout. A thin page is `noindex`ed and omitted from the sitemap until it carries unique content, then indexed and linked internally. Done when: every route has a recorded index intent, the mode is confirmed, and no styling or layout is touched.
2. **Configure crawl foundations.** In edit mode, write or update: `app/sitemap.ts` listing every public URL as absolute URLs with `lastModified` derived from the freshest content date (never hardcoded); above 50,000 URLs, export `generateSitemaps()` for a sitemap index. `app/robots.ts` allowing `/`, disallowing private paths, and linking the sitemap URL. Canonicals: pick one host, one casing, one trailing-slash policy; set `alternates.canonical` on every page; 308-redirect the non-canonical host unless the platform already edge-redirects. Redirects: permanent moves use 301 or 308, temporary use 302 or 307, pointing straight at the final URL, never chained. Status codes: a missing page returns a real 404 (a 200 with a friendly message is a soft 404); maintenance windows return 503 with `Retry-After`. In audit-only mode, verify these with curl against the deployed origin. Done when: sitemap, robots, canonicals, redirects, and status codes are all configured (edit) or verified (audit-only) per the above rules.
3. **Configure metadata and structured data.** In edit mode, write or update: unique title (50 to 60 chars) and unique description (150 to 160 chars) per page via static `metadata` or `generateMetadata`. OpenGraph and Twitter Card tags on every page with a 1200x630 image. Favicons: `favicon.ico`, `icon.svg`, `apple-touch-icon.png`. JSON-LD through one `JsonLd` script component: define each entity once with a stable `@id` (for example `https://<host>/#organization`, `/#website`, `/#person`) inside a single `@graph` emitted from the root layout or homepage; per-page schema references entities by `@id` instead of duplicating them inline. Homepage: `Organization` (with `logo`) and `WebSite`. Inner pages: `BreadcrumbList`. Where the content type matches: `Article` or `BlogPosting` (author is the `Person` `@id`, publisher is the `Organization` `@id`), `Product`, `FAQPage`; `ProfilePage` on identity pages. Fill recommended fields, not only required ones. In audit-only mode, verify with curl. Done when: unique titles and descriptions, OpenGraph and Twitter Card tags with favicons, and JSON-LD with stable `@id` entities are all in place (edit) or verified (audit-only).
4. **Enforce semantics, internal linking, and CWV budgets.** In edit mode: one h1 per page with a logical h2 to h6 hierarchy; descriptive alt text on all images; internal links between related pages; every indexable page reachable from navigation, footer, or the sitemap (orphans get a crawl path or are `noindex`ed and dropped from the sitemap). CWV targets: LCP below 2.5s (hero image with `priority`), INP below 200ms, CLS below 0.1 (width and height on all media), TTFB below 600ms. Recompress oversized `public/` images in place, keeping filenames and formats so references stay valid. Do not move indexable content behind a client-only render. For multi-locale sites (when the locale list is provided): pick one URL pattern for all locales (subdirectory by default), declare `hreflang` with BCP 47 codes reciprocally (every alternate lists every other alternate including itself, plus a self-reference and `x-default`), translate everything in the head and structured data per locale, and never auto-redirect locale by IP geolocation. In audit-only mode, verify with curl and Lighthouse. Done when: semantics, internal linking, CWV budgets, and hreflang (when applicable) are configured (edit) or verified (audit-only).
5. **Execute evidence-based validation.** Run each check and mark pass or fail with command output:
| Check | Command | Expected |
|---|---|---|
| Production build | `pnpm run build` (or the repository build command) | exits 0 |
| Response headers | `curl -sI <url>` | correct status, redirects, canonical host |
| Served HTML metadata | `curl -s <url>` piped to `grep -F -e canonical -e "og:" -e "twitter:" -e "application/ld+json"` | tags present in the served source |
| Robots | `curl -s <origin>/robots.txt` | expected allow and disallow and sitemap link |
| Sitemap | `curl -s <origin>/sitemap.xml` | indexed routes, absolute URLs, fresh `lastmod` |
| Lighthouse | `pnpm dlx lighthouse <url> --only-categories=seo,performance --output=json` | SEO and Performance scores, or blockers listed |
External gates (Rich Results Test, Search Console) may be unreachable from the skill's environment. Mark those items as blocked with the exact reason; do not fabricate or estimate metrics. Done when: every check is marked pass with command evidence, fail with a named blocker, or blocked with the exact reason. Done does not require green Core Web Vitals when the Lighthouse or external gates are unreachable; those items are blocked, not failed.
## Failure and recovery
- Build failure after an edit: restore that file's recorded prior content; never leave the production build red. Rollback is restoring the recorded prior content or the VCS state of the touched files.
- Missing deployed origin for audit-only: the origin URL is required for audit-only mode. If it is missing or unreachable, mark the audit-only checks as blocked with the exact reason.
- External search gates unreachable: Rich Results Test and Search Console require browser access or post-deploy verification. Mark these as blocked with the exact reason; do not claim Done while pretending they passed.
- Findings conflict: apply the indexing policy, `noindex` plus removal from the sitemap, and record the decision; do not widen into rewriting content or redesigning pages.
- A live hreflang set is not reciprocal: fix reciprocity before shipping; search engines ignore non-mutual sets, so a partial set must not ship.
- Blockers remain: the terminal result is a blocker list with exact URLs and owner or action per item; Done is never declared with failing or missing evidence.
## Output
A completed pass or fail checklist with per-check command evidence, the list of applied file changes each with recorded prior content for rollback (edit mode), a recommendation-only list for findings not applied, and remaining blockers with exact URLs and owner or action. Done is claimed only when every checklist item is pass, fail with a named blocker, or blocked with an exact reason.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!