Track brand mentions in Perplexity answers
To track brand mentions in Perplexity answers, run a fixed prompt set through Perplexity on a schedule, per market, and store each answer with its numbered sources. From each answer you read whether Perplexity named your brand, whether it cited your domain and how early, and how much of the answer rests on your pages. Perplexity cites every answer and maps each inline citation back to its source list, so citation position and coverage can be measured directly.
The fields are documented on the Perplexity engine page. If you are comparing ways to collect Perplexity answers rather than measuring them, see best Perplexity scrapers.
Definitions
- Mention rate: answers whose
textnames your brand, divided by answers. - Citation rate: answers that cite at least one URL on your domain, divided by answers.
- Citation position: the
positionof a source inresult.sources, the order in which the sources are listed. - Citation group: a set of sources cited together at one point in the answer, returned as entries of
result.citationPillssharing acitationPillId.
The endpoint and request fields
POST https://api.answerline.dev/v1/monitor/perplexity, with Authorization: Bearer <key> (authentication).
| Field | Required | Notes |
|---|---|---|
prompt |
yes | The prompt sent to Perplexity (up to 2,000 characters). |
country |
yes | Any country code; GET /v1/countries?model=perplexity lists supported values. |
state |
no | A US state code; implies country US. Perplexity answers for the whole US (states). |
include.markdown |
no | Adds result.markdown. |
include.html |
no | Adds result.html, a link to the answer’s public page on perplexity.ai. |
include.rawResponse |
no | Adds result.rawResponse, the answer as normalized stream events; include.rawWire returns null on Perplexity. |
Step 1: send a prompt
curl
curl -X POST https://api.answerline.dev/v1/monitor/perplexity \
-H "Authorization: Bearer $ANSWERLINE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Which project management tools do agencies use?",
"country": "GB",
"include": { "markdown": true }
}'
Python (requests)
import os
import requests
API = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['ANSWERLINE_API_KEY']}"}
resp = requests.post(
f"{API}/v1/monitor/perplexity",
headers=HEADERS,
json={"prompt": "Which project management tools do agencies use?", "country": "GB"},
timeout=660,
)
resp.raise_for_status()
result = resp.json()["result"]
for s in result.get("sources", []):
print(s["position"], s["url"])
TypeScript (@answerline/sdk)
import { Client } from "@answerline/sdk";
interface PerplexityResult {
text?: string;
markdown?: string;
sources?: { position: number; url: string; label?: string; description?: string }[];
citationPills?: { citationPillId: number; position: number; url: string; domain: string; label: string }[];
places?: { name: string; url?: string; rating?: number; address?: string[]; categories?: string[] }[];
}
const client = new Client({ apiKey: process.env.ANSWERLINE_API_KEY! });
const { result } = await client.monitor.perplexity<PerplexityResult>({
prompt: "Which project management tools do agencies use?",
country: "GB",
});
console.log((result.sources ?? []).map((s) => s.url));
The TypeScript SDK is on npm as @answerline/sdk; the Python examples call the HTTP endpoints with requests.
Step 2: the response fields
The body is { "success": true, "result": { ... } }.
| Field | Meaning |
|---|---|
text |
The answer as plain text. |
markdown |
The answer in Markdown, with include.markdown. |
links[] |
The links in the answer text. |
sources[] |
Every source, in order: position, url, label, description. |
citationPills[] |
One entry per citation-group-and-source pair: citationPillId (1-based), position (1-based index into sources), url, domain, label, optional description. Empty when there are none. |
places[] |
The places on the map Perplexity shows with the answer, hotels included: name, url, rating, address, lat, lng, categories, map_url, images. |
images[] |
The pictures shown with the answer: title, url, thumbnail, source, and dimensions. |
rawResponse[] |
The answer as normalized stream events, with include.rawResponse. result.rawWire (with include.rawWire) is null on Perplexity. |
related_queries, search_model_queries, videos, hotels and shopping_cards are in the contract and come back empty. Perplexity-specific names such as map_url keep snake_case, while shared fields such as citationPills use camelCase; use the names exactly as returned.
Citation groups
Perplexity cites sources in bracketed groups such as [1][2][3]. Such a group comes back as three citationPills entries with the same citationPillId, each carrying its own url, domain and label. label is always present but may be empty; use domain or url to identify the source.
from collections import defaultdict
def citation_groups(result: dict) -> dict[int, list[int]]:
groups = defaultdict(list)
for pill in result.get("citationPills", []):
groups[pill["citationPillId"]].append(pill["position"])
return dict(groups)
A source cited in many groups carries more of the answer than one cited once. Count groups per domain as well as positions.
Step 3: brand metrics from a run
import re
from urllib.parse import urlsplit
def on_domain(url: str, domain: str) -> bool:
host = (urlsplit(url).hostname or "").lower().removeprefix("www.")
return host == domain or host.endswith("." + domain)
def perplexity_metrics(result: dict, aliases: list[str], domain: str) -> dict:
brand = re.compile(r"\b(" + "|".join(re.escape(a) for a in aliases) + r")\b", re.IGNORECASE)
positions = [s["position"] for s in result.get("sources", []) if on_domain(s["url"], domain)]
groups = {p["citationPillId"] for p in result.get("citationPills", []) if on_domain(p["url"], domain)}
places = [p.get("name", "") for p in result.get("places", [])]
return {
"mentioned": bool(brand.search(result.get("text", ""))),
"cited": bool(positions),
"best_position": min(positions) if positions else None,
"groups_citing": len(groups),
"in_places": any(brand.search(n) for n in places),
}
Roll these up per prompt, market and run:
- Mention rate: share of answers naming the brand, cited or not (mentions vs citations).
- Citation rate: share of answers with
cited. - Average best position among cited answers. Lower is earlier in the list.
- Group coverage: average
groups_citing, a measure of how much of the answer relies on your pages. - Place presence, for local prompts: share of answers with places that list your business.
Word boundaries in the pattern stop “Acme” from matching “Acmeology”. For how many prompts a rate needs before you can report it, see how to measure brand mentions; the method is the same on every engine.
Step 4: run it at volume
A synchronous call waits for the full answer. For a prompt set, such as daily brand checks or a category watchlist, submit async tasks with a webhook and let results arrive as each completes:
[
{
"taskType": "PERPLEXITY",
"payload": { "prompt": "Which project management tools do agencies use?", "country": "US" },
"idempotencyKey": "pplx-pm-tools-agencies-US-2026-11-11",
"webhook": { "url": "https://you.example/hook" }
},
{
"taskType": "PERPLEXITY",
"payload": { "prompt": "Which project management tools do agencies use?", "country": "GB" },
"idempotencyKey": "pplx-pm-tools-agencies-GB-2026-11-11",
"webhook": { "url": "https://you.example/hook" }
}
]
POST that array to /v1/async/task/batch (1 to 500 tasks). With the SDK:
const markets = ["US", "GB"];
const tasks = markets.map((country) => ({
taskType: "PERPLEXITY" as const,
payload: { prompt: "Which project management tools do agencies use?", country },
idempotencyKey: `pplx-pm-tools-agencies-${country}-2026-11-11`,
webhook: { url: "https://you.example/hook" },
}));
const batch = await client.createBatch(tasks);
console.log(batch.summary); // { total, succeeded, failed }
Each item in results answers by index; failed items carry VALIDATION_ERROR, RESOURCE_ALREADY_EXISTS or INSUFFICIENT_CREDITS without affecting the rest. The webhook body is the GET /v1/async/task/{id} JSON, with the Perplexity result under response.result. Verify the signature (verify webhook signatures) and dedupe by task.id. For the batch-and-webhook plumbing, see the rank-tracking pipeline; for key design, idempotency keys explained.
What it costs
Per billing, at the Starter tier:
| Request | Price |
|---|---|
| Perplexity request | $0.0015 |
include.markdown, include.html or include.rawResponse |
+0 |
Worked example: 40 prompts in 3 markets, weekly, is 40 x 3 x $0.0015 = $0.18 per run as tasks, or $0.72 for four weekly runs. A new account’s 100 free requests work on any engine. See pricing and cost planning.
Sync or async
- Use synchronous calls interactively: checking a prompt while writing content, debugging your integration, a “run now” button. A call holds the connection until the answer is ready.
- Use async tasks for scheduled prompt sets. They queue with no count limit (about 100,000 typical tasks per account), go in batches of up to 500, accept
priority1 to 10 among your own tasks, and return results by webhook or polling.
Details in sync calls, async tasks or webhooks.
Pitfalls
- Counting a citation group once per source. For “how many places in the answer cite us”, count distinct
citationPillId, not entries. - Single-run conclusions. Citations change between runs of the same prompt; measure across runs (answer volatility).
- Reading empty fields as signal.
related_queriesandshopping_cardscome back empty on every answer, so they say nothing about your brand. - Retrying synchronous 5xx. A 500 or 502 is final and uncharged; resubmit as a task with an idempotency key (API errors and retries).
Perplexity in a cross-engine program
Mention and citation rates on Perplexity are most useful next to the same numbers on other engines, such as Gemini and ChatGPT. Where you are cited on one and missing on another, compare the sources of both to see who takes the slot. How AI engines choose citations and running your own citation study go deeper; see also the AI visibility tracking use case.
See every field on the Perplexity engine page and in the API reference.
Questions
How do I track brand mentions in Perplexity?
Run a fixed prompt set through Perplexity on a schedule, per market, and store each answer. For every answer record whether the text names your brand, whether sources cites your domain and at what position, and how many citation groups cite you. Report those rates across runs, not from a single answer.
Which fields does a Perplexity result carry?
text, markdown (with include.markdown), links, sources, citationPills, places and images. citationPills is an empty list when the answer has none. related_queries, search_model_queries, videos, hotels and shopping_cards are in the contract but come back empty.
How do I rebuild Perplexity's bracketed citation groups?
Group result.citationPills by citationPillId. A group such as [1][2][3] appears as three entries sharing one citationPillId, each with its own url, domain and label, and position pointing into result.sources.
Does Perplexity show my business on its map?
For local prompts, result.places lists the places on the map Perplexity shows with the answer, each with name, url, rating, address, coordinates, categories and a map link. Match your business name against it to track local presence.
Can I monitor Perplexity in a specific US state?
No. Perplexity accepts a US state but answers for the whole US, the same as without it. See /docs/coverage#states.