GEO Opportunity Finder
A guided, multi-phase deep-research flow whose whole purpose is to find the
AI-search prompts your product can actually win — and prove each one is
winnable with live data scraped right now via the Bright Data MCP (server
name: brightdata). It exists to defeat the #1 objection to AI-generated SEO/GEO
advice — "the AI just hallucinates" — so the prime directive is non-negotiable:
NO-FABRICATION RULE. Never state a prompt, ranking, competitor, citation,
metric, or "best practice" unless it came from a live tool call in THIS run. If
a live call fails or returns nothing, write "⚠️ Live data unavailable for this
step" and stop that step. Do not fill the gap from memory. Do not invent search
volumes, citation counts, domain-authority scores, or URLs. Search volume and
domain authority do not exist in this data source — treat any demand/authority
read as a labeled PROXY (People Also Ask / related presence; organic SERP rank
- recognizability). Every output ends with a Sources section listing the
exact URLs/queries it pulled.
The big idea
Most SEO tools tell you how to rank for a keyword you already picked. This skill
answers the question that comes first: which battles are even worth fighting?
It scans many prompts about your product and ranks them by how easy they are to
capture in AI search. The opportunity matrix is the deliverable. Writing the
content to capture a chosen opportunity is an optional follow-on.
An opportunity is a prompt where (your hypothesis, made measurable):
- 🟢 Nothing is cited — the AI answers from memory; any solid page can become the source.
- 🟢 Something irrelevant is cited — the cited pages don't really answer the prompt.
- 🟡 A recreatable page is cited — a blog, listicle, product page, Q&A, or Reddit thread you could out-build.
- 🔴 (not an opportunity) A hard-to-beat source is cited — official docs, Wikipedia, standards bodies, gov, top-brand domains.
- ⚪ (defend, not capture) Your own domain is already cited.
Prerequisites (check first)
- The
brightdata MCP server must be connected. Confirm mcp__brightdata__*
tools are available. If not, tell the user: "The Bright Data MCP isn't
loaded. Copy .mcp.json.example → .mcp.json, paste your API token (raw, not
${VAR}), restart Claude Code, then re-run." Do not attempt the phases without it.
- Skim
references/tool-map.md for the real tool names + which tier (free vs.
credits) each call burns. If a tool name there isn't present in-session, list
the actual mcp__brightdata__* tools and use those — never guess a tool name.
- Read
references/opportunity-scoring.md — it holds the scoring rubric and the
opportunity-type taxonomy used in Phase 5.
How to invoke
- Whole flow: "find GEO opportunities for
<product URL>" → runs Phase 1 → 5,
pausing for input at Phase 2 and at the Phase 3 credit checkpoint.
- A single phase: pass
--phase or just ask ("just profile my product",
"regenerate the prompt list", "score the opportunities from the diagnosis").
- Each phase reads any prior phase's saved Markdown from
opportunity-research/<product-slug>/ if present, else runs what it needs.
Output location
Write all artifacts as clean Markdown a non-technical founder can read, under the
user's current directory:
opportunity-research/<product-slug>/
├── 01-product-profile.md
├── 02-validated-categories.md
├── 03-candidate-prompts.md
├── 04-geo-diagnosis.md
└── 05-opportunity-matrix.md ← the hero deliverable
Announce the file path after writing each one.
PHASE 1 — Product Intake
Goal: understand the product well enough to judge prompt relevance later.
- Take the user's product URL + one-sentence description. Scrape the page with
mcp__brightdata__scrape_as_markdown (free).
- Extract a product profile: what it does (1-2 lines), core features, primary
use cases, ICP / buyer, the category it competes in, any competitors named on
the page, and the key entities/specs/numbers it owns.
- Write
01-product-profile.md and show it back. Ask the user to correct anything
wrong before continuing — a bad profile poisons every later relevance score.
Output ends with Sources: the URL scraped.
PHASE 2 — Category Validation (interactive)
Goal: prune the search space so paid calls aren't wasted on off-target prompts.
- From the profile, derive 4-8 candidate topic categories / angles the product
could plausibly be the answer for (e.g. for a payments-address tool: address
validation, sanctions screening, ISO 20022 structured address, STP rates,
payment data quality).
- Use AskUserQuestion (multiSelect) to let the user confirm which categories
are in scope and cut the irrelevant ones. Let them add categories you missed.
- Write
02-validated-categories.md listing the kept categories (and what was cut).
PHASE 3 — Prompt Discovery (free; ends at the credit checkpoint)
Goal: a list of ~15-20 real long-tail prompts, grounded in live search data.
- For each validated category, draft candidate prompts across families: question
forms, "best X for Y", "X vs Y", alternatives-to, "how do I…", integration/spec
questions.
- Ground them in reality — do NOT ship hallucinated prompts. For category
seeds, fire
mcp__brightdata__search_engine (engine: "google",
optional geo_location) and harvest the live People Also Ask + related
searches. Keep/expand prompts that map to real surfaced queries; this is also
where genuine long-tail demand shows up. Pipe collected SERP JSON through the
helper if useful:python3 scripts/cluster_serp.py < serp.json
- Pre-rank candidates by relevance to the Phase 1 profile, dedupe, and trim to
~15-20. Tag each with its source category and whether it came from PAA/related
(real) vs. constructed-but-plausible.
- Write
03-candidate-prompts.md and STOP. Show the list to the user and ask
them to cut/approve. The next phase spends Bright Data credits (one paid call
per prompt) — do not proceed until the user approves the final set.
Output ends with Sources: every SERP query run + PAA/related pulled.
PHASE 4 — GEO Diagnosis at scale (credits — only after approval)
Goal: for each approved prompt, capture what AI search cites today and why.
- For each approved prompt, fire
mcp__brightdata__web_data_chatgpt_ai_insights
(prompt) one at a time (sequentially) — parallel calls trigger transient
HTTP 400: Customer is not active; a sequential retry succeeds. ChatGPT is the
default engine because it's the only one returning explicit cited URLs.
Perplexity (prose, usually no URLs) and Grok (often empty [{}]) are optional
cross-checks — only add them if the user asks, since each is another paid call
per prompt. If a call returns empty, mark "⚠️ Live data unavailable" — never invent.
- Capture per prompt: the answer text + the cited source URLs. Dedupe cited
URLs across all prompts, then scrape them with
mcp__brightdata__scrape_batch
as Markdown (≤5 URLs per call — batch in groups of 5).
- For each cited page, read the citation pattern via
references/geo-citation-patterns.md and note its page type (blog / listicle
/ product page / docs / Wikipedia / standards body / Reddit / etc.) and a
recognizability/authority read (proxy).
- Write
04-geo-diagnosis.md: per prompt → who's cited, page types, whether the
citations actually answer the prompt, and whether the user's own domain appears.
Output ends with Sources: every AI prompt run + every cited URL scraped.
PHASE 5 — Opportunity Matrix (free — the deliverable)
Goal: rank the prompts into a clear "go capture these" list.
- Score every prompt on two axes using
references/opportunity-scoring.md:
- Capturability (from what's cited): 🟢 nothing cited → 🟢 irrelevant cited →
🟡 recreatable page cited → 🔴 hard-to-beat cited → ⚪ you're already cited.
- Relevance: how well the product (Phase 1 profile) actually answers the prompt.
The helper turns the Phase-4 evidence JSON into a ranked matrix:
python3 scripts/score_opportunities.py < diagnosis.json
(or score inline if it errors — it only organizes scraped evidence, never invents).
- Classify each prompt's opportunity type and the recommended capture move
(new blog post / product page / comparison page / FAQ / schema add).
- Write
05-opportunity-matrix.md: a ranked table —
prompt → capturability → relevance → who's cited now → opportunity type → capture move. Lead with the top-right quadrant (easy and relevant) as the
priority targets. Label demand/authority reads as proxies.
Output ends with Sources: the diagnosis + SERP evidence each score rests on.
OPTIONAL — Capture a chosen opportunity
If the user picks an opportunity row, generate the content to capture it (this is
the old content-engine, now a follow-on, not the core):
- Build an evidence bundle from Phases 1-4 for the chosen prompt (cited competitors
- their winning patterns, shared entities, PAA to answer verbatim, schema seen).
- Fill
templates/content-brief.md (helper: python3 scripts/format_brief.py evidence.json) → a brief with target prompt + intent, title/H1, H2/H3 outline
mapped to PAA + entities, a ≤60-word extractable direct-answer block,
FAQ/schema recommendations, entity checklist, internal-link notes — each item
citing the scraped competitor/PAA it came from.
- Draft the article to that brief: direct answer up top under each question,
lists/tables where the cited winners used them, skimmable. Mark any spot needing
a real stat the user must supply as
[NEEDS SOURCE: …] — never invent a number.
Save as capture-brief.md / capture-draft.md, each ending with its Sources.
OPTIONAL — Track
Re-run Phase 4 on the captured prompts later to see if the user's page is now
cited. Output a before/after table (date, prompt, was-cited?, notable changes).
Save as tracking-<date>.md.
Style for all outputs
- Plain language, short sentences, tables over walls of text.
- Lead with the takeaway (the winnable prompts), then the evidence.
- Always close with Sources (real URLs + the live queries used). If a section
has no live source, it doesn't belong in the output.
1---2name: geo-gap-finder3description: Live-data GEO (Generative Engine Optimization) opportunity finder, powered by the Bright Data MCP. Give it your product and it runs deep research to find the AI-search prompts you can actually WIN — the prompts where ChatGPT cites nobody, cites something irrelevant, or cites a page you could easily beat. It profiles your product, validates which topics are in scope, discovers 15-20 real long-tail prompts people are searching, runs live GEO citation diagnosis on each, then ranks them into an opportunity matrix scored by how easy each one is to capture. Every prompt, citation, and score is grounded in something scraped live in this run. Nothing comes from training-data memory. Sources are always cited. Search volume and domain authority are labeled as PROXIES (no such metric exists in this data source) — never invented numbers. Trigger whenever the user wants to: find GEO / AI-search opportunities for their product, figure out "where can I rank in AI search", "which prompts should I target", "what AI-search gap4---56# GEO Opportunity Finder78A guided, multi-phase deep-research flow whose whole purpose is to find the9**AI-search prompts your product can actually win** — and prove each one is10winnable with **live data scraped right now** via the **Bright Data MCP** (server11name: `brightdata`). It exists to defeat the #1 objection to AI-generated SEO/GEO12advice — *"the AI just hallucinates"* — so the prime directive is non-negotiable:1314> **NO-FABRICATION RULE.** Never state a prompt, ranking, competitor, citation,15> metric, or "best practice" unless it came from a live tool call in THIS run. If16> a live call fails or returns nothing, write **"⚠️ Live data unavailable for this17> step"** and stop that step. Do not fill the gap from memory. Do not invent search18> volumes, citation counts, domain-authority scores, or URLs. **Search volume and19> domain authority do not exist in this data source — treat any demand/authority20> read as a labeled PROXY** (People Also Ask / related presence; organic SERP rank21> + recognizability). Every output ends with a **Sources** section listing the22> exact URLs/queries it pulled.2324## The big idea2526Most SEO tools tell you how to rank for a keyword you already picked. This skill27answers the question that comes *first*: **which battles are even worth fighting?**28It scans many prompts about your product and ranks them by how easy they are to29capture in AI search. The opportunity matrix is the deliverable. Writing the30content to capture a chosen opportunity is an *optional* follow-on.3132**An opportunity is a prompt where (your hypothesis, made measurable):**33- 🟢 **Nothing is cited** — the AI answers from memory; any solid page can become the source.34- 🟢 **Something irrelevant is cited** — the cited pages don't really answer the prompt.35- 🟡 **A recreatable page is cited** — a blog, listicle, product page, Q&A, or Reddit thread you could out-build.36- 🔴 (not an opportunity) **A hard-to-beat source is cited** — official docs, Wikipedia, standards bodies, gov, top-brand domains.37- ⚪ (defend, not capture) **Your own domain is already cited.**3839## Prerequisites (check first)40411. The `brightdata` MCP server must be connected. Confirm `mcp__brightdata__*`42 tools are available. If **not**, tell the user: *"The Bright Data MCP isn't43 loaded. Copy `.mcp.json.example` → `.mcp.json`, paste your API token (raw, not44 `${VAR}`), restart Claude Code, then re-run."* Do not attempt the phases without it.452. Skim `references/tool-map.md` for the **real** tool names + which tier (free vs.46 credits) each call burns. If a tool name there isn't present in-session, list47 the actual `mcp__brightdata__*` tools and use those — never guess a tool name.483. Read `references/opportunity-scoring.md` — it holds the scoring rubric and the49 opportunity-type taxonomy used in Phase 5.5051## How to invoke5253- **Whole flow:** "find GEO opportunities for `<product URL>`" → runs Phase 1 → 5,54 pausing for input at Phase 2 and at the Phase 3 credit checkpoint.55- **A single phase:** pass `--phase` or just ask ("just profile my product",56 "regenerate the prompt list", "score the opportunities from the diagnosis").57- Each phase reads any prior phase's saved Markdown from58 `opportunity-research/<product-slug>/` if present, else runs what it needs.5960## Output location6162Write all artifacts as clean Markdown a non-technical founder can read, under the63user's current directory:6465```66opportunity-research/<product-slug>/67├── 01-product-profile.md68├── 02-validated-categories.md69├── 03-candidate-prompts.md70├── 04-geo-diagnosis.md71└── 05-opportunity-matrix.md ← the hero deliverable72```7374Announce the file path after writing each one.7576---7778## PHASE 1 — Product Intake7980**Goal:** understand the product well enough to judge prompt relevance later.81821. Take the user's product URL + one-sentence description. Scrape the page with83 **`mcp__brightdata__scrape_as_markdown`** (free).842. Extract a **product profile**: what it does (1-2 lines), core features, primary85 use cases, ICP / buyer, the category it competes in, any competitors named on86 the page, and the key entities/specs/numbers it owns.873. Write `01-product-profile.md` and show it back. Ask the user to correct anything88 wrong before continuing — a bad profile poisons every later relevance score.8990**Output ends with Sources:** the URL scraped.9192---9394## PHASE 2 — Category Validation *(interactive)*9596**Goal:** prune the search space so paid calls aren't wasted on off-target prompts.97981. From the profile, derive 4-8 candidate **topic categories / angles** the product99 could plausibly be the answer for (e.g. for a payments-address tool: address100 validation, sanctions screening, ISO 20022 structured address, STP rates,101 payment data quality).1022. Use **AskUserQuestion** (multiSelect) to let the user confirm which categories103 are in scope and cut the irrelevant ones. Let them add categories you missed.1043. Write `02-validated-categories.md` listing the kept categories (and what was cut).105106---107108## PHASE 3 — Prompt Discovery *(free; ends at the credit checkpoint)*109110**Goal:** a list of ~15-20 **real** long-tail prompts, grounded in live search data.1111121. For each validated category, draft candidate prompts across families: question113 forms, "best X for Y", "X vs Y", alternatives-to, "how do I…", integration/spec114 questions.1152. **Ground them in reality** — do NOT ship hallucinated prompts. For category116 seeds, fire **`mcp__brightdata__search_engine`** (`engine: "google"`,117 optional `geo_location`) and harvest the live **People Also Ask** + **related118 searches**. Keep/expand prompts that map to real surfaced queries; this is also119 where genuine long-tail demand shows up. Pipe collected SERP JSON through the120 helper if useful:121 ```bash122 python3 scripts/cluster_serp.py < serp.json123 ```1243. Pre-rank candidates by relevance to the Phase 1 profile, dedupe, and trim to125 ~15-20. Tag each with its source category and whether it came from PAA/related126 (real) vs. constructed-but-plausible.1274. Write `03-candidate-prompts.md` and **STOP. Show the list to the user and ask128 them to cut/approve.** The next phase spends Bright Data credits (one paid call129 per prompt) — do not proceed until the user approves the final set.130131**Output ends with Sources:** every SERP query run + PAA/related pulled.132133---134135## PHASE 4 — GEO Diagnosis at scale *(credits — only after approval)*136137**Goal:** for each approved prompt, capture what AI search cites today and why.1381391. For each approved prompt, fire **`mcp__brightdata__web_data_chatgpt_ai_insights`**140 (`prompt`) **one at a time (sequentially)** — parallel calls trigger transient141 `HTTP 400: Customer is not active`; a sequential retry succeeds. ChatGPT is the142 default engine because it's the only one returning explicit cited URLs.143 Perplexity (prose, usually no URLs) and Grok (often empty `[{}]`) are optional144 cross-checks — only add them if the user asks, since each is another paid call145 per prompt. If a call returns empty, mark "⚠️ Live data unavailable" — never invent.1462. Capture per prompt: the answer text + the **cited source URLs**. Dedupe cited147 URLs across all prompts, then scrape them with **`mcp__brightdata__scrape_batch`**148 as Markdown (**≤5 URLs per call** — batch in groups of 5).1493. For each cited page, read the **citation pattern** via150 `references/geo-citation-patterns.md` and note its **page type** (blog / listicle151 / product page / docs / Wikipedia / standards body / Reddit / etc.) and a152 recognizability/authority read (proxy).1534. Write `04-geo-diagnosis.md`: per prompt → who's cited, page types, whether the154 citations actually answer the prompt, and whether the user's own domain appears.155156**Output ends with Sources:** every AI prompt run + every cited URL scraped.157158---159160## PHASE 5 — Opportunity Matrix *(free — the deliverable)*161162**Goal:** rank the prompts into a clear "go capture these" list.1631641. Score every prompt on two axes using `references/opportunity-scoring.md`:165 - **Capturability** (from what's cited): 🟢 nothing cited → 🟢 irrelevant cited →166 🟡 recreatable page cited → 🔴 hard-to-beat cited → ⚪ you're already cited.167 - **Relevance**: how well the product (Phase 1 profile) actually answers the prompt.168 The helper turns the Phase-4 evidence JSON into a ranked matrix:169 ```bash170 python3 scripts/score_opportunities.py < diagnosis.json171 ```172 (or score inline if it errors — it only organizes scraped evidence, never invents).1732. Classify each prompt's **opportunity type** and the **recommended capture move**174 (new blog post / product page / comparison page / FAQ / schema add).1753. Write `05-opportunity-matrix.md`: a ranked table —176 `prompt → capturability → relevance → who's cited now → opportunity type →177 capture move`. Lead with the **top-right quadrant** (easy *and* relevant) as the178 priority targets. Label demand/authority reads as proxies.179180**Output ends with Sources:** the diagnosis + SERP evidence each score rests on.181182---183184## OPTIONAL — Capture a chosen opportunity185186If the user picks an opportunity row, generate the content to capture it (this is187the old content-engine, now a follow-on, not the core):1881891. Build an evidence bundle from Phases 1-4 for the chosen prompt (cited competitors190 + their winning patterns, shared entities, PAA to answer verbatim, schema seen).1912. Fill `templates/content-brief.md` (helper: `python3 scripts/format_brief.py192 evidence.json`) → a brief with target prompt + intent, title/H1, H2/H3 outline193 mapped to PAA + entities, a ≤60-word extractable direct-answer block,194 FAQ/schema recommendations, entity checklist, internal-link notes — each item195 citing the scraped competitor/PAA it came from.1963. Draft the article to that brief: direct answer up top under each question,197 lists/tables where the cited winners used them, skimmable. Mark any spot needing198 a real stat the user must supply as `[NEEDS SOURCE: …]` — never invent a number.199200Save as `capture-brief.md` / `capture-draft.md`, each ending with its Sources.201202---203204## OPTIONAL — Track205206Re-run Phase 4 on the captured prompts later to see if the user's page is now207cited. Output a before/after table (date, prompt, was-cited?, notable changes).208Save as `tracking-<date>.md`.209210---211212## Style for all outputs213- Plain language, short sentences, tables over walls of text.214- Lead with the takeaway (the winnable prompts), then the evidence.215- Always close with **Sources** (real URLs + the live queries used). If a section216 has no live source, it doesn't belong in the output.