Website SEO & GEO Audit
Target: $ARGUMENTS
Audits a site for traditional SEO and Generative-Engine Optimization (GEO — visibility in AI search such as ChatGPT, Perplexity, Gemini, and Google AI Overviews) and generates implementable fixes. Prefer configuring the site or static-site generator so tags are emitted once (DRY) over hand-stuffing meta into every page. No over-analysis.
Audit Areas
Core meta
<title>(30-60 chars, unique per page),120-160 chars, entity-clear),<meta name="description">(langon<html>,charset,viewport(nomaximum-scale— it blocks zoom),robots,author,keywords,format-detection, and acanonicallink.
Open Graph & Twitter Card
og:title,og:description,og:url,og:type,og:site_name,og:image.twitter:card,twitter:title,twitter:description,twitter:image,twitter:site,twitter:creator.
Structured data (JSON-LD)
WebSite/Organization(name, url, logo, sameAs) and per-pageArticle/BlogPosting(headline, description, datePublished, author, publisher, image). Validate against the matching schema.org type.
GEO / AI-search
robots.txtAI user-agents (GPTBot, ClaudeBot, Google-Extended, CCBot, PerplexityBot, OAI-SearchBot) — the highest-leverage, best-honored lever.llms.txtat root — cheap, uncertain adoption; fine to keep.- Entity clarity, key info in the first ~160 chars, Q&A-friendly phrasing, explicit brand / product / service names.
Static-site-generator pitfalls (verify, do not assume)
- Do not double-emit. If an SSG plugin emits OG/Twitter/JSON-LD (e.g. jekyll-seo-tag, Next SEO), do NOT also hand-write those tags — duplicates result. Configure the plugin instead.
- Plugins emit conditionally. Twitter Card tags often need a configured
handle;
twitter:descriptionandog:image/twitter:imagemay not be emitted without explicit config or a per-page image. Fill only the genuine gaps in a single shared include.
Known-unwinnable conflicts (flag, do not chase)
Some checkers want mutually-exclusive lengths on a single shared tag:
og:title25-35 vstwitter:title50-70 — same tag, cannot satisfy both.og:description55-65 vs<meta name="description">120-160 — same tag.
Recommend the real-world optimum (Google limits plus GEO: a ~50-char title and a ~150-char description) and note the tradeoff rather than ping-ponging.
Reality check
- ai.txt /
/.well-known/ai.txtis not a recognized standard (competing vendor proposals, no IANA.well-knownregistration, no major adopter). Skip it; do not spend effort on/.well-known/ai.txt. - A complete
robots.txtAI-agent policy plus a full OG/JSON-LD set are what actually move GEO and social previews.
Workflow
- Identify scope from $ARGUMENTS (URL, file, or directory). For a URL,
fetch the rendered
<head>— converting tools return markdown, so fetch raw HTML when you need the tags verbatim. - Inventory the tags present versus the audit areas above; detect duplicates.
- Classify findings: HIGH (title, description, canonical, OG core), MEDIUM (Twitter, JSON-LD, keywords), LOW (format-detection, author).
- Generate fixes — prefer SSG config plus a single shared include over per-page tags.
- Verify by re-fetching the built output, not the raw templates.
Output Format
Findings
HIGH
- [Tag/issue] - Current: [value or "missing"] - Page: [url/path]
Fix: [code/config snippet]
MEDIUM / LOW
- [Tag/issue] - Current: [value or "missing"]
Fix: [code/config snippet]
Implementation Checklist
- [ ] [Fix] - Impact: [High/Medium/Low] - scope: [site-wide | per-page]
Rules
- Configure once (DRY); do not hand-stuff tags an SSG already emits.
- Flag mutually-exclusive checker targets instead of chasing impossible green.
- Optimize for real engines and GEO, not vanity checker scores.
- Every finding includes a concrete, implementable fix.
- Keep output concise: findings + fixes + checklist only.