AnswerLine Start free

, GEO · Fundamentals · Analytics

GEO metrics vs SEO metrics: what maps and what doesn't

Most SEO metrics don’t carry over to AI answers: there is no ranked list of ten links to hold a position in, no impression count per answer, and no click-through rate you can observe from outside. The intent behind each metric (presence, prominence, share, traffic) does carry over, and each can be rebuilt from the structured fields an answer returns. Those fields differ by engine, so the tables below give the field per engine.

Definitions

The translation table

SEO metric GEO counterpart How well it maps
Average position Citation rate, plus first cited position in sources[] Partial. Being cited is binary and measurable; whether earlier source positions get more attention is not publicly established
Impressions Mention rate over a fixed prompt set Partial. You measure presence in a sample of prompts you chose, not in real user traffic
CTR AI referral sessions per cited page Weak. Only clicks are counted, and only where a source is identifiable (how)
Share of voice Citation share and mention share against named competitors Good. Both are fractions of a known denominator
SERP feature presence Answer block presence (shoppingCards, places/map, ads) Good, but field names and shapes differ per engine
Keyword rank tracking Fan-out query coverage in Google organic results New. Possible only where the engine exposes its searches
(none) Sentiment and framing of the mention New. Requires reading the text

The first row deliberately leaves out the order of ChatGPT’s entities[]: no public evidence shows that its order reflects preference.

Formulas

Compute every metric per engine and per market over a fixed prompt set P run at time t. Let A be the set of completed answers.

  1. Mention rate = |answers in A that mention the brand| / |A|
  2. Citation rate = |answers in A with at least one source URL on your domain| / |A|
  3. Citation share = (number of source entries on your domain, summed over A) / (number of source entries, summed over A)
  4. Mention share (vs a competitor set C) = mentions of your brand / mentions of any brand in C ∪ {you}, counted once per answer per brand
  5. First cited position = for each answer that cites you, the smallest position among your entries in sources[]; report the median, and report it alongside citation rate, never alone
  6. Block presence rate (block b) = |answers where block b contains your brand or domain| / |answers where block b is present|
  7. Fan-out coverage = |fan-out queries where your domain appears in Google organicResults[]| / |fan-out queries|
  8. Referral yield (page u) = AI referral sessions to u / number of answers citing u in the period

Block presence uses answers that contain the block as its denominator; otherwise an engine that rarely shows shopping cards looks like a failure. Citation share counts entries, so an answer with twenty sources dilutes your share more than one with four; that is intended, since you own less of that answer’s evidence.

For the share-of-voice variants and competitor weighting, see the share of voice framework.

Where each engine returns the data

All fields are under result in a synchronous response, or response.result for a completed async task. Many optional fields are omitted rather than returned empty, so read them with a default. “Empty today” marks ChatGPT fields that exist but come back empty on the ChatGPT answers served today.

Signal ChatGPT Perplexity Gemini Copilot Grok AI Mode Google Search
Answer text text text text text text text aioverview.text
Cited sources sources[] sources[] sources[] sources[] sources[] sources[] aioverview.sources[]
Inline citations citationPills[] (0-based id) citationPills[] (1-based) citationPills[] (1-based) citationPills[] (1-based) none citationPills[] (1-based) aioverview.citationPills[]
Fan-out queries searchQueries[] (free; empty today) none none coming searchQueries[] none n/a
Entities entities[] none none none none none knowledgeGraph (different concept)
Shopping inlineProducts[] (with include.shopping); shoppingCards[] empty today none none coming none shoppingCards[], inlineProducts[] shoppingCards[]
Places map[] none places[] coming none places[], map[] localResults[]
Ads ads[] array (with include.ads; empty today) none none none none ads object: {title, ads[]} ads[] array, aioverview.ads[]
Organic ranking n/a n/a n/a n/a n/a n/a organicResults[].position

Shapes differ inside the same concept. A ChatGPT shopping product title is inlineProducts[].product.title (shoppingCards[] is empty today: ChatGPT answers show no merchant cards); on AI Mode, shoppingCards[].title. The engine pages list every field.

Computing the metrics from stored answers

This function takes one stored answer and returns the per-answer facts the formulas need, handling the per-engine differences in one place so aggregation code stays engine-agnostic.

import re
from urllib.parse import urlsplit


