SEO/GEO Technical Audit
Find and fix the technical gaps that keep a site from being crawled,
indexed, and cited — by search engines and by AI answer engines. Scope is
technical setup only: no content strategy, keywords, or link building.
One principle drives modern GEO: most AI crawlers do not execute
JavaScript, and they read the raw HTML response. A site that serves its
content server-rendered, with clean URLs, working status codes, and an
accurate sitemap, is optimized for both Google and AI engines at once.
Everything in this skill serves that goal.
Workflow
Six phases, in order. Never fix before showing the audit — most projects
have partial setup, and some "gaps" (a noindex, a blocked AI crawler) are
deliberate choices to confirm, not bugs.
Phase 1 — Detect the project context
Identify:
- Framework: check for
next.config.* (Next.js — App Router if
app/), astro.config.* (Astro), nuxt.config.* (Nuxt),
svelte.config.* (SvelteKit), vite.config.* + index.html (Vite
SPA), plain *.html (static). Fix routes per framework are in
references/frameworks.md.
- Rendering mode: SSR, SSG, or client-side rendered. A CSR-only app is
the single biggest GEO gap (see Phase 3).
- Production URL:
homepage in package.json, CNAME, deploy config,
README. Ask if not inferable and not obviously pre-launch.
- Hosting: Vercel/Netlify/Cloudflare/nginx — determines where
redirects, headers, and host canonicalization get fixed.
Phase 2 — Run the scripted audit
Start the site (dev server, or build + preview for SSG/SSR so the
audited HTML is what production serves, not dev-mode output), then run
the audit script from this skill's directory (the project is the cwd,
so use the script's full path):
node <this-skill-dir>/scripts/audit-site.mjs <url> --local # local dev/preview
node <this-skill-dir>/scripts/audit-site.mjs <prod-url> --pages 10 # deployed site
(Node 18+, no dependencies. --pages N controls how many sitemap URLs
get page-level checks; default 5.)
Environment notes:
- Static site, no server: serve the output dir first —
python3 -m http.server 8080 -d <dir> or npx serve <dir>.
- Monorepo: ask which app/site to audit if more than one has a web
build.
- Bot protection / auth wall: the script may get 403s or challenge
pages. Don't fight it — fall back to the Phase 3 source-only audit and
say why. (Also note the finding itself: aggressive bot protection
blocks AI crawlers too.)
The script checks host/protocol canonicalization, robots.txt (including
per-AI-crawler policy), sitemap validity, per-page indexability (title,
canonical, meta robots, JSON-LD, hreflang, server-rendered content),
soft-404s, trailing slashes, and compression/caching headers. --local
skips HTTPS/host checks that only make sense in production and downgrades
noindex to informational. Exit 1 means at least one FAIL.
Phase 3 — Source-level audit (what the script can't see)
Check in the repo:
- Sitemap wiring — is the sitemap generated (framework route/plugin)
or a stale hand-written file? Generated wins: it stays correct as pages
are added.
- Per-page metadata mechanism — can every page set its own title,
description, and canonical, or is it hardcoded in one layout?
- Structured data coverage — Organization/WebSite on the home page;
the matching page-type schema (Article, Product, FAQPage,
BreadcrumbList) wherever the type applies. JSON-LD, not microdata.
- Redirect & host config — www↔apex and http→https handled at the
host (301/308), single trailing-slash policy, no redirect chains.
- Rendering strategy — if content is client-rendered, flag it as the
top finding. Recommendation order: SSG/prerender the public pages >
SSR > leave CSR (only for app-behind-login). Dynamic rendering
(bot-sniffing prerender layers) is deprecated by Google — don't build it.
- Internal linking mechanics — real
<a href> links (not onClick
handlers), History API routing (not #/ fragments), no orphan pages.
- CWV hygiene — image dimensions set (CLS), modern formats, lazy
loading below the fold,
font-display: swap, no render-blocking
third-party scripts in <head>. Full targets in
references/checklist.md.
The canonical pass/fail bar for every item — with the verified facts and
limits behind it — is references/checklist.md.
For AI-crawler policy decisions (which bots to allow/block and what each
trade-off is), read references/geo.md.
Phase 4 — Report the gaps
Present one table: finding → severity → why it matters → fix, ordered
FAIL → WARN → INFO. Separate a "confirm intent" group for findings
that may be deliberate (noindex, blocked AI crawlers, staging robots.txt)
and ask about those in one batched question round. Get a go-ahead before
Phase 5.
Phase 5 — Fix
Implement framework-idiomatically per
references/frameworks.md. Rules that hold
regardless of framework:
- Fix, don't append. Replace wrong tags; never leave two canonicals
or conflicting robots directives.
- robots.txt is for crawl control, not de-indexing. To keep a page
out of the index use
noindex (meta or X-Robots-Tag) — and the page
must not be robots-blocked, or crawlers never see the noindex.
- Canonicals and sitemap URLs must be absolute and agree with each
other and with the served URL form (host, protocol, trailing slash).
- Block AI training without killing AI visibility: training opt-out
tokens (GPTBot, ClaudeBot, Google-Extended) are separate from
search/answer fetchers (OAI-SearchBot, Claude-SearchBot,
PerplexityBot). Blocking everything removes the site from AI answers —
confirm that's wanted. Details in references/geo.md.
- Don't add folklore: no meta keywords, no llms.txt as an "SEO
requirement" (it's optional — see geo.md), no schema stuffing in the
hope of AI citations.
Phase 6 — Verify and hand off
- Re-run
audit-site.mjs (same mode as Phase 2) — all FAILs gone, WARNs
either fixed or explained in the report.
- For SSG/SSR:
curl -A GPTBot <url> and confirm the main content is in
the raw HTML response.
- Validate structured data (schema.org validator or Rich Results Test)
if JSON-LD changed.
- Close with the post-deploy checklist (needs the live domain) —
details for each item are in the "Verification & monitoring" section of
references/checklist.md:
- Google Search Console: verify (Domain property = DNS record), submit
the sitemap.
- Bing Webmaster Tools: import the verified GSC property.
- IndexNow: optional, non-Google engines only.
- Re-run
audit-site.mjs <prod-url> without --local to get the
HTTPS/HSTS/host checks.
- Watch CWV field data in GSC/CrUX once traffic accrues.
Scope
In scope: crawlability, indexability, robots.txt, sitemaps, canonicals,
redirects/status codes, structured data, rendering strategy, hreflang,
metadata plumbing, CWV/security-header basics, AI crawler policy,
search-engine verification. Out of scope (mention, don't implement):
content/keywords, link building, blogging cadence, analytics, paid
search. For deep link-preview/favicon work (og:image generation, platform
quirks), hand off to the share-ready skill if it's available — this
skill only checks OG presence.
1---2name: seo-geo-audit3description: Audits and fixes a website's technical SEO and GEO (AI answer engine) setup: crawlability, indexability, sitemaps, robots.txt + AI crawler policy, canonicals, structured data, rendering strategy, hreflang, Core Web Vitals basics, and search-engine verification. Use when launching a new site, checking why pages aren't indexed or cited by AI engines, setting up robots.txt/sitemap/canonical tags, or when the user mentions technical SEO, GEO, AI crawlers, or indexing.4---56# SEO/GEO Technical Audit78Find and fix the technical gaps that keep a site from being crawled,9indexed, and cited — by search engines and by AI answer engines. Scope is10**technical setup only**: no content strategy, keywords, or link building.1112One principle drives modern GEO: **most AI crawlers do not execute13JavaScript**, and they read the raw HTML response. A site that serves its14content server-rendered, with clean URLs, working status codes, and an15accurate sitemap, is optimized for both Google and AI engines at once.16Everything in this skill serves that goal.1718## Workflow1920Six phases, in order. Never fix before showing the audit — most projects21have partial setup, and some "gaps" (a noindex, a blocked AI crawler) are22deliberate choices to confirm, not bugs.2324### Phase 1 — Detect the project context2526Identify:2728- **Framework**: check for `next.config.*` (Next.js — App Router if29 `app/`), `astro.config.*` (Astro), `nuxt.config.*` (Nuxt),30 `svelte.config.*` (SvelteKit), `vite.config.*` + `index.html` (Vite31 SPA), plain `*.html` (static). Fix routes per framework are in32 [references/frameworks.md](references/frameworks.md).33- **Rendering mode**: SSR, SSG, or client-side rendered. A CSR-only app is34 the single biggest GEO gap (see Phase 3).35- **Production URL**: `homepage` in package.json, CNAME, deploy config,36 README. Ask if not inferable and not obviously pre-launch.37- **Hosting**: Vercel/Netlify/Cloudflare/nginx — determines where38 redirects, headers, and host canonicalization get fixed.3940### Phase 2 — Run the scripted audit4142Start the site (dev server, or **build + preview for SSG/SSR so the43audited HTML is what production serves**, not dev-mode output), then run44the audit script **from this skill's directory** (the project is the cwd,45so use the script's full path):4647```bash48node <this-skill-dir>/scripts/audit-site.mjs <url> --local # local dev/preview49node <this-skill-dir>/scripts/audit-site.mjs <prod-url> --pages 10 # deployed site50```5152(Node 18+, no dependencies. `--pages N` controls how many sitemap URLs53get page-level checks; default 5.)5455Environment notes:5657- **Static site, no server**: serve the output dir first —58 `python3 -m http.server 8080 -d <dir>` or `npx serve <dir>`.59- **Monorepo**: ask which app/site to audit if more than one has a web60 build.61- **Bot protection / auth wall**: the script may get 403s or challenge62 pages. Don't fight it — fall back to the Phase 3 source-only audit and63 say why. (Also note the finding itself: aggressive bot protection64 blocks AI crawlers too.)6566The script checks host/protocol canonicalization, robots.txt (including67per-AI-crawler policy), sitemap validity, per-page indexability (title,68canonical, meta robots, JSON-LD, hreflang, server-rendered content),69soft-404s, trailing slashes, and compression/caching headers. `--local`70skips HTTPS/host checks that only make sense in production and downgrades71noindex to informational. Exit 1 means at least one FAIL.7273### Phase 3 — Source-level audit (what the script can't see)7475Check in the repo:76771. **Sitemap wiring** — is the sitemap generated (framework route/plugin)78 or a stale hand-written file? Generated wins: it stays correct as pages79 are added.802. **Per-page metadata mechanism** — can every page set its own title,81 description, and canonical, or is it hardcoded in one layout?823. **Structured data coverage** — Organization/WebSite on the home page;83 the matching page-type schema (Article, Product, FAQPage,84 BreadcrumbList) wherever the type applies. JSON-LD, not microdata.854. **Redirect & host config** — www↔apex and http→https handled at the86 host (301/308), single trailing-slash policy, no redirect chains.875. **Rendering strategy** — if content is client-rendered, flag it as the88 top finding. Recommendation order: SSG/prerender the public pages >89 SSR > leave CSR (only for app-behind-login). Dynamic rendering90 (bot-sniffing prerender layers) is deprecated by Google — don't build it.916. **Internal linking mechanics** — real `<a href>` links (not `onClick`92 handlers), History API routing (not `#/` fragments), no orphan pages.937. **CWV hygiene** — image dimensions set (CLS), modern formats, lazy94 loading below the fold, `font-display: swap`, no render-blocking95 third-party scripts in `<head>`. Full targets in96 [references/checklist.md](references/checklist.md).9798The canonical pass/fail bar for every item — with the verified facts and99limits behind it — is [references/checklist.md](references/checklist.md).100For AI-crawler policy decisions (which bots to allow/block and what each101trade-off is), read [references/geo.md](references/geo.md).102103### Phase 4 — Report the gaps104105Present one table: **finding → severity → why it matters → fix**, ordered106FAIL → WARN → INFO. Separate a **"confirm intent"** group for findings107that may be deliberate (noindex, blocked AI crawlers, staging robots.txt)108and ask about those in one batched question round. Get a go-ahead before109Phase 5.110111### Phase 5 — Fix112113Implement framework-idiomatically per114[references/frameworks.md](references/frameworks.md). Rules that hold115regardless of framework:116117- **Fix, don't append.** Replace wrong tags; never leave two canonicals118 or conflicting robots directives.119- **robots.txt is for crawl control, not de-indexing.** To keep a page120 out of the index use `noindex` (meta or `X-Robots-Tag`) — and the page121 must *not* be robots-blocked, or crawlers never see the noindex.122- **Canonicals and sitemap URLs must be absolute** and agree with each123 other and with the served URL form (host, protocol, trailing slash).124- **Block AI training without killing AI visibility**: training opt-out125 tokens (GPTBot, ClaudeBot, Google-Extended) are separate from126 search/answer fetchers (OAI-SearchBot, Claude-SearchBot,127 PerplexityBot). Blocking everything removes the site from AI answers —128 confirm that's wanted. Details in [references/geo.md](references/geo.md).129- Don't add folklore: no meta keywords, no llms.txt as an "SEO130 requirement" (it's optional — see geo.md), no schema stuffing in the131 hope of AI citations.132133### Phase 6 — Verify and hand off1341351. Re-run `audit-site.mjs` (same mode as Phase 2) — all FAILs gone, WARNs136 either fixed or explained in the report.1372. For SSG/SSR: `curl -A GPTBot <url>` and confirm the main content is in138 the raw HTML response.1393. Validate structured data (schema.org validator or Rich Results Test)140 if JSON-LD changed.1414. Close with the **post-deploy checklist** (needs the live domain) —142 details for each item are in the "Verification & monitoring" section of143 [references/checklist.md](references/checklist.md):144 - Google Search Console: verify (Domain property = DNS record), submit145 the sitemap.146 - Bing Webmaster Tools: import the verified GSC property.147 - IndexNow: optional, non-Google engines only.148 - Re-run `audit-site.mjs <prod-url>` **without** `--local` to get the149 HTTPS/HSTS/host checks.150 - Watch CWV field data in GSC/CrUX once traffic accrues.151152## Scope153154In scope: crawlability, indexability, robots.txt, sitemaps, canonicals,155redirects/status codes, structured data, rendering strategy, hreflang,156metadata plumbing, CWV/security-header basics, AI crawler policy,157search-engine verification. Out of scope (mention, don't implement):158content/keywords, link building, blogging cadence, analytics, paid159search. For deep link-preview/favicon work (og:image generation, platform160quirks), hand off to the `share-ready` skill if it's available — this161skill only checks OG presence.