ChatGPT entities
The products, brands and other named things in a ChatGPT answer, as structured entities.
The `entities` field lists the named things in an answer with a type and name, so mention tracking and share of voice read a field instead of pattern-matching the prose.
Returned in result
| Field |
|---|
entities |
Request
curl -X POST "https://api.answerline.dev/v1/monitor/chatgpt" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt":"What are the best running shoes for flat feet?","country":"US","include":{"markdown":true}}'
What ChatGPT’s entities are
An entity is a named thing ChatGPT puts in its answer, such as a brand or a product. The API returns every one the answer names, the products from its shopping search too, in result.entities: a list of {type, name} records, each once. You can count who is mentioned without parsing the prose.
Mention metrics are separate from citation metrics: a citation tells you which page ChatGPT relied on, a mention tells you what it put in front of the reader. The usual measures are mention rate (the fraction of category answers that name your brand), share of voice (your share of all brand mentions across the prompt set) and co-mention (who is named beside you, and who takes the slot when you are absent).
Sampling and sample sizes are covered in measuring brand mentions in ChatGPT. This page covers the field and a share-of-voice script.
Field reference
result.entities[]
| Field | Type | Meaning |
|---|---|---|
type |
string, required | ChatGPT’s category for the entity, for example product or software. |
name |
string, required | ChatGPT’s full name for the entity. It can differ from the words in text. |
entities is absent when the answer names none. Read it with a default; the script below matches brand names in text when it is absent.
Annotated excerpt
Values are illustrative; field names follow the POST /v1/monitor/chatgpt result schema.
{
"success": true,
"result": {
"text": "For a 10-person sales team, Example CRM and Sample Pipeline are the usual shortlist...",
// The brands and products the answer names.
"entities": [
{ "type": "software", "name": "Example CRM" },
{ "type": "software", "name": "Sample Pipeline" }
],
"sources": [
{ "position": 1, "url": "https://www.example-reviews.com/crm-small-teams", "label": "CRM for small teams", "footnote": false }
]
}
}
Cost and request options
entities needs no include flag; a ChatGPT request costs $0.0006 at the Starter tier. include.shopping, also free, adds inlineProducts, the products from ChatGPT’s shopping search with prices and merchants, and shoppingCards, empty on the answers served today. Those products are already named in entities.
ChatGPT decides on its own whether to search; disableWebSearch changes nothing today.
Example: share of voice and co-mention
The script samples each prompt several times, maps names to brands with an alias table, reads entities when an answer has it and matches the text otherwise, and prints mention rate, share of voice and the competitors most often named alongside your brand.
import os
import time
from collections import Counter
from datetime import date
from itertools import combinations
import requests
API = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
PROMPTS = ["best CRM for a 10-person sales team", "which CRM is easiest to set up for a startup"]
SAMPLES = 5
DAY = date.today().isoformat()
MY_BRAND = "Example CRM"
ALIASES = {
"Example CRM": ["example crm"],
"Sample Pipeline": ["sample pipeline"],
"Demo Sales Cloud": ["demo sales cloud", "demosales"],
}
def run_tasks(tasks):
resp = requests.post(f"{API}/v1/async/task/batch", headers=HEADERS, json=tasks, timeout=60)
resp.raise_for_status()
pending = {item["task"]["id"] for item in resp.json()["results"] if item["success"]}
results = []
while pending:
time.sleep(10)
for task_id in list(pending):
body = requests.get(f"{API}/v1/async/task/{task_id}", headers=HEADERS, timeout=30).json()
status = body["task"]["status"]
if status in ("COMPLETED", "FAILED"):
pending.discard(task_id)
if status == "COMPLETED":
results.append(body["response"]["result"])
return results
def brand_of(name):
lowered = name.lower()
return next((brand for brand, keys in ALIASES.items() if any(k in lowered for k in keys)), None)
def brands_named(result):
"""Brands per answer: from entities when present, else from the text."""
if result.get("entities"):
return [b for b in (brand_of(e["name"]) for e in result["entities"]) if b]
text = result.get("text", "").lower()
return [brand for brand, keys in ALIASES.items() if any(k in text for k in keys)]
tasks = [
{
"taskType": "CHATGPT",
"payload": {"prompt": prompt, "country": "US"},
"idempotencyKey": f"crm-entities-{p}-s{s}-{DAY}",
}
for p, prompt in enumerate(PROMPTS)
for s in range(SAMPLES)
]
answers = run_tasks(tasks)
mentions = Counter()
answers_naming = Counter()
pairs = Counter()
for result in answers:
named = brands_named(result)
mentions.update(named)
answers_naming.update(set(named))
pairs.update(combinations(sorted(set(named)), 2))
total = sum(mentions.values()) or 1
print(f"{len(answers)} answers, {sum(not r.get('entities') for r in answers)} without entities")
for brand, n in mentions.most_common():
print(f"{brand:20} mention rate {answers_naming[brand] / len(answers):5.0%} share of voice {n / total:5.0%}")
for (a, b), n in pairs.most_common():
if MY_BRAND in (a, b):
other = b if a == MY_BRAND else a
print(f"named with {other}: {n} answers")
The text path counts each brand at most once per answer, while entities can list a brand several times: once per product or name ChatGPT gives it. Compare share of voice only within one method, or count each brand once per answer everywhere.
Pitfalls
The same brand appears as the company, a product line or a plan name. Without an alias table, share of voice splits one brand into several rows. Read a sample of answer texts each period; a new name may be a competitor you were not tracking.
Treat type as an open set. Filter on the values you have seen, log new ones, and decide per metric whether a type counts as a brand mention.
A brand can be named as the one to avoid. A name match carries no sentiment, so for prompts that matter, read text or classify the sentence around each mention.
A brand can be named without its site being cited, and cited without being named. Track both; mentions vs citations explains why.
Other engines do not return entities. For cross-engine share of voice, run the same text matching on every engine, ChatGPT included, so the method is identical.
Brand lists change between runs of the same prompt; report rates with the sample size (answer volatility).
Related
- ChatGPT engine guide: sync and async calls, webhooks, geo targeting and billing.
- ChatGPT sources for the pages behind the mentions, and ChatGPT shopping for the products with prices and merchants.
- AI share of voice framework and competitor AI answer monitoring.
- AI visibility tracking and competitor analysis.
Questions
Do ChatGPT entities need an include flag?
No. entities comes with ChatGPT results at the base price: $0.0006 at the Starter tier.
What fields does a ChatGPT entity have?
Two, both required: type, the entity's category such as product or software, and name, ChatGPT's full name for it, which can differ from the words in the answer text.
What entity types can appear?
type is ChatGPT's category for the entity, a string such as product or software. Treat it as an open set: group by the values you receive and keep a mapping table rather than hard-coding a list.
Is entities available on Perplexity, Gemini or other engines?
No. entities exists only in the ChatGPT result. On other engines, match brand names in the answer text; for a cross-engine comparison, match the text on ChatGPT too so the method is identical.
How do I calculate share of voice from ChatGPT answers?
Map the names in result.entities to brands with an alias table, count mentions per brand across a fixed prompt set, and divide your brand's count by all brand mentions. Report the mention rate, the fraction of answers naming you, next to it.
More ChatGPT data
sources
Every page ChatGPT cited in its answer, in order, with the inline chips that group them.
shopping results
The products ChatGPT's shopping search shows, with their prices and offers, in inlineProducts; shoppingCards is usually empty today.
query fan-out
The web searches ChatGPT ran to build an answer, and the keywords behind its citations.