def on_domain(url: str, domain: str) -> bool:
    host = urlsplit(url).netloc.lower().removeprefix("www.")
    return host == domain or host.endswith("." + domain)


def product_titles(engine: str, r: dict) -> list[str]:
    if engine == "CHATGPT":
        return [p.get("product", {}).get("title", "") for p in r.get("inlineProducts", [])]
    if engine == "AIMODE":
        return [c.get("title", "") for c in r.get("shoppingCards", [])] + [p.get("title", "") for p in r.get("inlineProducts", [])]
    return []


def answer_facts(engine: str, r: dict, brand: str, domain: str) -> dict:
    if engine == "GOOGLE":
        r = r.get("aioverview") or {}
    pattern = re.compile(rf"\b{re.escape(brand)}\b", re.IGNORECASE)
    sources = r.get("sources", [])
    mine = [s for s in sources if on_domain(s.get("url", ""), domain)]
    titles = product_titles(engine, r)
    ads = r.get("ads", [])
    ad_items = ads.get("ads", []) if isinstance(ads, dict) else ads  # object on AI Mode, array elsewhere
    return {
        "mentioned": bool(pattern.search(r.get("text") or "")),
        "sources_total": len(sources),
        "sources_mine": len(mine),
        "first_cited_position": min((s["position"] for s in mine if "position" in s), default=None),
        "shopping_present": bool(titles),
        "shopping_mine": any(pattern.search(t) for t in titles),
        "ads_present": bool(ad_items),
        "fan_out": r.get("searchQueries", []),
    }

Aggregate per engine and market: mention rate is the mean of mentioned; citation rate is the mean of sources_mine > 0; citation share is sum(sources_mine) / sum(sources_total); shopping presence rate is sum(shopping_mine) / sum(shopping_present). The Google branch reads the AI Overview only; skip answers where aioverview is null when computing AI Overview rates, and count them for an “AI Overview shown” rate instead. Ad brand matching needs its own per-engine accessor (ChatGPT ads[].brand.name, empty on the answers served today; AI Mode ads.ads[].store; Google ads[].domain); see tracking ads in AI answers.

What doesn’t map

The two-layer dashboard

Keep both pipelines. The retrieval layer is Google Search: organicResults[] positions for your keywords and for the fan-out queries of engines that return them. ChatGPT’s list comes back empty on the answers served today (chatgpt query fan-out). The answer layer is the monitor endpoints: mention rate, citation rate and share, block presence, per engine and market.

Cost per run at Starter-tier prices for an illustrative set of 100 prompts: ChatGPT $0.0006 and Gemini $0.0006, so $0.0012 per prompt and $0.12 per run. Adding 3 Google queries per prompt (an illustrative number) at $0.00103 each adds 100 × 3 × $0.00103 = $0.309, for $0.429 per run. Cost planning covers cadence choices.

The migration map walks the full move of an SEO reporting stack. For field details, start at the AI visibility tracking use case.

Questions

What is the GEO equivalent of search ranking position?

There is no exact equivalent. The closest measurable proxies are whether your domain is cited at all (citation rate), the position of your first cited source in the answer's sources list. Neither has been shown publicly to behave like a ranking, so report them as descriptive measures.

What is the difference between citation rate and citation share?

Citation rate is the fraction of answers that cite your domain at least once. Citation share is the fraction of all cited sources, across those answers, that are yours. A brand can have a high citation rate and a low share if it is cited once in answers that list many sources.

Which engines return an entities list?

Only ChatGPT. Its entities field is an array of type and name pairs for the brands and products the answer names. On Gemini and the other engines, measure mentions by matching your brand in the answer text.

Are ads and places returned the same way on every engine?

No. Ads are an array on ChatGPT and Google Search but an object with a title and an ads array on AI Mode; ChatGPT's ads array comes back empty on the answers served today. Places are returned as places and map on AI Mode, and as map on ChatGPT, with different item fields; Copilot's map results are coming.

Should I stop tracking Google rankings once I track AI answers?

Keep both. Google documents that AI Overviews and AI Mode may run multiple related searches to build a response, so classic rankings for those queries still describe part of the candidate pool, while answer monitoring describes what was said and cited.

Try it on your own prompts

100 free requests on any engine, no card. One POST returns the answer, sources and citations as JSON.

Keep reading