# Geo

> Generative Engine Optimization — get the brand cited inside ChatGPT, Perplexity, Gemini, Claude, and Google AI Mode answers rather than just ranked on a SERP

- Skill: `abouchard11/geo` (Agent Skill)
- Install (CLI): `npx skillmds@latest add abouchard11/geo`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abouchard11/geo/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: abouchard11 (https://skillmd.com/u/abouchard11)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/abouchard11/geo

---


# GEO — Generative Engine Optimization

**First:** Read `~/.claude/skills/seo-references/core.md`. Apply the methodology and voice to all output. Purchase-intent pages stay the 80/20. GEO is a citation layer on those pages, not a license to stand up a "what is" blog.

**Also read:**
- `~/.claude/skills/seo-references/data-pull-patterns.md` for MCP tool names
- `~/.claude/skills/seo-references/sturm-shorts.md` for the dated operator notes this skill encodes
- `~/.claude/skills/seo-references/fan-out-diagnostic.md` for the one-page AI Mode branch check
- `~/.claude/skills/seo-references/measurement-2026-09-02.md` for the GA4/log boundary and current OpenSEO capability check
- Companion research: https://github.com/abouchard11/ai-citation-patterns — engine-by-engine citation behavior. Do not copy that file into the playbook. Use it as the evidence desk.
- Input gate: `/geo-crawl` — [geo-crawl-audit](https://github.com/abouchard11/geo-crawl-audit). Do not re-audit robots.txt by hand in this skill.

Unit of success: a **citation, brand mention, or recommendation** inside a synthesized answer. Not a blue-link rank. Not a featured snippet (that is `/aeo`). Not "can the bot fetch the HTML" (that is `/geo-crawl`).

Route, do not duplicate:
- Reach / TTFB / raw HTML / robots / WAF → `/geo-crawl` (hard preflight)
- Preferred Sources badge → `/preferred-source`
- Extractable passages / snippets / PAA → `/aeo`
- Fan-out branches on one existing BOFU page → this skill + `/aeo` (never a new desk)
- Referring-domain work → `/hunter` then `/kilo`
- Indexing → `/indexer`

## Do not do this

- Do not put "this page is optimized for AI assistants and LLM search, not human marketing" (or any cousin) at the top of a page. Models already filter "SEO spam" in the thinking trace. Admitting the page is for machines is a self-report. Write for a buyer. Let the structure do the extractability work.
- Do not ship `llms.txt` as a ranking lever. Google ignores it. Treat it as optional agent-hygiene only.
- Do not scrape Google SERPs as a primary data path. The `/goto` redirect plus the retired `num=100` parameter broke that class of tracker. Use GSC, Semrush, and first-party AI-visibility tools.
- Do not invent an eight-site directory list from memory. If the personal-site submission list from the Sturm short is needed, pull it from the video itself (see sturm-shorts.md). Then execute through `/kilo`.
- Do not write citation copy while `/geo-crawl` is STOP. A passage the bot cannot retrieve is not GEO.
- Do not open a new URL per inferred fan-out branch. That is the page farm the gap memo refused.

## Step 1: Parse Domain

Extract the domain. Strip protocol, www, trailing slash, lowercase. Resolve against the MCP Routing Map.

Name the entity the engines should learn: brand string, legal name, product names, founder name if the property is personal. GEO fails when the page talks about "we" and never writes the proper noun.

## Step 2: Input gate (hard preflight)

Run `/geo-crawl` on this domain first, or reuse a probe from this session if it is already on the same host.

| `/geo-crawl` verdict | This skill |
|---|---|
| **STOP** | Print the crawl verdict. Stop after Section 1 of the playbook. Do not build a prompt matrix. Do not draft passages. Recommended Action 1 is the crawl fix. |
| **CONTINUE WITH FIXES** | Proceed. Keep the crawl flags in Section 1 and in Recommended Actions ahead of any content patch. |
| **CLEAR** | Proceed. |
| Probe unavailable and operator did not accept an unprobed run | Same as STOP. |

CSR_SHELL, retrieval/user_fetch BOT_DIFFERENTIAL, and retrieval/user_fetch ROBOTS_BLOCKS are STOP conditions. Training-bot policy is not. Advertising-class tokens (`OAI-AdsBot`) are not.

## Step 3: Pull Live Data

Skip this step on STOP.

**Semrush (PRIMARY):**
1. `mcp__semrush__execute_report` — Domain Overview (database=us). Authority + organic baseline.
2. `mcp__semrush__execute_report` — Referring Domains, display_limit=20. ChatGPT retrieval is gated hard by referring-domain count. Note the RD total in the verdict.
3. `mcp__semrush__execute_report` — Domain Organic Search Keywords, display_limit=30. Separate branded vs unbranded. GEO probes use both.

**GSC (ENRICHMENT):**
4. `mcp__gscServer__get_search_analytics` — last 28 days, dimensions=[query], rowLimit=50. Queries that already impress are the first prompt set.

**GA4 (ENRICHMENT):**
5. `mcp__google-analytics__run_report` — sessions by landing page, last 28 days. Pages that already convert are the pages that should become citable, not a new explainer silo.

**CamoFox (ENRICHMENT):**
6. Snapshot the homepage + the #1 converting page. Check: brand name in H1 / first sentence, server-rendered facts (price, specs, city, phone), author byline, outbound citations, FAQ block, schema present, no "for LLMs" disclosure. If CamoFox is down: `[SEO] CamoFox unavailable — on-page extractability check skipped.` Do not use CamoFox as a substitute for `/geo-crawl`. CamoFox is a rendered browser; the probe is a non-rendering fetch.

**Optional OpenSEO enrichment (never PRIMARY):**
OpenSEO ([every-app/open-seo](https://github.com/every-app/open-seo), hosted [openseo.so](https://openseo.so)) combines standard DataForSEO-backed SEO workflows with UI-based AI-visibility features.

Capability boundary checked 2026-09-02:

- The product UI includes Brand Lookup, Prompt Explorer, cited-page / cited-source tables, and Share of Voice.
- The repository's MCP server does **not** register those AI-visibility functions. Do not instruct an agent to call nonexistent OpenSEO MCP tools for brand lookup or prompt exploration.
- Hosted AI visibility is plan-gated. Self-hosting removes the app subscription gate, but it does not remove DataForSEO usage costs.
- Vendor estimates are enrichment. They do not replace the repeated `/geo` prompt matrix or verified crawler evidence.

Use OpenSEO only as a compact cross-site enrichment layer if connected. Keep Semrush + GSC as the standard SEO truth, `/geo-crawl` as reachability, the owned drain as verified crawler evidence, and the repeated prompt matrix as citation truth.

If a source fails, print the `[SEO]` warning from core.md and continue.

## Step 4: Prompt Probe Set

Skip this step on STOP.

Build 8–12 prompts the engines will actually be asked. Split:

| Bucket | Count | Pattern |
|---|---|---|
| Category recommend | 3 | "best [vertical] in [city / for X]" |
| Comparison | 2 | "[brand] vs [competitor]" |
| Entity | 2 | "what is [brand]", "who makes [product]" |
| Money | 2 | price / "hire [vertical] in [city]" / availability |
| Correction | 1–3 | the wrong fact a model already says |

Run each prompt against whatever surfaces the operator can reach this session (ChatGPT Search, Perplexity, Gemini, Claude with web search, Google AI Mode / AI Overviews). Repeat ChatGPT prompts — backend switching makes a single snapshot unreliable.

Score each surface per prompt:

| Score | Meaning |
|---|---|
| **CITED** | Brand or URL named with a source link |
| **MENTIONED** | Brand named, no link |
| **ABSENT** | Competitors present, we are not |
| **WRONG** | Hallucinated fact, dead URL, or wrong city / price |
| **UNTESTED** | Surface not reachable this run |

## Step 4b: Fan-out diagnostic (one page)

Skip on STOP. Follow `fan-out-diagnostic.md`.

Take one money or category-recommend prompt that already maps to the #1 converting URL. Infer at most six branches from the closed list. Map each branch onto an existing heading on that URL or onto an existing silo page. Label landings `SAME_URL` or `SILO_PAGE`. Never `NEW_URL`.

If AI Mode / AI Overviews is reachable this session, load the seed prompt once and list cited domains. Otherwise mark every branch `INFERRED`. The Recommended Action is one heading + 134–167 word passage on the existing BOFU page. Do not treat branch coverage as a citation probability.

## Step 5: Generate the GEO Playbook

**Section 1 — Verdict**
Open with the `/geo-crawl` handshake (STOP / CONTINUE WITH FIXES / CLEAR) and the one-line citation verdict if the run proceeded. Are we in the answer, next to the answer, or invisible? Name the highest-leverage missing citation. On STOP, this section is the whole playbook.

**Section 2 — Citation matrix**
Skip on STOP. Table: prompt × surface × score × who got cited instead. No theater. Empty cells stay UNTESTED.

**Section 3 — Entity and off-site pool**
Skip on STOP. Engines fan out to the sources they already trust. List the third-party pages that should mention this brand (G2/Capterra/Clutch if software, GBP + local citations if local-service, Wikipedia / Wikidata only if notable, Reddit threads that already rank, YouTube titles + transcripts). Route the actual link asks to `/hunter` and `/kilo`.

Personal-site / founder-entity properties: quality referring domains help both classic SEO and AI appearance, and they are one path toward a knowledge panel. Do not wallpaper generic directories onto a local-service money site.

**Section 4 — On-page citability (BOFU pages only)**
Skip on STOP. For the top 2–3 converting URLs, specify the smallest patch that makes a passage reusable:
- Proper noun in the first sentence
- One standalone 134–167 word passage that answers the category prompt without the rest of the page
- One dated statistic or price with an outbound source
- Comparison table only if the page already competes on "vs" queries
- FAQ answers as atomic paragraphs, not a new /blog
- Server-rendered facts — prices and specs must not live only in JS
- Fan-out heading match for the single worst MISSING branch from Step 4b — on this URL, not a new one

Keep pages at core.md length caps. GEO is extractability, not word count. If `/geo-crawl` already flagged `THIN_HTML` or `CSR_SHELL`, the fix is render-or-expand, not a new URL.

**Section 5 — Crawler pointer**
Do not re-parse robots.txt here. One paragraph: handshake verdict, flag codes, link to the probe report. Retrieval vs training is decided in `/geo-crawl`.

**Section 6 — Measurement**
Skip detail on STOP. What to re-run in 28 days: `/geo-crawl` if any CONTINUE fix shipped, then the same prompt matrix, RD count, branded GSC queries, and OpenSEO AI-visibility UI/export if the operator has access. Do not use scraped Google rank-tracker URL paths as proof — `/goto` ate those.

**Section 7 — What this will not do**
- Will not replace Map Pack for local
- Will not buy position one
- Will not make a login-walled tool citable
- Will not reward a page that announces it is spam for machines
- Will not cite-optimize a host the retrieval bots cannot fetch
- Will not farm a URL per inferred fan-out branch

## Step 6: Output

Follow the Output Protocol from core.md:
1. Print the full GEO playbook to terminal
2. Extract structured summary (include crawl handshake)
3. Save to Graphiti with name `GEO — [domain]`

In Recommended Actions, first item is the crawl fix on STOP or CONTINUE WITH FIXES. On CLEAR, first item is the single prompt + surface where a one-page patch would most likely flip ABSENT → CITED this month. If Step 4b produced a MISSING branch, that heading patch is the same item — do not list a second content workstream.

