Tutorial2026-07-176 min read

How to measure share of voice in Google AI Overviews

Share of voice in Google AI Overviews has a problem the chatbot surfaces don't have, and it lives entirely in the denominator. Google doesn't show an AI Overview for every search. Send twenty queries and you might get twelve overviews — the other eight simply had no AI block on the page for anyone, you or your competitors, to appear in. Divide by twenty and you have measured Google's product decisions, not your visibility. Divide by twelve and you have measured your visibility. The difference is routinely twenty points, always in the direction that makes you look worse than you are. So report two numbers, not one: AI Overview coverage — how often an overview appeared at all — and your share within the ones that did.

Tutorial

To measure share of voice in Google AI Overviews, fix a query set and a brand set, run every query with "surfaces": ["google_ai_overview"], and count brand mentions across the overviews you actually received. Records that come back failed mean Google showed no AI Overview for that search: skip them, count them separately, and keep them out of every denominator. What you report is a pair — coverage, and share within coverage — because either one alone can move for reasons that have nothing to do with the other.

The manual way (and why it stops working)

Do it on paper once; the afternoon is genuinely worth spending. Pick ten questions a buyer would type. Search each one in an incognito window and record three things per query: whether an AI Overview appeared at all, which of your tracked brands it named, and which domains it referenced. Ten rows later you can divide and get real percentages — and you'll have noticed something no dashboard would have told you, which is that a meaningful slice of your category doesn't get an AI Overview at all.

Then try to do it again next month:

  • The sample shrinks twice. Ten queries is already thin for a percentage. If only six produce an overview, your share of voice rests on six observations — and one changed answer moves it by seventeen points.
  • The missing overviews get quietly dropped. By hand, the natural move is to skip the queries with no overview and forget you did. Now the report says "share of voice: 50%" over an unstated base, and next month's 40% might be a Google change rather than yours.
  • Personalisation contaminates the count. Signed-in history and local results shape what you see, so two people measuring the same query set get different numbers and neither is measuring the market they sell into.
  • Every definition change costs another afternoon. Decide later that a name in a heading shouldn't count the same as one buried in a list, and the only way to apply that is to run the whole set again. Store the raw overviews and the recount is instant.
  • One reading isn't a measurement, and here it's ambiguous too. A percentage with nothing to compare it against is a fact rather than a metric. Worse, unless coverage was recorded beside it you can't say whether a fall means you lost ground inside the overviews or Google simply started showing fewer of them.

Do it with one API call

Each query is one POST. The response tells you both things you need: whether an overview existed, and if so what it said. An AI Overview is a block on a results page rather than a chat reply, so country and language map to the search's gl= and hl= parameters — set them explicitly and keep each market in its own table.

curl -X POST https://api.agentgeo.org/v1/fetches \
  -H "Authorization: Bearer ag_live_..." \
  -H "Content-Type: application/json" \
  -d '{"query": "best expense management software", "surfaces": ["google_ai_overview"], "country": "US", "language": "en"}'

Now the measurement. There are two counters that matter and one rule: a failed record increments the queries-sent count and nothing else.

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 expense management software",
    "expense management software for a 50-person company",
    "how to automate expense reports",
    "corporate card with built-in expense tracking",
    "what does expense management software cost",
]

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

sent = 0           # every query we asked for
with_overview = 0  # the ones Google actually answered inline - the denominator
named = Counter()

for query in QUERIES:
    resp = requests.post(
        "https://api.agentgeo.org/v1/fetches",
        json={
            "query": query,
            "surfaces": ["google_ai_overview"],
            "country": "US",
            "language": "en",
        },
        headers={"Authorization": f"Bearer {KEY}"},
        timeout=200,  # an AI Overview SERP round-trip alone runs 40-90s
    )
    resp.raise_for_status()

    for answer in resp.json()["answers"]:
        sent += 1

        if answer.get("status") == "failed":
            # No AI Overview on this SERP. Zero credits, and - crucially - not
            # a zero for anybody's share. It never enters the denominator.
            continue

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

coverage = with_overview / sent if sent else 0
total = sum(named.values()) or 1

print(f"AI Overview coverage: {with_overview}/{sent} = {coverage:.0%}\n")
print(f"{'brand':<10}{'in overviews':>14}{'presence':>10}{'share':>8}")
for brand in BRANDS:
    hits = named[brand]
    ratio = f"{hits}/{with_overview}"
    presence = hits / with_overview if with_overview else 0
    print(f"{brand:<10}{ratio:>14}{presence:>10.0%}{hits / total:>8.0%}")

Three numbers per brand, and they answer different questions. Presence is the share of the overviews you appeared in — it can be high for every brand at once, because an overview usually names several. Share is your slice of all mentions across the tracked set, which sums to 100% and is the figure people normally mean by share of voice. And sitting above both, coverage is the fraction of your query set Google answered inline at all. Five queries against one surface costs at most five credits, and any that came back with no overview cost nothing.

The two-denominator problem, with numbers

Say you ran twenty queries. Twelve produced an AI Overview, eight didn't, and Acme was named in six of the twelve. Here is the same data reported two ways:

Divide by every query sentDivide by the queries that produced an overview
Denominator20 — the whole query set12 — the searches Google answered inline
Acme's number6 / 20 = 30%6 / 12 = 50%
What's mixed in8 searches with no AI Overview for anyoneNothing — every query in the base had an overview to appear in
What moves itGoogle changing when it shows overviews at allYour presence actually changing
What it hidesThat coverage is 60%, a separate and useful factNothing, as long as you print coverage next to it

The naive number understates Acme by twenty points, and it does so systematically — the eight queries with no overview can only ever drag it down, never up. Worse, it's unstable for reasons you don't control: if Google starts showing overviews on four more of those queries next quarter and Acme isn't in any of them, the naive rate stays at 30% while the correct one falls to 37.5%. One number moved for a real reason and the other didn't move at all. That's why the pair is the deliverable.

This is why AgentGEO fails a record rather than delivering an empty answer. When Google shows no AI Overview, the record comes back status: "failed" with "Google returned no AI Overview for this query" and is charged nothing — an empty delivered record would have billed a credit and, far worse, would have arrived in your data looking exactly like an absence. The distinction between "no overview existed" and "an overview existed and skipped you" is preserved in the record on purpose, because it is the only thing standing between you and a denominator that quietly lies.

Let your agent do it

Share of voice is arithmetic over records, which makes it a natural job for an agent: fetch the query set, do the counting, 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, speaking stdio with no npm dependencies and a Node.js 18+ floor. Because surfaces accepts anywhere from one to six engine keys in a single call, the same instruction widens beyond AI Overviews the moment you want it to. Then state the metric, denominator included:

Run these twenty queries through google_ai_overview. Tell me how many produced an AI Overview at all, then give me mention share for Acme, Globex and Initech over only those. List the queries with no overview separately — they aren't zeros.

No share-of-voice figure is calculated on AgentGEO's side; nothing is ranked and nothing is scored. Every definition lives in your code or your agent — which matters more on this surface than on any other. Hand the arithmetic to a vendor and you have also handed over the decision about whether a missing AI Overview counts as a zero. That is the single most consequential choice in the whole metric, and it will get made somewhere you can't see it.

Common problems

Share of voice is easy to compute and easy to compute wrongly. On this surface, five things to hold onto:

  • A failed record is never a zero. It cost nothing and it told you nothing. Skip it, count it, and print the count beside the percentage — folding it into the base makes every brand in your set look worse for a reason that has nothing to do with the market.
  • Coverage moves on its own. How often Google answers a query inline is Google's decision and it changes over time. Track coverage as a first-class metric and check it before you interpret any movement in share — otherwise you'll write a content post-mortem for something that happened in Mountain View.
  • Budget for shrinkage when you size the query set. Your effective sample is coverage times query count, so at 60% coverage a thirty-query set gives you about eighteen observations. If twenty to thirty overviews is the number you want to reason from, ask for meaningfully more queries than that.
  • Say whose share it is. Every percentage here is relative to the brands you decided to track; admit a fourth name and all three existing numbers fall without a thing having changed in the world. Print the tracked set and the query set alongside the figure — six months on, a bare percentage with no roster attached is uninterpretable, including by the person who produced it.
  • One market per table. country sets the search gl= and language sets hl=, so US-English and German runs are different markets with different competitive sets and different coverage. Don't average them, and don't compare an AI Overview share against a ChatGPT share as though they were the same measurement — the surfaces produce records for different reasons.

Summary

Measuring share of voice in AI Overviews is the same arithmetic as anywhere else, with one addition that changes the answer: the queries where Google showed no overview are not queries you lost. Keep them out of the denominator, count them separately, and report the pair — coverage, and share within coverage. One call per query, two counters, and a stored history. Do it that way and the number stops understating you, and starts moving only when something real has moved.

Give your AI Overview share of voice an honest denominator. Start free — no credit card and measure coverage on your own query set.

Start for free

Frequently asked questions

What is share of voice in Google AI Overviews?
It's the proportion of AI Overviews in a defined query set that mention your brand, relative to the competitors you track. The catch specific to this surface is the base: Google doesn't produce an AI Overview for every search, so the denominator has to be the queries that actually returned one, not every query you sent.
How do you calculate share of voice for AI Overviews?
Fix a query set and a brand set, send each query with "surfaces": ["google_ai_overview"], and skip any record with status: "failed" — that means no overview appeared. Count brand mentions in answerText across the delivered overviews and divide by the total mentions across your tracked set. Report AI Overview coverage alongside it so the base is visible.
What happens if Google doesn't show an AI Overview for a query?
The record comes back with status: "failed" and the message "Google returned no AI Overview for this query", and it costs zero credits. It's a real result, not an error — there was no overview on the page for anyone to be in. Counting it as an absence is the most common way an AI Overview share-of-voice number ends up understating every brand in the set.
How many queries do I need for a reliable AI Overview share of voice?
More than you'd need on a chatbot surface, because some fraction of your queries won't produce an overview at all. If twenty to thirty observations is your working minimum, and coverage in your category runs around 60%, then a set of forty to fifty queries is a more honest starting point. Measure your own coverage first, then size the set from it.
Is AI Overview share of voice comparable to ChatGPT share of voice?
Not directly. The surfaces array accepts one to six engine keys and the record shape is identical, so the same script runs everywhere — but an AI Overview is a search result block and a chatbot reply is a generated conversation, and they fail for different reasons. Keep separate tables per surface and compare each one against its own history rather than against the others.

Keep reading