# How to measure brand visibility in AI answers

Javier Rodeiro · 2026-10-12

Share of voice in AI answers is the fraction of answers where a brand is present, compared with a fixed set of peers. In a 2,194-turn sample I collected for an insurance brokerage, 1,093 answers named at least one tracked company and none named the client. Counting only names would have hidden the 345 answers that cite sources instead.

## Why does a name count miss most of the picture?

The client's marketing team wanted to know how often ChatGPT-style assistants mention the brand when someone asks about insurance. The first version of the metric was the obvious one: count answers whose text contains the brand name.

That count is nearly always zero for a brokerage that compares prices. An assistant asked for the cheapest car insurance in Spain lists insurers, not comparison sites, and it often attaches source links to the answer. The brand can be present as a cited domain without appearing once in the text. A name-only metric reports zero for a company that is being used as a source, and zero for a company that is invisible. Those are different situations and the dashboard could not tell them apart.

## What did I count instead?

I count a brand as present in a turn (one question and its answer) if its name appears in the text or its domain appears among the cited URLs. Each turn counts once per actor, whichever signal fired. Then I divide the client's count by the total across the client and its peers, per topic cluster. The peer set is fixed in advance, so the number moves only when the answers move.

![Pipeline: prompts rotate across LLM providers, each answer turn is checked for names and cited domains, and the union feeds a per-cluster share of voice against peers.](../../../assets/articles/ai-visibility-share-of-voice-1.svg)

The diagram shows the one step that matters: name and citation are merged before anything is divided. This is the core of the dbt model that feeds the dashboard (client and peer names changed, shape unchanged):

```sql
round(
    safe_divide(
        cm.client_comparator_mentions,
        nullif(cm.total_comparator_mentions, 0)
    ), 4
) as geo_mention_rate
```

`dbt` is the SQL transformation tool the project uses to build its marts, the final tables the dashboards read. `comparator_mentions` is the per-cluster union of name hits and citation hits.

## Why return NULL instead of zero?

The `nullif` in that snippet is deliberate. If no tracked actor appears in a cluster, neither the client nor any peer, the share is undefined, not zero. A zero would say "the client lost this cluster". The truth is "the assistants talked about something else". The model returns NULL, the dashboard shows a gap, and the budget allocation model skips the cluster instead of penalising it. I wrote the decision down as an architecture decision record in the repo, because I knew I would forget the reason in a month.

## How are the prompts collected?

The data comes from prompt farming: I run a large set of realistic questions against several LLM providers on a schedule and store every answer. A small rotator, a class that picks the next provider for each prompt, spreads the questions so no single model's habits dominate the sample. Each conversation has two turns, so a follow-up question can shift the sources. Everything lands in DuckDB, an embedded analytical database, loaded with dlt, a Python library for extract-and-load jobs.

## What did the sample show?

The snapshot dated 22 June 2026 holds 1,097 conversations and 2,194 turns. Across them the extractor found 22,328 mentions of 15 tracked actors. Of the 2,194 turns, 1,093 name at least one tracked actor and 345 carry source links: 2,422 citations over 316 distinct domains. The client is named in none of the turns and its domain is cited in none.

![Bar chart of 2,194 answer turns: 1,093 name a tracked actor, 345 cite a source, 0 name the client, 0 cite the client's domain.](../../../assets/articles/ai-visibility-share-of-voice-2.svg)

The two zeros are the finding. The market is not invisible to the assistants: half the turns name somebody. The client is absent from both channels, so adding citations to the metric did not rescue it. It does mean future movement can come from either channel, and the report can say which.

## What is still open?

Three things. The sample is one snapshot, so I cannot say whether the zeros are stable or noisy. The extractor decides what counts as an actor mention with a language model, and I have not measured its error rate against hand labels. And the peer set is a choice: change it and the share changes, so the report states it every time.

If you run a comparison or aggregator site, the takeaway is small. Count names and citations together, divide by a fixed peer set, and keep "no data" separate from zero.

Source: https://javierrodeiro.com/blog/measuring-brand-visibility-in-ai-answers/
