seo-check

/seo-check · SEO checker skill for Claude Code · MIT · zero dependencies

Most SEO disasters ship as innocent‑looking diffs.

/seo-check is an open‑source SEO checker skill for Claude Code. It reads your uncommitted changes for SEO regressions, then crawls the routes they touch the way Googlebot does — and gives you one verdict before you commit.

/plugin marketplace add AnTIdoTe003/claude-seo-check
/plugin install seo-check@claude-seo-check
View the source
app/layout.tsx+2 −0 · uncommitted
@@ -8,5 +8,7 @@ export const metadata: Metadata = {
88 title: 'Acme — Furniture that lasts',
99 description: 'Solid oak tables, chairs and shelving, made to order.',
10+ // TODO remove before launch
11+ robots: { index: false, follow: false },
NOINDEX_META — crawl confirms noindex, nofollow on / and /tables. This is the root layout: every route inherits it.
1012 metadataBase: new URL('https://acme.com'),
1113 alternates: { canonical: '/' },
1214 }

crawl · googlebot-smartphone · http://localhost:3000 · 2 routes affected by this layout

GET/200meta robots: noindex, nofollow
GET/tables200meta robots: noindex, nofollow

Fix before committing — 1 blocker

app/layout.tsx:11robots: { index: false } added to the root layout. Crawler confirms NOINDEX_META on 2 of 2 routes. This deindexes the whole site.

Fix: remove it, or gate it on process.env.VERCEL_ENV !== 'production'.

VERIFIED CLEAN title, description, canonical, metadataBase, structured data.

@@ what an innocent diff can do @@

Seven one‑line changes that cost rankings

Each one looks harmless in code review. The checklist the audit reads ranks them by what they actually cost: a blocker deindexes pages, blocks crawling, 404s live URLs or destroys structured data; a warning is a likely loss.

+robots: { index: false },app/layout.tsx · left over from staging

Deindexes every route under the layout. The #1 accidental SEO kill. Often gated on an env check that no longer matches.

Blocker
+Disallow: /public/robots.txt · app/robots.ts

