**open-geo is a GEO (generative engine optimization) visibility tracker: it measures whether your brand shows up in AI answers by reading the rendered answer a logged-in user actually sees.** Capture runs through an agent in a real, logged-in browser — not
FAQ
open-geo is a Claude Code plugin with 1 hand-picked skill for marketing work, indexed on Flowy. Install it with the command on its page. It includes open-geo. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
> /plugin marketplace add Pupok462/open-geo> /plugin install open-geo@open-geo-marketplace
open-geo is a GEO (generative engine optimization) visibility tracker: it measures whether your
brand shows up in AI answers by reading the rendered answer a logged-in user actually sees.
Capture runs through an agent in a real, logged-in browser — not the engine's API and not a
headless scrape, because those don't match the answer a person is shown. It covers Google AI
Overview, ChatGPT, Claude, Gemini, Yandex Alice and DeepSeek, and reports an honest funnel
(queries → answers → sources → citations) that says when a run can't be trusted instead of
guessing. It runs as a Claude Code skill: point /open-geo at a question set and a domain,
get a dashboard and a PDF.
Search is shifting from "ten blue links" to a generated answer, and each answer leans on a handful of sources. Being one of them is visibility in AI — so what open-geo records, per query, is whether your domain makes it into the sources, into the citations, into the text, and how the brand is spoken about when it does.
| What it is | A GEO / AI-visibility tracker for a brand or a URL, packaged as a Claude Code skill |
| How it measures | An agent reads the rendered AI answer in a real, logged-in browser (Claude-in-Chrome) |
| Engines covered | Google AI Overview, ChatGPT, Claude, Gemini, Yandex Alice (Нейро), DeepSeek — Perplexity playbook written, awaiting live validation |
| What it reports | A funnel — answer coverage → visibility in sources → visibility in citations — plus positions, source→citation conversion, brand-mention rate, qualitative sentiment, and a top-domains leaderboard |
| Deliverables | A local dashboard (FastAPI + React, 4 languages) and a themed PDF, from a local SQLite history |
| Operating model | An on-demand audit you run yourself, not a 24/7 hosted monitor |
| Requirements | Claude Code, the Claude-in-Chrome extension, a browser logged in to the engine. No data API, no paid keys |
| License | MIT |
engines/<engine>.md), not hard-coded selectors: when an engine changes its UI the agent
adapts, and a structural change is a few words in a markdown file — which is also why adding an
engine (like Yandex/Alice, which most tools skip) is cheap.pipeline/INTERFACES.md./open-geo at a CSV and a
domain, get a dashboard. No SaaS, no upload, no account.Three different shapes solve "am I visible in AI answers?", and they are not interchangeable. This table is about what each shape is built for, so you can pick the right one:
| open-geo | Hosted AI-visibility monitoring | A DIY API / scraping script | |
|---|---|---|---|
| What it reads | The rendered answer inside a real, logged-in browser session | A vendor-operated capture pipeline | Whatever the engine's API or the fetched HTML returns |
| Engine coverage | Six engines today, including Yandex Alice and DeepSeek; adding one is a markdown playbook, not a parser | Set by the vendor's roadmap | Whatever you build and keep building |
| When the UI changes | The agent follows a natural-language playbook (engines/<engine>.md), so a structural change is a few words in a file | Handled for you, on the vendor's schedule | Yours to fix when the markup moves |
| Operating model | An on-demand audit you trigger and supervise | Continuous monitoring over large prompt sets | Whatever you schedule |
| Scale | Tens to low hundreds of queries per run; costs inference and attention | Thousands of prompts, hands-off | Bounded by your budget and rate limits |
| Where results live | Local SQLite history, local dashboard and PDF | The vendor's cloud | Wherever you put them |
| When the data is shaky | A grounded-answer gate and a nested funnel; a run is flagged, never guessed | Vendor-defined | Yours to design |
The trade-off is deliberate: fidelity over volume. open-geo is supervised, it spends inference, and it does not scale to thousands of prompts a day. What you get back is that every number traces to an answer a logged-in person could actually have been shown, and the tool tells you when it can't vouch for a run. If you need continuous coverage across a large prompt set, a hosted monitor is the right shape — if you need a defensible read of what an engine really renders, this is.
relative_citation), plus a brand mention rate — the share of
answers whose text names the brand, linked or not (an adjacent axis, not a funnel stage) — and a
short free-text note on how each answer treats the brand. The dashboard and PDF also show a per-lens qualitative sentiment
summary synthesized from those per-query notes (see Metrics).robots.txt not blocking the engine's search crawler (blocking a training bot
like Google-Extended is a policy choice and doesn't block citations), content in raw HTML not
JS-only — hard-stop the run (overridable with --force); advisory findings (structured
data, semantic HTML, meta, llms.txt, entity/trust, freshness) ship with a concrete fix but
never block it. It runs first, is stored, and surfaces in the PDF and the dashboard. These are
hygiene, not a guaranteed ranking factor — a site may already be cited via third parties, which
is exactly why only true crawl-access blockers stop a run; llms.txt (not llm.txt) is an
emerging ~10–15%-adoption convention, cheap to add but unproven.data/aeo.db (SQLite, WAL),
so you accumulate history per brand + engine and get run-over-run deltas.--repeat R captures the same question set R times as
R ordinary runs sharing one group (). The dashboard reads the group as : the seven metrics are aggregated across the repeats and every KPI card shows a
instead of a delta — a stability signal, not a precision claim (single AI
answers are noisy; the spread says when a number can't be trusted). The trend chart gains a
toggle (ISO-week rollup).open-geo is a Claude Code skill — you drive it from a chat with Claude, not from a pile of shell commands. The whole setup is: clone, ask Claude to install it, then use it as a command.
Clone the repo (or just point Claude at the URL):
git clone <repo> open-geo
Ask Claude to set it up. In a Claude Code session in that folder, say something like:
Set up open-geo (run
scripts/setup.sh), then trackexample.com(brand "Example") onexamples/questions.csv.
Claude runs the install and the capture for you — and prints a dashboard link and a summary.
Or run it directly as a command once installed:
/open-geo examples/questions.csv google example.com --brand "Example" --n-worker 3 --output both
examples/questions.csvis a placeholder — a fictional brand's question set, there so the first run works out of the box. For a real read, swap in your own queries: the question set is the core input — it decides what gets measured, and the report is only as good as the questions you ask. Format and how to choose them: What input do I need?.
Or install it as a Claude Code plugin — registers the command and its worker agents in any session:
/plugin marketplace add Pupok462/open-geo
/plugin install open-geo@open-geo-marketplace
Plugin skills are namespaced, so the plugin-installed command is
/open-geo:open-geo(from a repo clone it stays plain/open-geo). The plugin is a discovery wrapper: the pipeline still runs from a repo clone (steps 1–2 above), and the command says exactly that if invoked outside one. To pick up a new release later, run/plugin update open-geo.
Track it on a schedule. Wrap the command in Claude Code's /loop to re-capture on an
interval and watch the drift — e.g. a weekly read:
/loop 1w /open-geo examples/questions.csv google example.com --brand "Example" --n-worker 3 --output both
The one thing Claude can't do for you: connect the Claude-in-Chrome extension and log the browser in to the market you want to track. That logged-in session is what capture drives.
Everything runs through one operator command — the /open-geo skill. You don't touch
Python: Claude orchestrates capture → metrics → deliverables and hands you a dashboard and/or a PDF.
/open-geo <questions.csv> <engine> <domain> --brand "<name>" --n-worker <N> \
[--output dashboard|pdf|both] [--period today|all] [--lang en|ru|zh|ar]
| argument | meaning |
|---|---|
<questions.csv> | CSV with columns query,lens, where lens ∈ general | branded | comparative. Ready sample: examples/questions.csv. |
<engine> | which AI engine to track (e.g. google). The same slot takes any engine that has a capture playbook under engines/. |
<domain> | the target domain or URL prefix (github.com, github.com/user, github.com/user/repo; any spelling — normalized automatically). |
--brand "<name>" | human brand name (used in report/dashboard titles and the summary). |
--n-worker <N> | number of capture workers run in parallel — the run's concurrency. |
--output | dashboard (default) | pdf | both. |
--period | all (default — full brand+engine history, with the trend chart) | today (this run only). |
--lang | UI language of the deliverables — en (default) | ru | zh | ar. |
What it does, end to end: creates a run → splits the queries across parallel capture workers
(each drives the engine in your logged-in Chrome and returns one validated record per query) →
ingests and scores them centrally → emits the dashboard and/or PDF → prints a short summary from
the cross-lens all row. Re-run on a /loop to track drift over time.
The whole tracker is orchestrated by the /open-geo command:
engines/<engine>.md) is driven by
Claude-in-Chrome in a visible, logged-in Chrome. It reads the rendered AI answer as an
LLM does, expands the sources panel and the inline citation chips, normalizes domains, and emits
one QueryCapture object per query.QueryCapture — the validated capture contract (Pydantic v2; authoritative spec in
pipeline/INTERFACES.md).all row.The pipeline is engine-agnostic: engine is an open id end to end (contract, DB, CLI,
dashboard, report), and supporting a new engine is mainly a new engines/<engine>.md playbook —
see engines/README.md.
The funnel, in plain words. The four counts narrow down at each step:
Each step is a subset of the one before it, so the counts nest:
n_cited ≤ n_in_sources ≤ n_overviews ≤ n_queries. (Citations are a subset of sources because the
model can only cite what it retrieved.) The denominator for visibility is answer-present queries
— you can only be visible where an answer actually rendered. Everything is computed per lens
(general / branded / comparative) plus an aggregate all row.
The seven metrics are just ratios and positions along that funnel — plus one adjacent axis:
overview_coverage — share of queries that produced an AI answer at all
(n_overviews / n_queries).visibility_in_sources — of answer queries, the share where your domain made it into the
relied-on sources (n_in_sources / n_overviews).visibility_in_citations — of answer queries, the share where your domain is cited in
the answer (n_cited / n_overviews).avg_source_position — average best (min) rank of your domain among sources, over the
queries where it appears (lower is better; — if it never appears).avg_citation_position — average best (min) rank among citations, over the queries where
it is cited (lower is better; — if never cited).relative_citation — the source→citation conversion: of the queries where you were
retrieved into sources, the share where the model actually cited you (n_cited / n_in_sources;
higher is better, bounded to [0, 1]).brand_mention_rate — of answer queries, the share where the answer text mentions the
brand name — linked or not (n_brand_mentions / n_overviews). It surfaces the per-query
brand_in_answer_text field capture has always recorded, as a plain share — not a composite
index. An adjacent axis, not a funnel stage: an unlinked mention is invisible to the link
funnel (mentioned does not imply cited, and cited does not imply mentioned), so the three-step
funnel and its inequality are unchanged.all synthesis), shown as a
"Sentiment by lens" strip in the dashboard and as the lead of the PDF's sentiment section. It
follows the language of the captured data, not --lang.A top-domains leaderboard (INTERFACES §4.2) ranks every domain in the answers — your brand
highlighted — by appearances and average source/citation position, for honest competitive context
computed from the same captured data. There is still intentionally no composite index, no
share-of-voice index, and no numeric sentiment — the leaderboard is plain frequencies and
positions, not a blended score. Deltas between runs are computed at read-time against the
previous completed run of the same brand + engine; they are not stored. Authority:
pipeline/INTERFACES.md §4.
Every run produces two deliverables — a themed PDF report and a local dashboard, both built from the same scored run.
The PDF's key-metrics page (from the seeded Example demo — engine google;
download the full sample PDF):
The dashboard — KPI cards with read-time deltas, the per-lens breakdown, a "Sentiment by lens" strip, a "Top domains in answer space" leaderboard, a retrospective chart and a per-query table, with a four-language switcher and light/dark themes:
At the end of a run, /open-geo prints a short headline summary built from the lens="all" row
(here, the seeded Example demo — engine google, run of 2026-06-09):
Run for brand "Example" (engine google), queries: 24.
• Answer coverage: 83% (20 of 24 queries).
• Visibility in sources: 60% of overview queries.
• Visibility in citations: 45% of overview queries.
• Average source position: 2.5 (lower is better).
• Average citation position: 1.0 (lower is better).
• Source→citation conversion (relative citation): 75% (higher is better).
• Brand mention rate: 55% of grounded answers name the brand.
The seven metrics for lens="all", with the underlying funnel counts
(n_queries = 24 → n_overviews = 20 → n_in_sources = 12 → n_cited = 9):
| Metric | Value | Plain meaning | Direction |
|---|---|---|---|
overview_coverage | 0.83 (20/24) | Share of queries where an AI answer rendered at all | higher = better |
visibility_in_sources | 0.60 (12/20) | Of answer queries, share where example.com made it into the relied-on sources | higher = better |
visibility_in_citations | 0.45 (9/20) | Of answer queries, share where the domain is cited in the answer prose | higher = better |
avg_source_position | 2.50 | Average best (min) rank among sources, over queries where it appears | lower = better |
avg_citation_position | 1.00 | Average best (min) rank among citations, over queries where it is cited | lower = better |
relative_citation | 0.75 (9/12) | Source→citation conversion (last funnel step, ∈ [0, 1]) | higher = better |
A value renders as — (not 0) when its guard trips — e.g. for the comparative lens in this run
the domain never reached sources, so the three source/citation metrics are all —.
GEO is the practice of getting a brand surfaced and cited inside AI-generated answers, rather than ranked in a list of links. It is also called AEO (answer engine optimization). The measurement problem is different from SEO's: there is no rank position to read, so what you track is whether an answer retrieved you, whether it cited you, and where in the answer you landed.
Yes — open-geo is one. It installs as a Claude Code skill and runs as a single command,
/open-geo <questions.csv> <engine> <domain>, driving your logged-in Chrome through the
Claude-in-Chrome extension. You can also add it as a plugin with
/plugin marketplace add Pupok462/open-geo.
Six today: Google AI Overview, ChatGPT (web search), Claude (web search), Google Gemini, Yandex
Alice / Нейро, and DeepSeek (web search). A Perplexity playbook is written and awaiting its first
live validation run. Each engine is a natural-language playbook in
engines/, so adding one is writing a markdown file, not a parser.
Yes, both are supported engines — yandex_neuro and deepseek. They matter because Russian- and
Chinese-market answer engines are commonly left out of Western tooling, and each has its own quirks
the playbook handles (Yandex mixes paid "Промо" cards in with sources, which open-geo deliberately
keeps out of sources and citations; DeepSeek numbers its retrieved set like Perplexity does).
The real UI. An agent drives a visible, logged-in Chrome and reads the answer as it was rendered to a person — the sources panel, the inline citation chips, the answer text. This is the core design choice: API and headless reads do not match what a logged-in user is actually shown, so they measure a surface nobody sees.
An audit you run on demand. A run is supervised, spends inference, and measures the questions
you chose — so it is built for a point-in-time read you can defend, not for continuous coverage of
a large prompt set. If you want it repeated, wrap the command in Claude Code's /loop (e.g. weekly)
or use --repeat R to capture the same set several times and read the min–max spread.
Different shape, on purpose: open-geo trades volume for fidelity. It reads the rendered answer in your own logged-in browser, keeps the history locally, and flags a run it can't vouch for instead of guessing — at the cost of scale and of being hands-on. A hosted monitor is the better fit when you need thousands of prompts tracked continuously without supervision. See How open-geo compares.
Yes. The target accepts a domain (example.com) or a URL prefix
(github.com/user/repo), so you can measure a single repo, a docs section or a subfolder. Prefix
matching is conservative: a link that only names the domain is not counted as a match when your
target has a path.
Your own list of questions — a CSV with two columns, query,lens, where lens ∈ general | branded | comparative (general = neutral query with no brand named; branded = brand explicitly
named; comparative = brand vs alternatives). You author this file, and it is the single most
important input: GEO visibility is measured relative to the questions you ask, so the whole
report is only as good as the question set. Write the queries your real customers would type,
balanced across the three lenses (a handful of each is enough to start). The bundled
examples/questions.csv is a placeholder for a fictional brand — use
it to see the format, then replace it with yours.
Don't have a list yet? open-geo can harvest one for you. If you don't pass a CSV, the wizard
offers to generate a grounded set (question harvesting): recon sub-agents gather real,
signal-backed user queries across several angles on your product (demand, supply, category,
reputation, comparisons), a skeptic pass cuts anything invented or mislabeled, and you get a
query,lens CSV plus a *_rationale.md explaining why these questions — which you review
(apply / edit / discard) before the run. It is grounded, not made-up (every query traces to an
observable signal), and fully opt-in — your own hand-made CSV is always a first-class input. The
process is documented in harvest/METHODOLOGY.md.
No external data API and no paid keys. You need Claude Code, the Claude-in-Chrome extension connected, and a browser already logged in to the engine / market you want to track.
No. open-geo is a local tool: every run is stored in a local SQLite (WAL) database at
data/aeo.db, and the deliverables are a local PDF and a local dashboard you run yourself.
There is no SaaS and no account, so the methodology is yours to inspect and reproduce. (Capture
itself runs through Claude Code / Claude-in-Chrome, so it is not an offline or air-gapped tool.)
Because six of them form a funnel (answer → sources → citations) — the seventh, the brand
mention rate, is an adjacent plain share, not another index — and collapsing it into one number
invites hand-wavy weighting and invented baselines. Every number is auditable to one formula in
pipeline/INTERFACES.md §4, plus a free-text sentiment note that is never
reduced to a number. A top-domains leaderboard (§4.2) gives competitive context as plain
frequencies + positions — still no composite index and no share-of-voice index.
--n-worker, and how long does a run take?--n-worker N is the run's concurrency: the queries are split into N chunks and N capture
sub-agents run in parallel, each in its own browser tab/context. A single-query capture is
roughly 6–10 tool calls, so wall-clock time scales with how many queries each worker handles in
sequence — raise --n-worker to shorten a large run (within reason, to stay under the engine's
"unusual traffic" radar).
Yes — MIT-licensed, and there is no data API or paid key in the loop. Running it does spend your own Claude Code inference, and it needs a browser already logged in to the engine you want to measure.
MIT. Release notes are in CHANGELOG.md.
.claude/
.claude-plugin/
marketplace.json
plugin.json
README.md
agents/
capture-worker.md
harvest-skeptic.md
harvest-worker.md
skills/
open-geo/
SKILL.md
.github/
workflows/
ci.yml
.gitignore
assets/
cover.svg
dashboard-ar.png
dashboard-en.png
dashboard-ru.png
dashboard-zh.png
demo.gif
report-cover.png
report-metrics.png
sample-report-example.pdf
social-preview.png
audit/
__init__.py
bots.py
cache.py
CHECKS.md
checks.py
fetch.py
gate.py
html.py
README.md
robots.py
schema.py
CHANGELOG.md
conftest.py
dashboard/
__init__.py
api.py
README.md
seed_fixture.py
web/
.gitignore
index.html
package-lock.json
package.json
postcss.config.js
src/
redesign/
components/
AuditPanel.test.tsx
AuditPanel.tsx
CompetitorsPanel.test.tsx
CompetitorsPanel.tsx
EngineMatrix.test.tsx
EngineMatrix.tsx
icons.test.tsx
icons.tsx
LensBreakdown.test.tsx
LensBreakdown.tsx
LensSentiment.test.tsx
LensSentiment.tsx
MetricCard.test.tsx
MetricCard.tsx
MetricsChart.logic.test.tsx
MetricsChart.render.test.tsx
MetricsChart.tsx
primitives.test.tsx
primitives.tsx
ResultsTable.test.tsx
ResultsTable.tsx
lib/
api.test.ts
api.ts
format.test.ts
format.ts
i18n.test.tsx
i18n.tsx
metrics.test.ts
metrics.ts
theme.ssr.test.tsx
theme.test.tsx
theme.tsx
main.tsx
RedesignApp.test.tsx
RedesignApp.tsx
test/
setup.ts
theme.css
tsconfig.json
vite-env.d.ts
tsconfig.app.json
tsconfig.json
tsconfig.node.json
vite.config.ts
vitest.config.ts
data/
.gitkeep
docs/
.nojekyll
.well-known/
security.txt
feed.xml
index.html
llms.txt
robots.txt
sitemap.xml
engines/
chatgpt_search.md
claude_search.md
deepseek.md
gemini.md
google.md
perplexity.md
README.md
yandex_neuro.md
examples/
questions.csv
fonts/
build.py
NotoNaskhArabic-Bold.ttf
NotoNaskhArabic-Regular.ttf
NotoSansSC-Bold.ttf
NotoSansSC-Regular.ttf
OFL-NotoNaskhArabic.txt
OFL-NotoSansSC.txt
README.md
harvest/
__init__.py
build.py
METHODOLOGY.md
README.md
schema.py
i18n/
ar.json
en.json
locales.json
README.md
ru.json
zh.json
LICENSE
pipeline/
__init__.py
aggregate.py
db.py
ingest.py
INTERFACES.md
lens_sentiment.py
schema.py
seed_demo.py
pyproject.toml
README.ar.md
README.md
README.ru.md
README.zh.md
report/
__init__.py
_selftest_fixture.py
generate.py
i18n.py
textshape.py
reports/
.gitkeep
requirements.txt
scripts/
setup.sh
tests/
__init__.py
test_aggregate.py
test_api.py
test_audit_bots.py
test_audit_checks.py
test_audit_fetch.py
test_audit_gate.py
test_audit_html.py
test_audit_robots.py
test_audit_schema.py
test_db.py
test_domain_stats.py
test_fixtures.py
test_harvest.py
test_ingest.py
test_lens_sentiment.py
test_pipeline.py
test_report_audit.py
test_report_format.py
test_report_i18n.py
test_report_render.py
test_schema.py
test_seed_demo.py© 2026 Flowy · Free and open source
Built for Claude Code · Not affiliated with Anthropic
group_idreport.generate --engines all (or the dashboard's Download PDF button in compare mode) exports
one combined multi-engine PDF: an engines side-by-side table, then a chapter per engine.