Brand mentions API: measure LLM mentions per engine
If your brand is missing from an assistant’s answer, or a competitor’s page is the source it cites, nothing in your web analytics shows it. Measuring brand mentions through an API means running the questions your buyers ask, in the markets where they ask them, on a schedule, and recording two numbers per engine: mention rate and citation share. The setup below uses Python against the HTTP API; the AI visibility API page carries the same pipeline as a reference implementation.
Is there a brand mentions API?
There is no endpoint that returns mentions by themselves. You request the answer and match inside it. Each engine endpoint takes a prompt or query plus a market and returns that engine’s response as structured JSON: the assistants served today are ChatGPT, Gemini and Microsoft Copilot, alongside Google Search, Google AI Mode and Google News. Perplexity and Grok are paused for now and coming back soon. A mention is a match of your brand and its aliases in the answer text. A citation is one of the sources the answer listed: sources[] entries carry a position and a url, so a domain match gives you both citation rate and the position of your first citation.
“LLM mentions API” has the same answer. The mentions you can measure are the ones in answers to prompts you chose to run, not a pre-built corpus of mentions to query, which is why the prompt set below is the measurement: fixed and versioned, so a change in a rate is a change in the answers and not a change in the question.
Definitions
- Mention rate: the share of answers in a prompt set that name your brand.
- Citation share: the share of answers whose cited sources include your domain, reported together with the position of your first citation.
- Fan-out coverage: the share of the web search queries an assistant ran while answering (its query fan-out) for which your pages rank. ChatGPT’s
searchQueries[]comes back empty on the answers served today, so this cannot be measured on ChatGPT now. - Prompt set: a fixed, versioned list of natural-language questions, each with an id, intent label and target markets.
Mentions and citations move independently: an assistant can recommend you while citing a review site, or cite your docs without naming you in the text. Track both. Mentions vs citations explains the difference in depth.
Step 1: choose the prompts your buyers ask
Group prompts by intent, because each intent answers a different business question:
| Intent | Example | What it tells you |
|---|---|---|
| Category | “best project management tool for agencies” | are you on the shortlist |
| Comparison | “Asana vs Monday for a 20-person agency” | how you are positioned against a named rival |
| Problem | “how to track billable client hours” | whether you are the answer before the buyer knows the category |
| Brand | “is Acme good for agencies” | what the assistant says when asked about you directly |
Write prompts the way people type into an assistant: full questions with context, not keyword strings. Keep each prompt’s wording frozen once it is in the set; changing a word creates a new prompt and breaks the trend line. Designing a prompt set covers sizing and versioning.
Step 2: pick engines and markets
Every engine endpoint takes a required country (ISO 3166-1 alpha-2). ChatGPT, Gemini, AI Mode and Google Search answer from 213 countries, and Copilot takes any country. Gemini also takes a US state. List supported codes with GET /v1/countries?model=....
Start with the engine your buyers use most and the markets that carry revenue. Add engines once the first pipeline is stable. Engine-specific notes: ChatGPT and Gemini. For location effects, see state-level AI answers.
Step 3: submit the runs as async tasks
Submit the set as one batch. POST /v1/async/task/batch takes a JSON array of 1 to 500 tasks; each task has a taskType, a payload (the engine’s request body), an optional priority (1-10), an idempotencyKey and a webhook.
[
{
"taskType": "CHATGPT",
"payload": {
"prompt": "best project management tool for agencies",
"country": "US"
},
"idempotencyKey": "pm-agencies-chatgpt-us-2026-09-14"
},
{
"taskType": "GEMINI",
"payload": {
"prompt": "best project management tool for agencies",
"country": "US"
},
"idempotencyKey": "pm-agencies-gemini-us-2026-09-14"
}
]
Build the idempotency key from what the run means (prompt, engine, market, day), never from a random value per attempt. A retried submission then returns the task already created instead of charging twice. Idempotency keys explained covers the edge cases.
The batch response has summary { total, succeeded, failed } and results[], one per input index, each with either task and credits (the charge in dollars) or an error whose code is VALIDATION_ERROR, RESOURCE_ALREADY_EXISTS or INSUFFICIENT_CREDITS. One invalid task does not block the others.
A submitter in Python:
import datetime as dt
import os
import requests
API = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['ANSWERLINE_API_KEY']}"}
PROMPTS = [
("pm-agencies", "best project management tool for agencies"),
("pm-vs", "Asana vs Monday for a 20-person agency"),
("client-hours", "how to track billable client hours"),
]
MARKETS = ["US", "GB"]
today = dt.date.today().isoformat()
tasks = [
{
"taskType": "CHATGPT",
"payload": {"prompt": prompt, "country": country},
"idempotencyKey": f"{pid}-chatgpt-{country.lower()}-{today}",
# "webhook": {"url": "https://example.com/hooks/answers"},
}
for pid, prompt in PROMPTS
for country in MARKETS
]
r = requests.post(f"{API}/v1/async/task/batch", json=tasks, headers=HEADERS, timeout=60)
r.raise_for_status()
body = r.json()
print(body["summary"])
task_ids = []
for item in body["results"]:
if item["success"]:
task_ids.append(item["task"]["id"])
else:
print("task", item["index"], item["error"]["code"], item["error"]["message"])
A RESOURCE_ALREADY_EXISTS result on a re-run the same day means the key already has a task; the key prevented a duplicate, so do not alert on it.
Step 4: collect results
Two ways to get finished tasks:
- Webhook (recommended at scale). Add
"webhook": {"url": "https://..."}to each task. When the task finishes, the API posts the same JSON thatGET /v1/async/task/{taskId}returns. Verify theWebhook-Signatureheader and deduplicate bytask.id; see webhooks and verifying signatures. - Polling (fine for small sets). Call
GET /v1/async/task/{taskId}untiltask.statusisCOMPLETEDorFAILED. Only those two are final; a task can move fromPROCESSINGback toQUEUED.
import time
def wait_all(ids, interval=10, timeout=1800):
pending, done = set(ids), {}
deadline = time.monotonic() + timeout
while pending and time.monotonic() < deadline:
for tid in list(pending):
t = requests.get(f"{API}/v1/async/task/{tid}", headers=HEADERS, timeout=30)
t.raise_for_status()
data = t.json()
if data["task"]["status"] in ("COMPLETED", "FAILED"):
done[tid] = data
pending.discard(tid)
if pending:
time.sleep(interval)
return done
finished = wait_all(task_ids)
Store the whole task JSON, not only the parsed metrics. When you change how you detect mentions, you can recompute history without paying for new runs.
Step 5: compute the metrics
For ChatGPT the relevant fields under response.result are text, sources[] (position, url, label, description) and citationPills[] (inline citations with domain). ChatGPT’s entities[] (type, name) lists the brands and products the answer names; searchQueries[] (with include.searchQueries) exists but comes back empty on the answers served today. Other engines return text and sources[].
from urllib.parse import urlparse
BRAND_NAMES = {"acme", "acme pm"}
DOMAIN = "acme.com"
def host(url):
h = urlparse(url).hostname or ""
return h[4:] if h.startswith("www.") else h
def measure(task_json):
result = (task_json.get("response") or {}).get("result") or {}
text = (result.get("text") or "").lower()
mentioned = any(n in text for n in BRAND_NAMES)
ours = [s for s in result.get("sources", []) if host(s["url"]) == DOMAIN or host(s["url"]).endswith("." + DOMAIN)]
return {
"mentioned": mentioned,
"cited": bool(ours),
"first_position": min((s["position"] for s in ours), default=None),
}
rows = [measure(t) for t in finished.values() if t["task"]["status"] == "COMPLETED"]
n = len(rows)
print("mention rate", sum(r["mentioned"] for r in rows) / n)
print("citation share", sum(r["cited"] for r in rows) / n)
Fan-out coverage is not in the script: it needs the searches the assistant ran, and ChatGPT’s searchQueries[] comes back empty on the answers served today. Query fan-out covers the idea.
Worked example
The numbers are invented to show the arithmetic. Suppose 40 prompts in the US return 40 completed answers. Your brand is named in 14 of them, your domain is cited in 9, and your first citation position averages 3. Mention rate is 14 / 40 = 35%; citation share is 9 / 40 = 22.5%. The 26 answers without a mention are the list to read first: which brands are named instead, and which sources are cited for them. That comparison is the basis of competitor monitoring and AI share of voice.
Segment every metric by intent. A high brand-prompt mention rate with a low category-prompt rate means assistants know you but do not recommend you.
Step 6: re-run on a schedule
Answers change between runs even when nothing else changed, so a single run is an anecdote. Decide cadence by how fast you need to react:
| Situation | Cadence |
|---|---|
| Steady-state reporting | weekly |
| Launch, campaign, pricing change | daily for the period |
| Reputation issue | daily, with alerts on transitions |
| Distinguishing noise from change | repeat the same prompt several times in one run |
How often AI answers change and sampling vs census cover the statistics.
Cost
Per-task prices at the Starter tier: ChatGPT $0.00062, Gemini $0.0005, Google AI Mode $0.00156, Google Search $0.00078 (+$0.00078 with the AI Overview), Google News $0.0002; Copilot is paused for now. ChatGPT’s include flags are free. Synchronous calls add $0.0007 more (plus $0.00078 per results page on Google Search and Google News); async tasks do not.
| Run | Tasks | Cost per task | Cost per run |
|---|---|---|---|
| 100 prompts, US, ChatGPT | 100 | $0.00062 | $0.062 |
| same, Gemini | 100 | $0.0005 | $0.05 |
| same, Google AI Mode | 100 | $0.00156 | $0.156 |
A task reserves its maximum cost when created (credits.creditsToCharge) and is charged the actual cost when it completes (credits.creditsCharged); failed tasks are not charged. New accounts get 100 free requests on any live engine, the assistants included; see pricing and cost planning.
Pitfalls
- Keyword-string prompts. “pm tool agencies” is not what buyers type into an assistant and produces different answers than a natural question.
- Substring brand matching. Short or common brand names match unrelated words. Prefer word-boundary matching, and review a sample by hand.
- Counting failed tasks as “not mentioned”. Exclude
FAILEDtasks from denominators and report them separately. - Random idempotency keys. They defeat retry safety; a network retry can charge twice.
- One market for a global brand. The answer in GB is not the answer in the US; run every market that carries revenue.
- Comparing across prompt-set versions. Changing prompts resets the baseline. Version the set and annotate the chart.
Next steps
Once the two metrics are stable, report them per engine and intent (report template), connect them to outcomes (AI referral traffic) and act on the gaps (how AI engines choose citations). The use-case overview is at AI visibility tracking; no-code versions of this pipeline are in the n8n and Zapier guides.
Start with the quickstart.
Questions
Is there a brand mentions API or an LLM mentions API?
There is no endpoint that returns mentions by themselves. You request an engine's answer for a prompt and a market and get it back as structured JSON, then match your brand and its aliases in the answer text; citations are the sources the answer listed, each with a position and a URL.
What should I measure when tracking AI answers about my brand?
Two numbers per prompt set, engine and market: mention rate (share of answers that name your brand) and citation share (share of answers citing your domain, with position). Fan-out coverage (whether you rank for the web searches the assistant ran) cannot be computed for ChatGPT today, because its searchQueries list comes back empty.
How many prompts do I need?
Enough to cover the category, comparison and problem questions your buyers ask, typically tens to a few hundred. Start small, check that the metrics are stable across repeated runs, then grow the set.
Why run the same prompt in several countries?
Assistants localize answers, so a brand visible in one market can be absent in another. Each request takes a required country code. ChatGPT and Gemini answer from 213 countries, and Gemini also takes a US state.
How much does a tracking run cost?
Prompts times markets times the per-task price. A ChatGPT async task costs $0.00062 at the Starter tier; 100 prompts in the US is $0.062 per run.
How often should I re-run the prompt set?
Weekly is a reasonable default for trend lines. Run daily during launches, campaigns or a reputation issue, and repeat runs of the same prompt when you need to separate real change from answer-to-answer variation.