/seo-validate — SEO Validation Scanner
$ARGUMENTS
Scan a codebase for SEO issues using pattern-matching heuristics. Detects W3C/HTML violations, meta tag gaps, structured data problems, hreflang errors, Core Web Vitals risks (LCP/INP/CLS), resource-hint misuse, above-the-fold anti-patterns, GEO gaps (chunk architecture, hedging language, decision frameworks, semantic triples, freshness), topical authority gaps (pillar/cluster structure, orphan pages, cannibalization), SPA/CSR/SSG crawlability problems, technical SEO misconfigurations, and accessibility-for-SEO issues. Read-only — never modifies files.
Standards basis: W3C HTML5 Recommendation, W3C WCAG 2.2, Schema.org vocabulary, IETF RFC 5646 (BCP 47 language tags) for hreflang, web.dev Core Web Vitals thresholds (LCP <2.5s, INP <200ms, CLS <0.1), Google Search Central crawlability guidelines, and emerging GEO (Generative Engine Optimization) practices.
Usage
/seo-validate # Scan full project, auto-detect framework
/seo-validate src/ # Scan specific path
/seo-validate --scope rendering # Only SPA/CSR/SSG crawlability checks
/seo-validate --scope performance # Only Core Web Vitals static signals
/seo-validate --scope geo # Only GEO (Generative Engine Optimization)
/seo-validate --scope topical # Only topical authority and cluster architecture
/seo-validate --severity high # Filter to HIGH findings only
/seo-validate --framework next # Force framework (skip auto-detection)
/seo-validate --rendering csr # Force rendering-mode interpretation
/seo-validate --output json # Structured JSON output for CI integration
Scopes:
full (default) — all 10 categories
technical — HTML semantics, hreflang, CWV, rendering, technical SEO (categories 1, 4, 5, 7, 8)
content — meta/OG, structured data, GEO, a11y-for-SEO (categories 2, 3, 6, 9)
performance — only CWV static signals (category 5)
geo — only GEO / citability checks (category 6)
rendering — only category 7 (SPA/CSR/SSG crawlability) — useful for migration audits
topical — only topical authority and cluster architecture (category 10)
Severity filtering: --severity high shows only HIGH, --severity warn shows HIGH+WARN, --severity info shows all. Default: all.
What This Command Does
- Detect framework and rendering mode from
package.json, config files, and entry HTML.
- Run the scanner script for a deterministic baseline over 8 of the 10 categories.
- Extend the scan by hand using
Grep/Glob/Read against framework-aware patterns for everything the script does not cover.
- Interpret findings with specific fix suggestions tied to the detected framework.
- Report findings with file paths, line numbers, severity, confidence, and standards citations.
Steps
Step 1: Detect Framework & Rendering Mode
Run detection before scanning so category patterns can adapt. Detection order:
- Read
package.json (if present) and inspect dependencies + devDependencies:
| Deps contain |
Framework |
Default rendering |
next |
next |
hybrid (per-route) |
nuxt |
nuxt |
ssr |
astro |
astro |
ssg |
gatsby |
gatsby |
ssg |
@sveltejs/kit |
sveltekit |
hybrid |
@remix-run/* |
remix |
ssr |
@angular/core + @angular/ssr or @nguniversal/* |
angular |
ssr |
@angular/core alone |
angular |
csr (flag as SPA) |
vue + nuxt |
see nuxt row |
— |
vue without nuxt |
vue |
csr (flag as SPA) |
react + vite without Next/Remix |
vite-spa |
csr (flag as SPA) |
react-scripts |
cra |
csr (flag as SPA) |
no package.json OR no framework deps |
static |
static |
Read config files to refine:
next.config.* — check output: 'export' (forces SSG), images, i18n settings.
nuxt.config.* — check ssr: false, generate blocks (SSG export).
astro.config.* — check output: 'server'|'static'|'hybrid' and prerender directives.
gatsby-config.* — plugin list (gatsby-plugin-react-helmet, gatsby-plugin-sitemap).
svelte.config.* — adapter choice (static, node, vercel).
vite.config.* + package.json scripts — look for vite-plugin-ssr, vite-plugin-prerender.
angular.json — look for SSR builder config.
Read entry HTML (public/index.html, index.html, app/layout.tsx, src/app.html, etc.) to confirm whether meaningful content is prerendered or only a mount point (<div id="root"></div>).
Override precedence: --framework and --rendering flags override detection.
Report the detected framework and rendering mode in the Summary table.
Step 2: Run the Scanner Script
python3 ${CLAUDE_SKILL_DIR}/scripts/seo-scanner.py [path] [--output json|text]
Deterministic checks over meta tags, heading order, image alt, JSON-LD, hreflang,
robots.txt, sitemap, Core Web Vitals signals and llms.txt. No framework
awareness — it reads files, not build config. Categories 7 and 10 are not touched.
Step 3: Extend the Scan by Hand
Read reference/scanner-categories.md in full,
then work every category in --scope with Grep (regex across files) and Read
(config parsing / ordered checks), skipping only what Step 2 already reported.
Patterns are framework-aware — use the framework detected in Step 1 to select the
right rule set.
Categories 7 (Rendering Mode & Crawlability) and 10 (Topical Authority) get no help
from the script. Run them in full or say in the report that you did not.
Step 4: Interpret and Enrich
For each finding:
- Read the flagged file/lines to confirm the match is real (not a comment, not a type-only reference).
- Add a specific fix tied to the framework (e.g., "use
next/image with priority prop" vs. "add <link rel="preload" as="image"> to <head>").
- Mark confidence:
definitive for regex matches against known-bad patterns, heuristic for co-occurrence / absence checks.
- Skip false positives when context shows the concern is addressed elsewhere (e.g., meta tags set in a layout file the route inherits from).
Step 5: Report
Present findings sorted by severity (HIGH → WARN → INFO), then by file path.
State which findings came from the script and which from the manual pass, and name
any category you did not complete.
Scanner Reference
scripts/seo-scanner.py gives a deterministic baseline over 8 of the 10 categories.
The full pattern tables, per-framework rules and standards citations live in
reference/scanner-categories.md.
| # |
Category |
Covered by the script |
Manual pass |
| 1 |
HTML Semantics & W3C |
heading order |
rest of the category |
| 2 |
Meta & Open Graph |
title, description, OG/Twitter tags |
rest of the category |
| 3 |
Structured Data / Schema.org |
JSON-LD presence and shape |
rest of the category |
| 4 |
Hreflang & i18n |
hreflang pairs, x-default |
rest of the category |
| 5 |
Core Web Vitals (static signals) |
LCP/CLS/INP signal patterns |
rest of the category |
| 6 |
GEO (Generative Engine Optimization) |
llms.txt presence |
rest of the category |
| 7 |
Rendering Mode & SPA/CSR/SSG Crawlability |
nothing |
the whole category |
| 8 |
Technical SEO |
robots.txt, sitemap |
rest of the category |
| 9 |
Accessibility for SEO |
image alt |
rest of the category |
| 10 |
Topical Authority & Cluster Architecture |
nothing |
the whole category |
Categories 7 and 10 have no script coverage at all — they are entirely manual, and
skipping them is the most likely way this skill under-reports.
Output Format
## SEO Validation Report
### Summary
| Metric | Value |
|--------|-------|
| Scope | full / technical / content / performance / geo / rendering / topical |
| Framework detected | next / nuxt / astro / gatsby / sveltekit / remix / angular / vue / react-spa / vite-spa / cra / static |
| Rendering mode | csr / ssr / ssg / isr / hybrid |
| Files scanned | N |
| Public routes found | N |
| Routes with prerendering | N of N |
| Findings: HIGH | N |
| Findings: WARN | N |
| Findings: INFO | N |
### Findings
#### [HIGH] app/layout.tsx:12
Category: HTML Semantics & W3C
Confidence: definitive
Pattern: `<html>` element missing `lang` attribute
W3C Rule: HTML5 §3.2.6
Fix: Add `lang="en"` (or appropriate BCP 47 code) to the `<html>` element.
See: reference/w3c-guidelines.md#lang-attribute
#### [HIGH] components/HomeHero.tsx:24
Category: Core Web Vitals (LCP)
Confidence: definitive
Pattern: Above-the-fold `<img>` with `loading="lazy"`
Rule: LCP anti-pattern — lazy loading the LCP element delays it
Fix: Remove `loading="lazy"`, add `fetchpriority="high"`. For Next.js use `<Image priority />`.
See: reference/core-web-vitals.md#above-the-fold
#### [HIGH] src/App.tsx:1
Category: Rendering Mode & SPA Crawlability
Confidence: definitive
Pattern: CSR-only React app (Vite) with no prerender plugin
Rule: Content-site SPAs without SSR/SSG are invisible to most crawlers
Fix: Add `vite-plugin-ssr` or migrate to Next.js/Remix; OR add `react-snap` for build-time prerender.
See: reference/spa-ssg-patterns.md#react-spa-migration
Confidence values:
definitive — regex match against a known-bad pattern with high precision.
heuristic — co-occurrence / absence / ordering / above-the-fold inference — may be false positive.
Exit codes (when --output json):
0 — no HIGH findings.
1 — one or more HIGH findings.
Rules
- Read-only: Never modify any files. Report findings only.
- Framework-aware: Always detect framework first; apply the correct rule set.
- Standards citation: Every HIGH/WARN finding must cite a W3C/Schema.org/RFC/web.dev reference.
- Skip non-source files: Binary files, lock files (
package-lock.json, yarn.lock, pnpm-lock.yaml), vendored directories (node_modules/, vendor/, .git/, dist/, build/, out/, .next/, .nuxt/, .svelte-kit/, public/build/).
- No false confidence: Label heuristic findings clearly; above-the-fold detection is always heuristic.
- GEO severity: Category 6 findings may be WARN (chunk size, author quality, freshness) or INFO (hedging, frameworks, contrast, bio) — see table. Never raise GEO findings to HIGH.
- SPA HIGH bar: Only flag Category 7 HIGH when the app is clearly a content site (has public routes with meaningful content). Auth-gated apps (dashboards, admin panels) should stay at WARN/INFO since SEO is not a concern.
- Noscript is not a substitute for SSR/SSG:
<noscript> catches only the "no-JS" case, not the "crawler without JS execution" case — don't upgrade a CSR HIGH to WARN just because noscript exists.
- No auto-fix in v1: Fixing SEO issues requires design/content decisions beyond pattern matching.
Gotchas
scripts/seo-scanner.py reads files, not build output. A Next.js metadata export, a useHead() call, or a <svelte:head> block produces correct tags at runtime that the scanner cannot see, so "missing meta description" on a framework project is a claim about the source, not about the page.
- Categories 7 (Rendering & Crawlability) and 10 (Topical Authority) get zero script coverage. They are also the two that most often carry the real problem, because a CSR-only app can pass every other category while being invisible to crawlers. Skipping Step 3 for these silently converts the worst finding into no finding.
robots.txt and sitemap.xml are checked at the project root. Frameworks that generate them at build time (next-sitemap, @astrojs/sitemap, gatsby-plugin-sitemap) leave nothing on disk, so absence is not evidence — check the config and the plugin list before reporting it.
- Hreflang correctness needs both directions. A page declaring
hreflang="de" is only valid if the German page declares the reverse; a one-file scan sees half the pair and cannot conclude.
- Core Web Vitals here are static signals only — missing
width/height, unbounded images, render-blocking patterns. Real LCP/CLS/INP come from field data (CrUX, RUM). Reporting a passing CWV category is out of this skill's reach.
- Category 6 (GEO) is genuinely young. Its "signals" track how generative engines behaved recently, not a ratified standard, so its findings stay WARN/INFO by rule — raising one to HIGH asserts more certainty than the field supports.
When NOT to Use
- On an auth-gated app — dashboards and admin panels have no crawler audience, and every category-7 finding will be noise.
- To measure Core Web Vitals — use PageSpeed Insights, CrUX, or your RUM; this skill sees source patterns, not field metrics.
- To verify tags a framework generates at build time — build the site and scan the output, or read the framework config instead.
- For accessibility beyond the SEO overlap — use
/a11y-validate; category 9 here is deliberately shallow.
- To rewrite content for topical authority — this skill is read-only and reports gaps; the writing is a separate job.
Reference Documents
- reference/w3c-guidelines.md — HTML5 semantic requirements, meta tag specs, language tag rules.
- reference/core-web-vitals.md — LCP/INP/CLS thresholds, resource hints, above-the-fold heuristic, per-framework image components.
- reference/geo-guidelines.md — GEO principles,
speakable schema, citation/source markup, AI-extractable content structure, chunk anatomy, 13-week freshness strategy.
- reference/geo-aeo-patterns.md — AEO (Answer Engine Optimization):
FAQPage/HowTo/QAPage schema, llms.txt, AI bot robots.txt directives, E-E-A-T signals, automated grep patterns for Category 6.
- reference/content-citability.md — Chunk architecture, semantic triples, opinionated vs hedging language, decision frameworks, contrast patterns, negative definitions, justified superlatives, grep patterns.
- reference/ai-pipeline.md — Google's 4-stage AI pipeline (Prepare/Retrieve/Signal/Serve), 7 ranking signals (Gecko, Jetstream, PCTR, Freshness, BM25, Base, Boost/Bury), Query Fan Out, probabilistic ranking, format routing.
- reference/schema-types.md — Schema.org JSON-LD templates (Article, FAQ, BreadcrumbList, Organization, Product, LocalBusiness) with required properties.
- reference/spa-ssg-patterns.md — Rendering-mode decision tree, SPA pitfalls, per-framework detection patterns, prerendering strategies.
1---2name: seo-validate3description: SEO validator: meta/OG, Schema.org, hreflang, Core Web Vitals, crawlability. Triggers: SEO, meta tags, Schema.org, hreflang, LCP, INP, CLS, Core Web Vitals, sitemap, crawlability.4---56# /seo-validate — SEO Validation Scanner78$ARGUMENTS910Scan a codebase for SEO issues using pattern-matching heuristics. Detects W3C/HTML violations, meta tag gaps, structured data problems, hreflang errors, Core Web Vitals risks (LCP/INP/CLS), resource-hint misuse, above-the-fold anti-patterns, GEO gaps (chunk architecture, hedging language, decision frameworks, semantic triples, freshness), topical authority gaps (pillar/cluster structure, orphan pages, cannibalization), SPA/CSR/SSG crawlability problems, technical SEO misconfigurations, and accessibility-for-SEO issues. Read-only — never modifies files.1112**Standards basis**: W3C HTML5 Recommendation, W3C WCAG 2.2, Schema.org vocabulary, IETF RFC 5646 (BCP 47 language tags) for hreflang, web.dev Core Web Vitals thresholds (LCP <2.5s, INP <200ms, CLS <0.1), Google Search Central crawlability guidelines, and emerging GEO (Generative Engine Optimization) practices.1314## Usage1516```17/seo-validate # Scan full project, auto-detect framework18/seo-validate src/ # Scan specific path19/seo-validate --scope rendering # Only SPA/CSR/SSG crawlability checks20/seo-validate --scope performance # Only Core Web Vitals static signals21/seo-validate --scope geo # Only GEO (Generative Engine Optimization)22/seo-validate --scope topical # Only topical authority and cluster architecture23/seo-validate --severity high # Filter to HIGH findings only24/seo-validate --framework next # Force framework (skip auto-detection)25/seo-validate --rendering csr # Force rendering-mode interpretation26/seo-validate --output json # Structured JSON output for CI integration27```2829**Scopes:**30- `full` (default) — all 10 categories31- `technical` — HTML semantics, hreflang, CWV, rendering, technical SEO (categories 1, 4, 5, 7, 8)32- `content` — meta/OG, structured data, GEO, a11y-for-SEO (categories 2, 3, 6, 9)33- `performance` — only CWV static signals (category 5)34- `geo` — only GEO / citability checks (category 6)35- `rendering` — only category 7 (SPA/CSR/SSG crawlability) — useful for migration audits36- `topical` — only topical authority and cluster architecture (category 10)3738**Severity filtering:** `--severity high` shows only HIGH, `--severity warn` shows HIGH+WARN, `--severity info` shows all. Default: all.3940## What This Command Does41421. **Detect framework and rendering mode** from `package.json`, config files, and entry HTML.432. **Run the scanner script** for a deterministic baseline over 8 of the 10 categories.443. **Extend the scan by hand** using `Grep`/`Glob`/`Read` against framework-aware patterns for everything the script does not cover.454. **Interpret findings** with specific fix suggestions tied to the detected framework.465. **Report** findings with file paths, line numbers, severity, confidence, and standards citations.4748## Steps4950### Step 1: Detect Framework & Rendering Mode5152Run detection before scanning so category patterns can adapt. Detection order:53541. **Read `package.json`** (if present) and inspect `dependencies` + `devDependencies`:5556| Deps contain | Framework | Default rendering |57|--------------|-----------|-------------------|58| `next` | `next` | hybrid (per-route) |59| `nuxt` | `nuxt` | ssr |60| `astro` | `astro` | ssg |61| `gatsby` | `gatsby` | ssg |62| `@sveltejs/kit` | `sveltekit` | hybrid |63| `@remix-run/*` | `remix` | ssr |64| `@angular/core` + `@angular/ssr` or `@nguniversal/*` | `angular` | ssr |65| `@angular/core` alone | `angular` | csr (flag as SPA) |66| `vue` + `nuxt` | see nuxt row | — |67| `vue` without `nuxt` | `vue` | csr (flag as SPA) |68| `react` + `vite` without Next/Remix | `vite-spa` | csr (flag as SPA) |69| `react-scripts` | `cra` | csr (flag as SPA) |70| no `package.json` OR no framework deps | `static` | static |71722. **Read config files** to refine:73 - `next.config.*` — check `output: 'export'` (forces SSG), `images`, i18n settings.74 - `nuxt.config.*` — check `ssr: false`, `generate` blocks (SSG export).75 - `astro.config.*` — check `output: 'server'|'static'|'hybrid'` and `prerender` directives.76 - `gatsby-config.*` — plugin list (`gatsby-plugin-react-helmet`, `gatsby-plugin-sitemap`).77 - `svelte.config.*` — adapter choice (`static`, `node`, `vercel`).78 - `vite.config.*` + `package.json` scripts — look for `vite-plugin-ssr`, `vite-plugin-prerender`.79 - `angular.json` — look for SSR builder config.80813. **Read entry HTML** (`public/index.html`, `index.html`, `app/layout.tsx`, `src/app.html`, etc.) to confirm whether meaningful content is prerendered or only a mount point (`<div id="root"></div>`).82834. **Override precedence**: `--framework` and `--rendering` flags override detection.8485Report the detected framework and rendering mode in the Summary table.8687### Step 2: Run the Scanner Script8889```bash90python3 ${CLAUDE_SKILL_DIR}/scripts/seo-scanner.py [path] [--output json|text]91```9293Deterministic checks over meta tags, heading order, image `alt`, JSON-LD, hreflang,94`robots.txt`, sitemap, Core Web Vitals signals and `llms.txt`. No framework95awareness — it reads files, not build config. Categories 7 and 10 are not touched.9697### Step 3: Extend the Scan by Hand9899Read [reference/scanner-categories.md](reference/scanner-categories.md) in full,100then work every category in `--scope` with `Grep` (regex across files) and `Read`101(config parsing / ordered checks), skipping only what Step 2 already reported.102Patterns are framework-aware — use the framework detected in Step 1 to select the103right rule set.104105Categories 7 (Rendering Mode & Crawlability) and 10 (Topical Authority) get no help106from the script. Run them in full or say in the report that you did not.107108### Step 4: Interpret and Enrich109110For each finding:1111121. **Read the flagged file/lines** to confirm the match is real (not a comment, not a type-only reference).1132. **Add a specific fix** tied to the framework (e.g., "use `next/image` with `priority` prop" vs. "add `<link rel="preload" as="image">` to `<head>`").1143. **Mark confidence**: `definitive` for regex matches against known-bad patterns, `heuristic` for co-occurrence / absence checks.1154. **Skip false positives** when context shows the concern is addressed elsewhere (e.g., meta tags set in a layout file the route inherits from).116117### Step 5: Report118119Present findings sorted by severity (HIGH → WARN → INFO), then by file path.120State which findings came from the script and which from the manual pass, and name121any category you did not complete.122123---124125## Scanner Reference126127`scripts/seo-scanner.py` gives a deterministic baseline over 8 of the 10 categories.128The full pattern tables, per-framework rules and standards citations live in129[reference/scanner-categories.md](reference/scanner-categories.md).130131| # | Category | Covered by the script | Manual pass |132|---|----------|----------------------|-------------|133| 1 | HTML Semantics & W3C | heading order | rest of the category |134| 2 | Meta & Open Graph | title, description, OG/Twitter tags | rest of the category |135| 3 | Structured Data / Schema.org | JSON-LD presence and shape | rest of the category |136| 4 | Hreflang & i18n | hreflang pairs, x-default | rest of the category |137| 5 | Core Web Vitals (static signals) | LCP/CLS/INP signal patterns | rest of the category |138| 6 | GEO (Generative Engine Optimization) | `llms.txt` presence | rest of the category |139| 7 | Rendering Mode & SPA/CSR/SSG Crawlability | **nothing** | the whole category |140| 8 | Technical SEO | `robots.txt`, sitemap | rest of the category |141| 9 | Accessibility for SEO | image `alt` | rest of the category |142| 10 | Topical Authority & Cluster Architecture | **nothing** | the whole category |143144Categories 7 and 10 have no script coverage at all — they are entirely manual, and145skipping them is the most likely way this skill under-reports.146147## Output Format148149```markdown150## SEO Validation Report151152### Summary153| Metric | Value |154|--------|-------|155| Scope | full / technical / content / performance / geo / rendering / topical |156| Framework detected | next / nuxt / astro / gatsby / sveltekit / remix / angular / vue / react-spa / vite-spa / cra / static |157| Rendering mode | csr / ssr / ssg / isr / hybrid |158| Files scanned | N |159| Public routes found | N |160| Routes with prerendering | N of N |161| Findings: HIGH | N |162| Findings: WARN | N |163| Findings: INFO | N |164165### Findings166167#### [HIGH] app/layout.tsx:12168Category: HTML Semantics & W3C169Confidence: definitive170Pattern: `<html>` element missing `lang` attribute171W3C Rule: HTML5 §3.2.6172Fix: Add `lang="en"` (or appropriate BCP 47 code) to the `<html>` element.173See: reference/w3c-guidelines.md#lang-attribute174175#### [HIGH] components/HomeHero.tsx:24176Category: Core Web Vitals (LCP)177Confidence: definitive178Pattern: Above-the-fold `<img>` with `loading="lazy"`179Rule: LCP anti-pattern — lazy loading the LCP element delays it180Fix: Remove `loading="lazy"`, add `fetchpriority="high"`. For Next.js use `<Image priority />`.181See: reference/core-web-vitals.md#above-the-fold182183#### [HIGH] src/App.tsx:1184Category: Rendering Mode & SPA Crawlability185Confidence: definitive186Pattern: CSR-only React app (Vite) with no prerender plugin187Rule: Content-site SPAs without SSR/SSG are invisible to most crawlers188Fix: Add `vite-plugin-ssr` or migrate to Next.js/Remix; OR add `react-snap` for build-time prerender.189See: reference/spa-ssg-patterns.md#react-spa-migration190```191192**Confidence values**:193- `definitive` — regex match against a known-bad pattern with high precision.194- `heuristic` — co-occurrence / absence / ordering / above-the-fold inference — may be false positive.195196**Exit codes** (when `--output json`):197- `0` — no HIGH findings.198- `1` — one or more HIGH findings.199200## Rules201202- **Read-only**: Never modify any files. Report findings only.203- **Framework-aware**: Always detect framework first; apply the correct rule set.204- **Standards citation**: Every HIGH/WARN finding must cite a W3C/Schema.org/RFC/web.dev reference.205- **Skip non-source files**: Binary files, lock files (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`), vendored directories (`node_modules/`, `vendor/`, `.git/`, `dist/`, `build/`, `out/`, `.next/`, `.nuxt/`, `.svelte-kit/`, `public/build/`).206- **No false confidence**: Label heuristic findings clearly; above-the-fold detection is always heuristic.207- **GEO severity**: Category 6 findings may be WARN (chunk size, author quality, freshness) or INFO (hedging, frameworks, contrast, bio) — see table. Never raise GEO findings to HIGH.208- **SPA HIGH bar**: Only flag Category 7 HIGH when the app is clearly a content site (has public routes with meaningful content). Auth-gated apps (dashboards, admin panels) should stay at WARN/INFO since SEO is not a concern.209- **Noscript is not a substitute for SSR/SSG**: `<noscript>` catches only the "no-JS" case, not the "crawler without JS execution" case — don't upgrade a CSR HIGH to WARN just because noscript exists.210- **No auto-fix in v1**: Fixing SEO issues requires design/content decisions beyond pattern matching.211212## Gotchas213214- `scripts/seo-scanner.py` reads **files, not build output**. A Next.js `metadata` export, a `useHead()` call, or a `<svelte:head>` block produces correct tags at runtime that the scanner cannot see, so "missing meta description" on a framework project is a claim about the source, not about the page.215- Categories **7 (Rendering & Crawlability)** and **10 (Topical Authority)** get zero script coverage. They are also the two that most often carry the real problem, because a CSR-only app can pass every other category while being invisible to crawlers. Skipping Step 3 for these silently converts the worst finding into no finding.216- `robots.txt` and `sitemap.xml` are checked **at the project root**. Frameworks that generate them at build time (`next-sitemap`, `@astrojs/sitemap`, `gatsby-plugin-sitemap`) leave nothing on disk, so absence is not evidence — check the config and the plugin list before reporting it.217- Hreflang correctness needs **both directions**. A page declaring `hreflang="de"` is only valid if the German page declares the reverse; a one-file scan sees half the pair and cannot conclude.218- Core Web Vitals here are **static signals only** — missing `width`/`height`, unbounded images, render-blocking patterns. Real LCP/CLS/INP come from field data (CrUX, RUM). Reporting a passing CWV category is out of this skill's reach.219- Category 6 (GEO) is genuinely young. Its "signals" track how generative engines behaved recently, not a ratified standard, so its findings stay WARN/INFO by rule — raising one to HIGH asserts more certainty than the field supports.220221## When NOT to Use222223- On an auth-gated app — dashboards and admin panels have no crawler audience, and every category-7 finding will be noise.224- To measure Core Web Vitals — use PageSpeed Insights, CrUX, or your RUM; this skill sees source patterns, not field metrics.225- To verify tags a framework generates at build time — build the site and scan the output, or read the framework config instead.226- For accessibility beyond the SEO overlap — use `/a11y-validate`; category 9 here is deliberately shallow.227- To rewrite content for topical authority — this skill is read-only and reports gaps; the writing is a separate job.228229## Reference Documents230231- [reference/w3c-guidelines.md](reference/w3c-guidelines.md) — HTML5 semantic requirements, meta tag specs, language tag rules.232- [reference/core-web-vitals.md](reference/core-web-vitals.md) — LCP/INP/CLS thresholds, resource hints, above-the-fold heuristic, per-framework image components.233- [reference/geo-guidelines.md](reference/geo-guidelines.md) — GEO principles, `speakable` schema, citation/source markup, AI-extractable content structure, chunk anatomy, 13-week freshness strategy.234- [reference/geo-aeo-patterns.md](reference/geo-aeo-patterns.md) — AEO (Answer Engine Optimization): `FAQPage`/`HowTo`/`QAPage` schema, `llms.txt`, AI bot `robots.txt` directives, E-E-A-T signals, automated grep patterns for Category 6.235- [reference/content-citability.md](reference/content-citability.md) — Chunk architecture, semantic triples, opinionated vs hedging language, decision frameworks, contrast patterns, negative definitions, justified superlatives, grep patterns.236- [reference/ai-pipeline.md](reference/ai-pipeline.md) — Google's 4-stage AI pipeline (Prepare/Retrieve/Signal/Serve), 7 ranking signals (Gecko, Jetstream, PCTR, Freshness, BM25, Base, Boost/Bury), Query Fan Out, probabilistic ranking, format routing.237- [reference/schema-types.md](reference/schema-types.md) — Schema.org JSON-LD templates (Article, FAQ, BreadcrumbList, Organization, Product, LocalBusiness) with required properties.238- [reference/spa-ssg-patterns.md](reference/spa-ssg-patterns.md) — Rendering-mode decision tree, SPA pitfalls, per-framework detection patterns, prerendering strategies.