SEO GEO Site Audit
Turn a public website into a structured, evidence-based SEO + GEO audit.
How to invoke
Just give the skill the target URL. It runs immediately with defaults. Override inline if needed.
| Default |
Value |
| Mode |
Light template audit (10 pages) |
| Output style |
Operator |
| Performance |
Local Lighthouse on the homepage (mobile + desktop) |
| HTML report |
On |
| Output language |
English |
Defaults match the common case. Don't ask the user 5 questions. Run the wrapper and write the report.
Inline overrides
The agent parses these from the user's prompt and passes the matching flags to the wrapper:
| Phrasing |
Override |
fast, quick check, 1 page, homepage only |
--mode fast (1 page) |
template, standard, full, 50 pages |
--mode template (50 pages) |
N pages (1–50) |
--max-pages N |
boss style, executive summary |
--output-style boss |
specialist, detailed, deep |
--output-style specialist |
skip performance, skip lighthouse, no pagespeed |
--skip-pagespeed |
no html, json only, skip html |
drop --html-report |
in Chinese, 中文, 用中文 |
--report-language chinese |
in <language>, report in <language> |
--report-language <language> |
If the user inlines all preferences in the first message, parse and run. If the user gave only a URL, run with defaults silently.
When to actually ask
Three narrow cases. Otherwise, never ask:
- No URL. "Audit my site" without a URL — ask for the URL.
- Language explicitly mentioned but ambiguous — e.g. user typed in Spanish but didn't say "in Spanish for the report". Ask once: "Final report in English or Spanish?"
- Wrapper prerequisites missing. If
--auto-install-prereqs would download Lightpanda nightly or Camoufox, mention the install + ask permission once before running. Default to --skip-prereq-check and the urllib fallback if the user says no.
A vague session-level "be quick" or "no clarifying questions" is the same signal as "use defaults" — just run.
Default language stays English
If the user typed the request in Chinese, the report still defaults to English unless the user explicitly asks for a non-English report. Don't auto-translate based on prompt language.
Switch only on:
2 selected after a deliberate language question (case 2 above),
- a phrase like "in Chinese", "中文", "Spanish report", "report in German",
- the
--report-language CLI flag.
Architecture (read on demand)
Two evidence tracks per HTML page — a raw Googlebot-style HTTP baseline and a JS-rendered DOM — then comparison. Rendered fetching falls through Scrapling → Lightpanda → agent-browser → urllib. SPA recovery layer (Scrapling retry, scroll+wait, DOM route hints), domain-aware route guesser, sitemap-first fallback. Performance evidence comes from local Lighthouse via scripts/run_lighthouse.mjs.
Full rules — fetcher priority, recovery triggers, SPA detection thresholds, route guess templates, Lighthouse invocation — live in references/architecture.md.
Two principles to keep in working memory:
- Raw vs rendered. If a signal appears only after JS, call it a JavaScript-dependency risk, not "Google cannot see it." If both raw and rendered are missing, it is a true missing signal.
- Assisted discovery. Pages reached only through
dom_route_hint or route_guess are not search-discoverable. Don't present them as crawlable unless a raw <a href> or sitemap also exposes them.
Guardrails
- Treat the crawl as a sample, not a full index.
- Default crawl cap is 10 pages (light mode). Maximum is 50.
- Stay on the same origin unless the user explicitly wants cross-domain review.
- Separate observed evidence from inference.
- Never imply access to Search Console, analytics, Ahrefs, SEMrush, or server logs unless the user actually provided them.
- If Lighthouse data is unavailable because of a node/npm/Chrome failure, complete the audit anyway and clearly label performance evidence as missing or partial.
- Never hardcode API keys, tokens, or secrets in this repo.
Skill paths
The skill typically lives at ~/.claude/skills/seo-geo-site-audit/. The wrapper script is ${SKILL_DIR}/scripts/audit-site. Use ${SKILL_DIR}/... or the user's actual install path; don't hardcode another user's home directory.
Workflow
Parse the prompt. Extract the target URL and any inline overrides (see the override table above). If no URL, ask for it. Otherwise proceed silently — do not list defaults back at the user before running.
Run the wrapper with --html-report by default. Append any flags from the override parse.
${SKILL_DIR}/scripts/audit-site \
<URL> \
--mode light \
--output-style operator \
--html-report
Add --skip-pagespeed, --report-language chinese, etc. as overrides dictate.
Inspect the artifacts. The wrapper writes crawl.json, pagespeed.json, audit-run.json, evidence-report.html, and seeds final-report.json. Read the crawl summary, page list, security headers, and the Lighthouse aggregate. Look for:
- sitewide signals (
coverage_rates, duplicate titles, security headers, schema coverage)
- SPA flags + raw-vs-rendered deltas
- pages reached only through
dom_route_hint / route_guess
- mobile vs desktop Lighthouse averages
Score the audit. Read references/scoring-rubric.md. Score each of the seven sections 0–100, then weight:
- Technical SEO & Indexability
- On-Page SEO & Content Packaging
- Information Architecture & Internal Linking
- GEO & AI Extractability
- EEAT & Trust Signals
- Entity & Structured Data
- Performance & Page Experience
Round to whole numbers. Penalize recurring sitewide failures more than isolated page issues. If the sample is small, say confidence is lower.
Write the report. Follow references/report-template.md. Every section needs score, what passed, issues, recommended actions. Every issue needs severity (P0/P1/P2/P3), why it matters, what to fix — embed supporting numbers directly in the issue detail prose. Always label Lighthouse evidence as lab data without CrUX field metrics.
Render the HTML. Fill final-report.json, then run:
${SKILL_DIR}/scripts/render-report-html \
--report-json ${SKILL_DIR}/runs/site-audit-<host>-<stamp>/final-report.json \
--out ${SKILL_DIR}/runs/site-audit-<host>-<stamp>/audit-report.html
Mention the audit-report.html path in the final response alongside the chat audit.
Output modes (read on demand)
Boss (shortest) / Operator (default) / Specialist (deepest). Content rules in references/output-modes.md.
What to look for (read on demand)
Per-section signal lists in references/audit-checklist.md. Read when scoring a specific section.
Reporting rules
- Start with the scorecard.
- Call out passed items as well as failures.
- Prefer patterns over one-off nitpicks.
- Keep unsupported assumptions out of the report.
- State which URLs were crawled and which were used for Lighthouse.
- If a finding comes from a limited sample, say so.
- If rendered-browser evidence is stronger than the raw baseline, say so and treat it as a risk.
- Don't present
dom_route_hint or route_guess pages as search-discoverable without raw HTML or sitemap evidence.
- Always label Lighthouse evidence as lab data without CrUX field metrics.
Files in this skill
scripts/fetchers.py — unified fetcher with prereq detection, auto-install, SPA detection
scripts/crawl_sample.py — capped crawl + HTML signal extraction
scripts/pagespeed_batch.py — local Lighthouse runner writing the normalized JSON
scripts/run_lighthouse.mjs — programmatic Lighthouse via lighthouse + chrome-launcher
scripts/audit_site.py — wrapper that orchestrates crawl + Lighthouse + artifacts
scripts/audit-site — executable launcher for the wrapper
scripts/render_report_html.py — polished final-report HTML renderer
scripts/render-report-html — executable launcher for the renderer
scripts/language_packs.py — centralized EN/ZH UI strings
scripts/_report_styles.py — shared CSS palette tokens
scripts/package.json — Lighthouse npm dependencies
tests/ — pytest/unittest suite for crawl + parse helpers
references/setup-gate.md — defaults + override phrasings reference
references/cli-flags.md — wrapper flag reference + security notes
references/example-requests.md — example chat invocations
references/scoring-rubric.md — scoring rules and weights
references/report-template.md — output skeleton
references/report-payload-template.json — structured payload template
references/architecture.md — crawl + fetch + Lighthouse internals
references/audit-checklist.md — per-section signal lists
references/output-modes.md — Boss / Operator / Specialist content rules
Common rationalizations to avoid
| Excuse |
Reality |
| "User only gave a URL, I should ask 5 questions first" |
Defaults exist for that. Just run. |
| "Their session is autonomous, I should skip even the URL check" |
The URL is a hard requirement. Ask if missing. |
| "User typed in Chinese, the report should be Chinese too" |
English by default. Switch only on explicit phrasing. |
| "I should restate the defaults to confirm" |
The user can read the report; no need to narrate defaults. |
| "Performance check on just the homepage isn't enough" |
Homepage is the highest-traffic page on most sites — it's a fair single check. Use --max-pagespeed-urls N if the user asks for more. |
1---2name: seo-geo-site-audit3description: Use when the user asks for an SEO audit, GEO audit, AI visibility review, technical content-readiness review, site-quality review, crawlability check, or asks Claude to audit, score, or grade a public website — even if they don't say the word "skill". The skill crawls a representative sample of up to 50 pages, compares raw Googlebot-style HTML against rendered DOM, reviews crawlability, metadata, internal linking, structured data, trust signals, and runs local Lighthouse for mobile/desktop performance evidence, then produces a scored HTML report.4---56# SEO GEO Site Audit78Turn a public website into a structured, evidence-based SEO + GEO audit.910## How to invoke1112Just give the skill the target URL. It runs immediately with defaults. Override inline if needed.1314| Default | Value |15|---|---|16| Mode | Light template audit (10 pages) |17| Output style | Operator |18| Performance | Local Lighthouse on the homepage (mobile + desktop) |19| HTML report | On |20| Output language | English |2122Defaults match the common case. Don't ask the user 5 questions. Run the wrapper and write the report.2324## Inline overrides2526The agent parses these from the user's prompt and passes the matching flags to the wrapper:2728| Phrasing | Override |29|---|---|30| `fast`, `quick check`, `1 page`, `homepage only` | `--mode fast` (1 page) |31| `template`, `standard`, `full`, `50 pages` | `--mode template` (50 pages) |32| `N pages` (1–50) | `--max-pages N` |33| `boss style`, `executive summary` | `--output-style boss` |34| `specialist`, `detailed`, `deep` | `--output-style specialist` |35| `skip performance`, `skip lighthouse`, `no pagespeed` | `--skip-pagespeed` |36| `no html`, `json only`, `skip html` | drop `--html-report` |37| `in Chinese`, `中文`, `用中文` | `--report-language chinese` |38| `in <language>`, `report in <language>` | `--report-language <language>` |3940If the user inlines all preferences in the first message, parse and run. If the user gave only a URL, run with defaults silently.4142## When to actually ask4344Three narrow cases. Otherwise, never ask:45461. **No URL.** "Audit my site" without a URL — ask for the URL.472. **Language explicitly mentioned but ambiguous** — e.g. user typed in Spanish but didn't say "in Spanish for the report". Ask once: "Final report in English or Spanish?"483. **Wrapper prerequisites missing.** If `--auto-install-prereqs` would download Lightpanda nightly or Camoufox, mention the install + ask permission once before running. Default to `--skip-prereq-check` and the urllib fallback if the user says no.4950A vague session-level "be quick" or "no clarifying questions" is the **same** signal as "use defaults" — just run.5152## Default language stays English5354If the user typed the request in Chinese, the report still defaults to **English** unless the user explicitly asks for a non-English report. Don't auto-translate based on prompt language.5556Switch only on:57- `2` selected after a deliberate language question (case 2 above),58- a phrase like "in Chinese", "中文", "Spanish report", "report in German",59- the `--report-language` CLI flag.6061## Architecture (read on demand)6263Two evidence tracks per HTML page — a raw Googlebot-style HTTP baseline and a JS-rendered DOM — then comparison. Rendered fetching falls through Scrapling → Lightpanda → agent-browser → urllib. SPA recovery layer (Scrapling retry, scroll+wait, DOM route hints), domain-aware route guesser, sitemap-first fallback. Performance evidence comes from local Lighthouse via `scripts/run_lighthouse.mjs`.6465Full rules — fetcher priority, recovery triggers, SPA detection thresholds, route guess templates, Lighthouse invocation — live in [`references/architecture.md`](references/architecture.md).6667Two principles to keep in working memory:6869- **Raw vs rendered.** If a signal appears only after JS, call it a JavaScript-dependency risk, not "Google cannot see it." If both raw and rendered are missing, it is a true missing signal.70- **Assisted discovery.** Pages reached only through `dom_route_hint` or `route_guess` are not search-discoverable. Don't present them as crawlable unless a raw `<a href>` or sitemap also exposes them.7172## Guardrails7374- Treat the crawl as a **sample**, not a full index.75- Default crawl cap is **10** pages (light mode). Maximum is **50**.76- Stay on the same origin unless the user explicitly wants cross-domain review.77- Separate **observed evidence** from **inference**.78- Never imply access to Search Console, analytics, Ahrefs, SEMrush, or server logs unless the user actually provided them.79- If Lighthouse data is unavailable because of a node/npm/Chrome failure, complete the audit anyway and clearly label performance evidence as missing or partial.80- Never hardcode API keys, tokens, or secrets in this repo.8182## Skill paths8384The skill typically lives at `~/.claude/skills/seo-geo-site-audit/`. The wrapper script is `${SKILL_DIR}/scripts/audit-site`. Use `${SKILL_DIR}/...` or the user's actual install path; don't hardcode another user's home directory.8586## Workflow87881. **Parse the prompt.** Extract the target URL and any inline overrides (see the override table above). If no URL, ask for it. Otherwise proceed silently — do not list defaults back at the user before running.89902. **Run the wrapper with `--html-report` by default.** Append any flags from the override parse.9192 ```bash93 ${SKILL_DIR}/scripts/audit-site \94 <URL> \95 --mode light \96 --output-style operator \97 --html-report98 ```99100 Add `--skip-pagespeed`, `--report-language chinese`, etc. as overrides dictate.1011023. **Inspect the artifacts.** The wrapper writes `crawl.json`, `pagespeed.json`, `audit-run.json`, `evidence-report.html`, and seeds `final-report.json`. Read the crawl summary, page list, security headers, and the Lighthouse aggregate. Look for:103 - sitewide signals (`coverage_rates`, duplicate titles, security headers, schema coverage)104 - SPA flags + raw-vs-rendered deltas105 - pages reached only through `dom_route_hint` / `route_guess`106 - mobile vs desktop Lighthouse averages1071084. **Score the audit.** Read [`references/scoring-rubric.md`](references/scoring-rubric.md). Score each of the seven sections 0–100, then weight:109 1. Technical SEO & Indexability110 2. On-Page SEO & Content Packaging111 3. Information Architecture & Internal Linking112 4. GEO & AI Extractability113 5. EEAT & Trust Signals114 6. Entity & Structured Data115 7. Performance & Page Experience116117 Round to whole numbers. Penalize recurring sitewide failures more than isolated page issues. If the sample is small, say confidence is lower.1181195. **Write the report.** Follow [`references/report-template.md`](references/report-template.md). Every section needs score, what passed, issues, recommended actions. Every issue needs severity (P0/P1/P2/P3), why it matters, what to fix — embed supporting numbers directly in the issue detail prose. Always label Lighthouse evidence as lab data without CrUX field metrics.1201216. **Render the HTML.** Fill `final-report.json`, then run:122123 ```bash124 ${SKILL_DIR}/scripts/render-report-html \125 --report-json ${SKILL_DIR}/runs/site-audit-<host>-<stamp>/final-report.json \126 --out ${SKILL_DIR}/runs/site-audit-<host>-<stamp>/audit-report.html127 ```128129 Mention the `audit-report.html` path in the final response alongside the chat audit.130131## Output modes (read on demand)132133Boss (shortest) / Operator (default) / Specialist (deepest). Content rules in [`references/output-modes.md`](references/output-modes.md).134135## What to look for (read on demand)136137Per-section signal lists in [`references/audit-checklist.md`](references/audit-checklist.md). Read when scoring a specific section.138139## Reporting rules140141- Start with the scorecard.142- Call out **passed items** as well as failures.143- Prefer patterns over one-off nitpicks.144- Keep unsupported assumptions out of the report.145- State which URLs were crawled and which were used for Lighthouse.146- If a finding comes from a limited sample, say so.147- If rendered-browser evidence is stronger than the raw baseline, say so and treat it as a risk.148- Don't present `dom_route_hint` or `route_guess` pages as search-discoverable without raw HTML or sitemap evidence.149- Always label Lighthouse evidence as lab data without CrUX field metrics.150151## Files in this skill152153- `scripts/fetchers.py` — unified fetcher with prereq detection, auto-install, SPA detection154- `scripts/crawl_sample.py` — capped crawl + HTML signal extraction155- `scripts/pagespeed_batch.py` — local Lighthouse runner writing the normalized JSON156- `scripts/run_lighthouse.mjs` — programmatic Lighthouse via `lighthouse` + `chrome-launcher`157- `scripts/audit_site.py` — wrapper that orchestrates crawl + Lighthouse + artifacts158- `scripts/audit-site` — executable launcher for the wrapper159- `scripts/render_report_html.py` — polished final-report HTML renderer160- `scripts/render-report-html` — executable launcher for the renderer161- `scripts/language_packs.py` — centralized EN/ZH UI strings162- `scripts/_report_styles.py` — shared CSS palette tokens163- `scripts/package.json` — Lighthouse npm dependencies164- `tests/` — pytest/unittest suite for crawl + parse helpers165- `references/setup-gate.md` — defaults + override phrasings reference166- `references/cli-flags.md` — wrapper flag reference + security notes167- `references/example-requests.md` — example chat invocations168- `references/scoring-rubric.md` — scoring rules and weights169- `references/report-template.md` — output skeleton170- `references/report-payload-template.json` — structured payload template171- `references/architecture.md` — crawl + fetch + Lighthouse internals172- `references/audit-checklist.md` — per-section signal lists173- `references/output-modes.md` — Boss / Operator / Specialist content rules174175## Common rationalizations to avoid176177| Excuse | Reality |178|---|---|179| "User only gave a URL, I should ask 5 questions first" | Defaults exist for that. Just run. |180| "Their session is autonomous, I should skip even the URL check" | The URL is a hard requirement. Ask if missing. |181| "User typed in Chinese, the report should be Chinese too" | English by default. Switch only on explicit phrasing. |182| "I should restate the defaults to confirm" | The user can read the report; no need to narrate defaults. |183| "Performance check on just the homepage isn't enough" | Homepage is the highest-traffic page on most sites — it's a fair single check. Use `--max-pagespeed-urls N` if the user asks for more. |