Tells every crawler to skip the whole site. A Disallow: meant for one path matches by prefix, so /guide also blocks /guides/*.

Blocker
app/guides/[slug]/page.tsxdeleted · no redirect added

Every URL under it starts returning 404. Rankings and backlinks go with it unless a 301/308 lands in next.config, vercel.json or middleware.

Blocker
+"aggregateRating": { "ratingValue": 4.8 },trailing comma before the closing brace

Invalid JSON-LD silently drops every rich result. Stars, FAQs, breadcrumbs — gone, with nothing in the build log.

Blocker
alternates: { canonical: '/pricing' },or pointed at a different page

Google may index some other URL instead. Removed canonicals let duplicates compete; wrong ones hand the ranking to the wrong page.

Warning → blocker
+'use client'top of app/blog/[slug]/page.tsx

The article text leaves the initial HTML. Google renders JS eventually; Bing, AI crawlers and link previews never see it.

Warning
permanent: truefalsenext.config redirects()

308 becomes 307. Temporary redirects stop consolidating link equity into the new URL.

Warning

@@ how it works @@

Two passes, then a verdict

The audit runs inside Claude Code against whatever is uncommitted. It reports; it doesn't change your code unless you ask.

1 static audit

Read the diff the way an SEO would

Scopes git diff to SEO‑relevant files — pages, layouts, metadata, robots, sitemaps, next.config, vercel.json, middleware, redirects — and maps each changed file to a URL route. Then greps the diff against the regression checklist and reads the full context of every hit, so a noindex behind a staging guard isn't a false alarm.

2 live crawl

Fetch the routes as Googlebot

Requests every affected route from your dev server with a Googlebot‑smartphone user agent and records exactly what a search engine receives from the initial HTML. Pass a production URL and it fetches each route on both origins and diffs every signal — the most direct evidence of “did my change break anything”.

3 verdict

One line first, evidence after

Blockers come with file:line, the crawler flag, and a concrete fix. Pre‑existing issues are listed separately from regressions. Checks it couldn't run are named, never omitted, so a clean result is credible.

SEO‑safe to commit
Commit with caution — N warnings
Fix before committing — N blockers

@@ what the crawler reports @@

Everything a search engine receives

Per route, from the initial HTML response — the part indexing depends on most, and the only part non‑Google crawlers ever see.

@@ install @@

Install in two lines

Needs Node ≥ 18 on your PATH for the crawler. Works with Next.js (app and pages router), Astro and plain HTML sites out of the box.

Pluginrecommended · inside Claude Code

/plugin marketplace add AnTIdoTe003/claude-seo-check
/plugin install seo-check@claude-seo-check

Manualpersonal skill · available in every project

git clone https://github.com/AnTIdoTe003/claude-seo-check.git
ln -s "$(pwd)/claude-seo-check/skills/seo-check" ~/.claude/skills/seo-check
/seo-check
audit whatever is uncommitted
/seo-check https://your-site.com
…and diff every route against production
/seo-check /pricing /blog/some-post
force specific routes into the audit
/seo-check --staged
only staged changes
/seo-check --branch main
diff against the merge‑base with main
/seo-check --full
also crawl the homepage and key sitemap routes

It auto‑detects your dev server on common ports, or starts and stops one itself.

@@ crawler, standalone @@

The crawler works without Claude

crawl.mjs is one zero‑dependency Node script. Point it at any URL, or wire it into a git hook or CI with its exit codes.

# audit three routes on your dev server
node skills/seo-check/scripts/crawl.mjs --base http://localhost:3000 / /about /blog/my-post

# diff local against production
node skills/seo-check/scripts/crawl.mjs --base http://localhost:3000 --compare https://prod.com /

# any public URL, machine-readable
node skills/seo-check/scripts/crawl.mjs https://example.com/page --json
--base <origin>
origin that bare route paths resolve against
--compare <origin>
fetch each route on a second origin and diff all signals
--ua <name>
googlebot-mobile (default), googlebot-desktop, chrome, or any string
--timeout <ms>
per‑request timeout, default 20000
--no-robots
skip robots.txt and sitemap checks
--json
machine‑readable output
exit 0 clean exit 1 error‑severity findings exit 2 fetch failures
# .husky/pre-commit — block the commit on blockers
node skills/seo-check/scripts/crawl.mjs \
  --base http://localhost:3000 / /pricing \
  || { echo "seo-check: fix blockers before committing"; exit 1; }

@@ limits, stated plainly @@

What it doesn't do

@@ questions @@

Questions people ask

What is seo-check?

seo-check is an open-source SEO checker skill for Claude Code, installable as a plugin. Run /seo-check and it audits the files you've changed but not yet committed for SEO regressions, then crawls the affected routes with a Googlebot user agent and returns a commit verdict: safe, caution, or fix first.

How is it different from a normal SEO audit tool?

Most SEO tools audit a live site after the damage is done. seo-check runs on the diff, before the commit, so a stray noindex, a broadened Disallow:, a deleted route or a broken JSON-LD block is caught before it reaches production. With a production URL it also diffs every signal between local and live, so you see exactly what your change altered.

Which frameworks does it support?

Next.js (app and pages router), Astro and plain HTML sites out of the box — it maps changed files to URL routes for those. The crawler itself works on any URL, whatever the stack.

Does it send my code anywhere or need an API key?

No API key. The crawler is a zero-dependency Node script that only fetches your own URLs. The static pass runs inside your existing Claude Code session, so your diff goes only where your Claude Code conversations already go.

Can I use it without Claude Code?

Yes. crawl.mjs runs standalone and exits 0, 1 or 2, so it drops straight into a git pre-commit hook or a CI step.

Is it free?

MIT-licensed, free, no sign-up. Install it from the repository's marketplace in two lines, or star and fork it on GitHub.