How to measure share of voice in Microsoft Copilot
Share of voice in Microsoft Copilot is the share of your category's answers that belong to you rather than your competitors — and because Copilot is grounded in a live Bing search, you should measure it twice. Mention share is how often each brand is named in answerText. Citation share is how often each brand's domain appears in sources[]. Run a fixed query set, count both, print them side by side.
Copilot cites most of what it delivers, so citation share is a real second metric here rather than the rarity it is on a plain chatbot. The gap between the two numbers is usually the finding: you can be cited without being named, or named entirely out of a competitor's page. This guide covers the by-hand version, the one-call version in curl and Python, the agent version over MCP, and the ways a share-of-voice number quietly goes wrong.
To measure share of voice in Copilot, fix a query set and a competitive set, run every query, and count two things per answer: which brands the text names, and which brands' domains appear in the citation list. Divide each brand's count by the total across the set and you have mention share and citation share. Copilot cites most delivered answers, so both numbers are real here — track them separately and read the gap.
The manual way (and why it stops working)
Do this by hand once — it's worth the hour. Pick ten questions a buyer would actually type, like best help desk software for a small support team. Run each at copilot.microsoft.com and, for every brand you track, tick two boxes: named in the reply, cited in the sources beneath it. Twenty rows of ticks later you can divide into real percentages, and you'll understand how Copilot describes your category better than any dashboard would have told you.
Then try to run it again next month.
- Ten queries is the floor, and by hand it's also the ceiling. Share of voice measured on three answers is noise wearing a percentage sign. Thirty queries a month, transcribed by hand, is a job nobody keeps doing past the second cycle.
- Copilot's citation lists are long, and they hide. A delivered answer can cite eight Bing results at once; eyeballing which are your domain versus a review aggregator on example.com is exactly where hand-counting goes wrong.
- Ticking boxes drifts. A brand named twice in one answer, near-identical domains, a mention buried mid-paragraph — manual counting makes small consistent errors, and consistent errors look exactly like trends.
- No denominator discipline. If one answer fails to load and you quietly skip it, every percentage changes base without anyone noticing. A script can skip it and report that it did.
- No trend. A share-of-voice number with no previous number is a fact, not a metric — and re-deriving last month by hand means the whole afternoon happens again.
Do it with one API call
Each query is one POST. The response carries everything both metrics need — the answer prose and the structured Bing citation list — so the counting is a loop, not a scraping project. The managed-scraper engine runs the browser session for you, and the same body reaches any of the six engines by swapping the surface key.
curl -X POST https://api.agentgeo.org/v1/fetches \
-H "Authorization: Bearer ag_live_..." \
-H "Content-Type: application/json" \
-d '{"query": "best help desk software for a small support team", "surfaces": ["copilot"], "country": "US"}'Two fields do the work. answerText is the prose Copilot showed the user — that's where mentions live. sources[] is the list of Bing pages it built the answer from, each with a title, url and position — that's where citations live. A delivered Copilot record usually carries both.
{
"id": "run_8f3c1a92",
"query": "best help desk software for a small support team",
"surfaces": ["copilot"],
"status": "completed",
"recordsDelivered": 1,
"creditsCharged": 1,
"answers": [
{
"surfaceKey": "copilot",
"status": "delivered",
"answerText": "For a small support team, Acme is frequently recommended for its shared inbox and quick setup, while Globex is cited for deeper automation. Initech is a lower-cost option that covers the basics.",
"sources": [
{ "title": "Acme Help Desk — Pricing & Features", "url": "https://acme.com/help-desk", "position": 1 },
{ "title": "Best Help Desk Software in 2026", "url": "https://example.com/reviews/help-desk", "position": 2 },
{ "title": "Globex Support Suite", "url": "https://globex.com/support", "position": 3 }
],
"fetchedAt": "2026-07-20T09:14:22Z",
"latencyMs": 24140
}
]
}Now the measurement. Declare the competitive set explicitly, run the query set, and tally mentions and citations into separate counters:
import requests
from collections import Counter
from urllib.parse import urlparse
KEY = "ag_live_your_key_here"
# Share of voice is always share *within a set you declare*. Declare it.
BRANDS = {
"Acme": "acme.com",
"Globex": "globex.com",
"Initech": "initech.com",
}
QUERIES = [
"best help desk software for a small support team",
"help desk with a shared inbox and automation",
"affordable help desk for a 5-person team",
"help desk software with live chat",
]
def host(url):
h = urlparse(url).netloc.lower()
return h[4:] if h.startswith("www.") else h
mentions, citations = Counter(), Counter()
delivered = skipped = 0
for query in QUERIES:
resp = requests.post(
"https://api.agentgeo.org/v1/fetches",
json={"query": query, "surfaces": ["copilot"], "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
delivered += 1
text = (answer.get("answerText") or "").lower()
# Copilot is Bing-grounded, so a delivered record usually carries sources
hosts = {host(s["url"]) for s in answer.get("sources", [])}
for brand, domain in BRANDS.items():
if brand.lower() in text:
mentions[brand] += 1
if any(h == domain or h.endswith("." + domain) for h in hosts):
citations[brand] += 1
total_mentions = sum(mentions.values()) or 1
total_citations = sum(citations.values()) or 1
print(f"{delivered} answers counted, {skipped} skipped\n")
print(f"{'brand':<10}{'mention share':>15}{'citation share':>16}")
for brand in BRANDS:
m = mentions[brand] / total_mentions
c = citations[brand] / total_citations
print(f"{brand:<10}{m:>15.0%}{c:>16.0%}")That prints a two-column table: mention share and citation share for every brand you track, plus how many answers were actually counted. Four queries against one surface is four delivered records — four credits — and failed records cost nothing, which is exactly why the script skips them instead of scoring them as zero. Swap your ag_live_ key for an ag_test_ one and the same code returns clearly-labelled demo records at zero credits while you wire it up.
Once you have both numbers per brand, the gap between them is the part worth reading. A few patterns recur:
| Pattern | What it usually means | Where to work |
|---|---|---|
| Mentions high, citations low | The category names you, but Copilot pulls the passage from other domains | Own the source — publish the page Bing ranks for this query |
| Mentions low, citations high | Your pages feed the answer while another brand is the subject of it | Write for the passage — make the product the subject of the claim |
| Both low | You're outside Bing's retrieval set for these queries | Coverage — rank something that answers this exact question |
| Both high | You own this query set | Widen it — add the adjacent intents you aren't measuring yet |
| Delivered, but no sources[] | Copilot answered from model knowledge without browsing | Count the mention, flag the row — a citation-less answer is a weaker signal |
Copilot's citations are live Bing results — every URL in sources[] is a page you can open, read, and act on. That's what makes citation share a real second metric here rather than a rarity: unlike a chatbot that only cites when it happens to browse, a delivered Copilot record usually comes with the exact pages the answer was assembled from. When your mention share outruns your citation share, open the URLs Copilot did cite — those are the pages winning the passage, and they tell you precisely what to publish.
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 reaches past Copilot whenever you want it to. Then the ask:
Run these twenty help-desk queries through Copilot and give me mention share and citation share for Acme, Globex and Initech — then, for every answer where a competitor is cited and we aren't, list the exact Bing URLs Copilot used.
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. See what a GEO data layer is, or wire it up in Python or curl.
Common problems
Share of voice is easy to compute and easy to compute wrongly. The five that matter:
- 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 number 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 — and Copilot re-ranks its Bing results often, so single answers really do change. Aim for twenty to thirty queries per category before treating any movement as signal.
- A slow scrape fails at zero cost — and hands you a ticket to redeem. When Copilot's Bing round-trip runs long, the record comes back
status: "failed"at 0 credits with aproviderFields.snapshot_id. Call the API again with that id andcopilotalone to collect the finished answer instead of paying to scrape it a second time. Never fold the failed pass into the denominator as a zero. - Name collisions inflate mention share. Substring matching on a short brand name catches unrelated words and other companies. Use word boundaries, and spot-check the raw
answerTextbehind any brand whose number suddenly jumps. - One market at a time.
countrydefaults to"US"and is the only locale lever Copilot honours — it rejectslanguageandweb_search, which belong to other surfaces. A UK help-desk query set is a different market with a different competitive set: keep it as its own table instead of averaging two markets into a number that describes neither.
Summary
Measuring share of voice once, by hand, is a genuinely useful hour and you should do it. Measuring it every month, over enough queries to mean something, with both mention and citation counted and last month's numbers to compare against — that's a script or an agent: one call per query, two counters, and a stored history. Copilot cites most of what it answers, so the citation column is worth as much as the mention column. Keep the definitions in your own code and the number stays yours.
Put a real number on your Microsoft Copilot share of voice. Start free — no credit card and run your first query set today.
Start for freeFrequently asked questions
- What is share of voice in Microsoft Copilot?
- It's the proportion of answers in a defined query set where your brand appears, relative to the competitors you track — measured inside Microsoft Copilot, the consumer assistant at copilot.microsoft.com (not GitHub Copilot or the M365 enterprise version). Because Copilot is grounded in a live Bing search, it's worth splitting into mention share (your brand named in the reply) and citation share (your domain in the source list). The two often differ, and the difference is diagnostic.
- How do you calculate share of voice for Copilot answers?
- Fix a query set and a competitive set, then send each query to POST https://api.agentgeo.org/v1/fetches with "surfaces": ["copilot"]. For every delivered answer, count whether each brand is named in answerText and whether its domain appears in sources[], then divide each brand's count by the total across all tracked brands. Record the two sets alongside the number, because the percentages only mean something relative to the set you chose.
- What's the difference between mention share and citation share on Copilot?
- Mention share counts brand names in Copilot's generated reply; citation share counts domains in the Bing sources it used. High mentions with low citations means the category talks about you but your pages aren't the reference Copilot pulled — a content gap. High citations with low mentions means your pages feed the answer while another brand is the subject of it — a positioning gap.
- 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 — and Copilot re-ranks its Bing results often, so single answers genuinely do change between runs. Keep the query set, the country, and the tracked brand set identical every time.
- Can I measure share of voice across Copilot and other engines together?
- Yes. The surfaces array on POST https://api.agentgeo.org/v1/fetches accepts one to six engine keys, so a single call can send the same query to copilot, chatgpt, perplexity, gemini, google_ai_overview and google_ai_mode at once, each delivered record costing one credit. Keep the per-engine tables separate before combining them: Copilot cites most answers, while a plain chatbot only cites when it browses, so citation share isn't directly comparable across engines.
Keep reading