Tutorial2026-07-146 min read

How to measure share of voice in Gemini

Share of voice in Gemini is the share of your category's answers that belong to you rather than your competitors. On a search-grounded engine you'd measure it twice — mentions and citations — but Gemini is a chatbot, and it only cites when it grounds an answer by browsing. A citation-share percentage here would be computed over whichever answers happened to browse that day, which is a denominator that moves for reasons that have nothing to do with your market. So measure the honest thing: mention share across a fixed query set. Run every query, count which brands each answer names, and divide. The arithmetic is trivial; the discipline is not. A percentage means nothing without the query set, the brand set and the date printed next to it, and this guide is mostly about that.

Tutorial

To measure share of voice in Gemini, fix a query set and a competitive set, run every query, and count how many answers name each brand. Two numbers fall out: mention rate (the share of answers that name you) and share of voice (your mentions as a share of all tracked brands' mentions). Report both, alongside the query set and the run date — on this surface citation share isn't a reliable metric, because most answers don't cite at all.

The manual way (and why it stops working)

Do this on paper once; it's worth the afternoon. Pick ten questions a buyer would genuinely type, run each in Gemini, and for every brand you track put a tick in a column when the answer names it. Ten rows of ticks later you can divide and get real percentages — and you'll have learned more about how your category gets described than any dashboard was going to tell you.

Then try to do it again next month.

  • Ten queries is the floor and, by hand, also the ceiling. A share of voice computed over four answers is noise with a percent sign after it. Thirty queries transcribed by hand is a job nobody does twice.
  • Ticking boxes drifts. A brand named twice in one reply, a near-miss spelling, a name buried in a bulleted aside — manual counting makes small consistent errors, and consistent errors look exactly like trends.
  • The denominator slips. Skip one answer that didn't load and every percentage silently changes base. A script can skip it and tell you it did.
  • You can't recompute. Change your mind about what counts as a mention — does an aside count? a comparison to a competitor? — and the whole afternoon happens again. With the raw answers stored, you re-run the counter in a second.
  • One number is not a metric. A share of voice with nothing to compare it against is a fact. It can't go into a monthly report, a client deck or an alert, which is exactly where it needs to end up.

Do it with one API call

Each query is one POST. The response carries the whole answer as text, which is all the counting needs — no HTML to parse, no selectors to keep alive.

curl -X POST https://api.agentgeo.org/v1/fetches \
  -H "Authorization: Bearer ag_live_..." \
  -H "Content-Type: application/json" \
  -d '{"query": "best password manager for a small team", "surfaces": ["gemini"], "country": "US"}'

Now the measurement. Declare the competitive set explicitly, match on word boundaries rather than substrings, and keep a count of how many answers you actually counted — that number belongs in the report as much as the percentages do:

import re
import requests
from collections import Counter

KEY = "ag_live_your_key_here"

# Share of voice is always share *within a set you declare*. Declare it.
BRANDS = ["Acme", "Globex", "Initech"]

QUERIES = [
    "best password manager for a small team",
    "password manager with SSO for a 30-person company",
    "team password manager that works offline",
    "password manager for an agency handling client credentials",
]

PATTERNS = {b: re.compile(rf"\b{re.escape(b)}\b", re.I) for b in BRANDS}

mentions = Counter()
counted = grounded = skipped = 0

for query in QUERIES:
    resp = requests.post(
        "https://api.agentgeo.org/v1/fetches",
        json={"query": query, "surfaces": ["gemini"], "country": "US"},
        headers={"Authorization": f"Bearer {KEY}"},
        timeout=200,  # the API waits up to 180s for live surfaces
    )
    resp.raise_for_status()

    for answer in resp.json()["answers"]:
        if answer.get("status") == "failed":
            skipped += 1  # costs 0 credits, and must not count as a zero
            continue

        counted += 1
        if answer.get("sources"):
            grounded += 1  # Gemini browsed for this one. Most runs it won't.

        text = answer.get("answerText") or ""
        for brand, pattern in PATTERNS.items():
            if pattern.search(text):
                mentions[brand] += 1

total_mentions = sum(mentions.values()) or 1
denominator = counted or 1

print(f"query set:  {len(QUERIES)} queries, country=US")
print(f"counted:    {counted} answers ({skipped} skipped)")
print(f"grounded:   {grounded}/{counted} answers cited anything at all\n")
print(f"{'brand':<10}{'mention rate':>14}{'share of voice':>16}")
for brand in BRANDS:
    rate = mentions[brand] / denominator
    share = mentions[brand] / total_mentions
    print(f"{brand:<10}{rate:>14.0%}{share:>16.0%}")

Two columns, and they answer different questions. Mention rate is how often Gemini names you at all — it can rise for every brand at once if answers simply get longer. Share of voice is your slice of the tracked brands' mentions — it's zero-sum, so it only moves when the balance between you and your competitors moves. Report both and the ambiguity disappears. Four queries against one surface is four delivered records: four credits, with failed records costing nothing.

Resist the urge to add a citation-share column here. On Perplexity you can compute one, because nearly every answer carries a source list; on Gemini many delivered answers ground in nothing at all, so a citation-share denominator would be built out of whichever answers happened to browse that day — and it would swing week to week for reasons that have nothing to do with your market. Keep grounding as a plain count (grounded out of counted) and let mention share carry the metric. And publish the query set, the brand set and the date beside the number: a percentage whose denominators are private is a decoration, not a measurement.

What ships alongside the number matters as much as the number:

Record it with the numberWhy the number depends on itWhat a reader concludes without it
The exact query setAdding one query where you're absent lowers your rate; dropping one raises it.Nothing usable — the figure can't be reproduced, so it can't be compared.
The tracked brand setShare is share within a set. A fourth name lowers everyone at once.A rise that's really just a competitor you quietly stopped counting.
Run date and countryAnswers move week to week, and a US answer is a different answer from a German one.Two numbers compared that were never measuring the same thing.
Answers counted, answers skippedfailed records cost nothing and told you nothing — they must not score as zeros.A bad scrape reads as a drop in visibility.
The matching ruleWord-boundary matching and plain substring matching give different counts.Two people compute different percentages from identical records.

Let your agent do it

Share of voice is arithmetic over records, which makes it a natural fit for an agent: it can fetch the query set, do the counting, and write the month's summary in one pass. Connect the server once:

claude mcp add agentgeo -- npx -y agentgeo-mcp --key ag_live_...

One tool, fetch_raw_answers, over stdio — zero npm dependencies, Node.js 18+. surfaces takes one to six engine keys per call, so the same instruction extends past Gemini whenever you want it to. Then the ask:

Run these eight password manager queries through Gemini. Count how many answers name Acme, Globex and Initech, and give me mention rate and share of voice for each. Print the query set and the run date above the table, and tell me how many answers cited anything at all.

AgentGEO computes no share-of-voice number itself — it ranks nothing and scores nothing. The definitions stay in your code or your agent, which is the point: the moment a vendor picks the denominator for you, the metric stops being comparable to anything you'd calculate yourself. The Python path hits the same endpoint if you'd rather own the loop.

Common problems

Share of voice is easy to compute and easy to compute wrongly. The five that matter here:

  • Share of what, exactly? These percentages are shares within the brand set you chose. Add a fourth competitor and everyone's number drops. Write the tracked set and the query set into the report, or the figure can't be interpreted — least of all six months later.
  • Small query sets swing violently. With five queries, one changed answer moves share by twenty points. Aim for twenty to thirty queries per category before treating any movement as signal, and change the set deliberately rather than casually.
  • Failed records are not zeros. A record with status: "failed" cost nothing and told you nothing. Skip it, report the count you skipped, and if it carries a providerFields.snapshot_id, a follow-up call with that id and the same single surface redeems the finished answer without paying again.
  • Don't quietly switch to citation share. It's tempting once you see sources[] populated on a few answers, but on Gemini the grounded subset changes run to run, so that percentage measures the model's browsing mood as much as your market. Keep grounding as a count next to the table, never as the denominator inside it.
  • One market per table. country shapes the market; language is not forwarded for Gemini at all — the chatbot datasets behind this surface reject the field — so don't expect a language setting to produce a German answer here. Set country, and keep each market as its own series instead of averaging two into a number that describes neither.

Summary

Measuring share of voice once, by hand, is a genuinely useful afternoon and you should do it. Measuring it every month, over enough queries to mean something, with last month's numbers to compare against — that's a script or an agent: one call per query, one counter, and a stored history. On Gemini, mention share is the honest metric, grounding is a count rather than a denominator, and the query set belongs in the report next to the percentage.

Put a real number on your Gemini share of voice. Start free — no credit card and run your first query set today.

Start for free

Frequently asked questions

What is share of voice in Gemini?
It's the proportion of answers in a defined query set where your brand appears, relative to the competitors you track. On Gemini it's measured from the answer text rather than from citations, because the engine is a chatbot and only cites when it grounds an answer by browsing — so a great many delivered answers carry no sources at all.
How do you calculate share of voice for AI answers?
Fix a query set and a competitive set, run every query, and count per answer whether each brand is named. Divide each brand's count by the number of answers counted for mention rate, and by the total mentions across all tracked brands for share of voice. The result is only meaningful alongside the two sets you chose, so record them with the number.
Can I measure citation share in Gemini?
You can compute one, but it's a weak metric here. Gemini only cites when it grounds an answer, so the denominator would consist of whichever answers happened to browse on that run — and that fluctuates independently of your market. Track grounding as a plain count (how many answers cited anything) and let mention share carry the measurement.
How many queries do I need for a reliable share of voice number?
Twenty to thirty per category is a reasonable working minimum. Below about ten, one changed answer moves the percentage far enough to look like a trend. Consistency matters as much as size: the same queries, the same country, and the same tracked brand set every run.
Does Gemini give the same answer every time?
No. The same query run twice can produce different wording and a different set of brands, which is why a single reading is a sample rather than a measurement. Repeat the fetch on a schedule, keep every record, and judge movement across a query set instead of reacting to one answer.

Keep reading