LLM Brand Visibility Tracker
Pricing
from $42.50 / 1,000 brand probes
LLM Brand Visibility Tracker
For each query that matters, check whether AI assistants recommend YOUR brand — and which competitors they cite instead. Grounded answers from Perplexity Sonar, GPT and Gemini with your own OpenRouter key. This is GEO: the SEO of the AI era.
LLM Brand Visibility Tracker — Is Your Brand Present in AI Answers?
Track whether a grounded AI answer names your brand, where the model reports it in the answer's
brand order, which alternatives it names, and which source domains appear in citation annotations.
Run the same buyer questions across Perplexity Sonar, GPT, Gemini, or another OpenRouter model and
receive one review-ready Dataset row per query × model probe.
Bring your own OpenRouter key. This Actor does not include model access. Provider usage is billed directly to your OpenRouter account; Apify separately charges the Actor start and each successfully delivered probe. Without a key, the Actor performs no model work and writes one free setup row. The Apify start event may still apply.

What this Actor sells
Most teams can manually ask one chatbot one question. The operational problem starts when the team has dozens of commercial questions, several markets, multiple models, repeated reporting dates and a need to explain why a row deserves attention. This Actor turns that matrix into structured data:
- whether the tracked brand was observed as a whole token sequence;
- the model-reported first-mention position when the answer supplies a brand list;
- alternative brands/products named in the same answer;
- structured citation URLs and domains when the provider returns them;
- separate brand-evidence and citation-evidence modes;
- freshness, coverage, confidence reasons and explicit data gaps;
- a conservative recommended review action;
- provider token usage and
providerCostUsdwhen OpenRouter reports it; - stable entity/event IDs for joining repeated exports;
- failure, retry and replay diagnostics for pipelines.
It is a probe and evidence-normalization product, not an SEO crawler, sentiment engine or ranking
oracle. Every row keeps safeToAutomate: false because one probabilistic answer is not enough to
publish content, contact a competitor, change a campaign or claim a durable market trend.
Who it is for
GEO and SEO agencies
Create the same bounded query portfolio for every client, export rows after each scheduled run and review brand gaps with citation evidence attached. The Actor makes the matrix repeatable; it does not manufacture a universal visibility score or pretend that all prompts have equal commercial importance.
In-house content and organic-search teams
Check whether category, comparison and problem-aware questions name your product. When an answer names alternatives but not your brand, inspect the cited domains and pages before deciding whether the gap is content, authority, product fit, geography or model variance.
Product marketing and competitive intelligence
Compare which alternatives appear for the same query across supported models and languages. Treat the extracted order as model-authored evidence from that response, not independently measured market rank.
Founders and small teams
Run a small hand-picked query set without buying another monthly dashboard. Use Apify schedules, webhooks and exports when the manual spreadsheet stops scaling. You still need an OpenRouter account and should cap spend in both OpenRouter and Apify.
Analysts and data pipelines
Join on entityId, retain eventId and observedAt, and compare repeated observations in your own
warehouse. The Actor itself is stateless: it does not label a change until your downstream system
compares two or more runs.
What you get in one row
| Question | Field(s) |
|---|---|
| Did the model answer successfully? | found, failureType, retryable, error |
| Was the brand observed? | mentioned, brandEvidenceMode |
| Where did the model report it? | position, positionBasis |
| Which alternatives were named? | competitorsNamed, legacy competitorsCited, brandNamesExtracted |
| Which sources grounded the answer? | citations, citedUrls, citedDomains, citationEvidenceMode, groundingObserved |
| How complete is the observation? | coverageScore, coverageBand |
| How strongly should it be trusted? | confidenceScore, confidenceBand, confidenceReasons |
| What is still unknown? | dataGaps |
| What should a human do next? | recommendedAction, actionPriority, actionReason, safeToAutomate |
| Can I reconcile provider spend? | promptTokens, completionTokens, providerCostUsd, modelAccessMode |
| Can I join repeated exports? | entityId, eventId, observedAt, freshness |
Quick start
- Create an OpenRouter key and apply the provider-side limit appropriate for your test.
- Click Try for free on Apify.
- Enter the exact brand name, one to twenty buyer questions, and one to three model IDs.
- Paste the key into the secret OpenRouter API key field.
- Keep concurrency at
1for a first run, review the Apify maximum charge, then start. - Open the Dataset and inspect
mentioned, evidence modes, cited domains, confidence reasons and data gaps together.
Minimal input:
{"brand": "Notion","queries": ["best note-taking app","best project management tool for a small startup"],"models": ["perplexity/sonar"],"lang": "en","openrouterApiKey": "YOUR_OPENROUTER_KEY","maxConcurrency": 1}
Do not commit the key to source control, paste it into a public Task definition or send it in a URL. The Apify Input field is marked secret. The Actor uses the value only in the OpenRouter Authorization header and never intentionally copies it to Dataset rows, OUTPUT or logs.
Input contract
| Field | Required | Limits | Meaning |
|---|---|---|---|
brand | yes | 1–200 characters | Exact brand, company or product token sequence to track |
queries | yes | 1–20 strings; 1,000 characters each | Questions real buyers might ask |
models | no | 1–3 IDs; 200 characters each | Default perplexity/sonar; every model multiplies row count |
lang | no | valid tag; max 35 characters | Requested answer language, default en |
openrouterApiKey | for probes | max 512 characters; secret | Your provider credential and provider billing boundary |
maxConcurrency | no | integer 1–3 | Parallel provider calls, default 1 |
Input validation is fail-closed. Values must already have the documented types: numbers are not coerced into strings, arrays are not silently truncated and blank elements are rejected. Exact duplicate queries or models are collapsed so the same literal probe is not billed twice. Case and wording are preserved because prompt wording can change a model answer.
Row count before you run
The requested matrix is:
number of rows = unique queries × unique models
Five queries across three models request fifteen rows. The maximum is twenty queries across three
models, or sixty rows. Error/setup/stop rows do not use the paid result-found event, but the
one-time Actor start price can still apply.
Model and retrieval policy
The listed grounded configurations are:
| Model ID | Retrieval request | Support label |
|---|---|---|
perplexity/sonar | Perplexity web search with high search context | listed_grounded_model |
openai/gpt-4o-mini | OpenRouter openrouter:web_search server tool | listed_grounded_model |
google/gemini-2.5-flash | OpenRouter openrouter:web_search server tool | listed_grounded_model |
The retired :online examples are not used for these listed models. You may submit another
OpenRouter model ID because this is a BYOK product, but the row is labeled custom_byok_model and
may have weak or absent structured citation evidence. A successful HTTP response alone never sets
groundingObserved: true.
Model availability, pricing, rate limits and retention are controlled by OpenRouter and the selected upstream provider. Check those terms before processing confidential prompts or committing to a schedule. This Actor does not proxy a hidden shared credential and does not promise a model will remain available forever.
How a response becomes evidence

1. Validate and reserve budget
The Actor validates exact input types and creates the bounded query × model matrix. Before a
provider call, it reserves room against the run's Apify maximum charge. That prevents spending the
buyer's OpenRouter balance for a new probe when the Actor already knows the Apify budget cannot
accept its result.
2. Request an answer and brand list
The tracked brand is not injected into the buyer question. The model receives the original query
and an instruction to answer concretely, then append one BRANDS_JSON list containing names it
actually used. This makes extraction more consistent, but the list is still model-authored output —
not independent telemetry.
3. Match the brand conservatively
The matcher normalizes letter/number tokens and requires the full tracked brand token sequence in a
candidate name. Go does not match Google; Notion does not match Notional Systems.
HubSpot may match HubSpot CRM, while tracking the longer HubSpot CRM does not silently reduce
the target to HubSpot.
When the structured marker is present:
mentionedis derived from the extracted ordered list;positionis the first matching index plus one;positionBasisismodel_reported_brand_order;- alternatives are preserved in
competitorsNamed; - legacy
competitorsCitedstays populated for backward compatibility.
When the marker is missing or malformed, the Actor falls back to a whole-token scan of answer text. It may still determine mention/no mention, but position and competitors remain empty rather than being invented.
4. Classify citation evidence
Citation evidence has three explicit modes:
structured_url_annotations— provider-supplied URL annotations were observed;inline_url_fallback— URLs appeared only inside answer text;none— no auditable URL was returned.
URLs are limited to HTTP(S), credentials and fragments are rejected/removed, common tracking and secret-bearing parameters are stripped, duplicates are collapsed and annotation titles are kept. The Actor does not fetch cited pages, prove their content, validate reachability or determine whether the page supports every claim in the answer.
5. Produce a review decision
Coverage and confidence answer different questions:
- coverage asks how much of the expected observation contract is present — answer, extracted brand order, citation evidence and usage metadata;
- confidence asks how strong the available evidence is for review routing.
A structured citation plus model-authored brand list currently reaches confidence 80/medium, not
high, because neither the order nor the recommendation is independent ranking telemetry. Missing
structured grounding caps confidence further. confidenceReasons explains the score; dataGaps
names what remains unresolved.
Recommended actions
| Action | When it appears | Human interpretation |
|---|---|---|
REVIEW_OWN_MENTION_AND_CITED_SOURCES | Brand mentioned and structured grounding observed | Inspect wording, context and cited pages before acting |
REVIEW_COMPETITOR_GAP | Alternatives named, tracked brand absent, structured grounding observed | Compare competitor/source footprint; do not assume causality |
VERIFY_GROUNDING_BEFORE_ACTION | Answer succeeded without strong citation evidence | Re-run or verify manually before strategy changes |
FIX_INPUT_KEY_MODEL_OR_PROVIDER | Probe/configuration failed | Follow failure and retry diagnostics first |
safeToAutomate is always false. The recommended action is a queue label, not permission to edit
a website, launch outreach, publish a comparison page or make a commercial claim automatically.
Real legacy output example
The following core fields come from an actual historical run on 2026-07-26. They demonstrate the
backward-compatible columns; the current version adds evidence and decision fields described above.
{"brand": "Zzqfake Nonexistent Xyz Corp","query": "best CRM software","model": "perplexity/sonar","lang": "en","found": true,"mentioned": false,"position": null,"competitorsCited": ["Salesforce","HubSpot CRM","Zoho CRM","Pipedrive","Microsoft Dynamics 365"],"promptTokens": 96,"completionTokens": 234,"checkedAt": "2026-07-26T13:27:30.617Z"}
The historical row did not retain structured citations or decision scores, so none are fabricated in this example. Current rows add those fields from the current response and code path.
Field dictionary
Identity and observation time
entityId— stable hash identity for brand + query + model + language;eventId— observation identity including time, mention state and extracted names;checkedAt/observedAt— when this model response was observed;firstSeenAt/lastSeenAt— equal for this stateless one-response observation;freshness.cacheReused— alwaysfalse; this Actor does not serve a cached model answer.
Brand evidence
mentioned— whether the full tracked-brand token sequence was observed;position— one-based index only when a model-reported list contains the brand;positionBasis— makes the origin of that position explicit;brandNamesExtracted— bounded ordered list produced from the response marker;competitorsNamed— extracted names that do not match the tracked brand;competitorsCited— legacy alias retained for existing consumers;brandEvidenceMode— structured model list or answer-text fallback.
The word “competitor” means an alternative name in this answer, not a verified corporate competitor, substitute product, market-share peer or legal entity.
Citation and grounding evidence
citations— normalized URL/title/evidence-type objects;citedUrls/citedDomains— convenient flattened arrays;citationEvidenceMode— structured annotation, inline fallback or none;groundingRequested— whether the transport requested retrieval;groundingObserved— true only for structured URL annotations;sourceEvidence— citation objects repeated in a decision-oriented form with reachability false.
Quality and decision fields
coverageScore/coverageBand— completeness of the observation contract;confidenceScore/confidenceBand— conservative evidence confidence;confidenceReasons— human-readable score drivers;dataGaps— nondeterminism, model-authored order, unfetched citation content, missing sentiment, weak grounding and/or absent independent position measurement;recommendedAction,actionPriority,actionReason— manual queue routing;safeToAutomate— always false.
Cost and failure fields
promptTokens,completionTokens— provider-reported token counts when available;providerCostUsd— provider-reported cost when available, useful for reconciling BYOK spend;modelAccessMode— alwaysbuyer_openrouter_keyfor model probes;modelSupport— listed grounded or custom BYOK model;failureType— configuration versus model-check failure;retryable— conservative retry hint, not a guarantee;setupRequired— true on the no-key setup row;error— redacted bounded diagnostic.
Pricing and two separate bills
This workflow has two billing boundaries.
Apify bill
On the FREE tier the configured price is $0.005 per Actor start + $0.05 per successfully delivered query × model row. Paid Apify tiers have lower event prices. The public Pricing tab is authoritative for your account.
Examples using FREE-tier Apify prices:
- 1 query × 1 model = 1 row:
$0.005 + $0.05 = $0.055; - 5 queries × 2 models = 10 rows:
$0.005 + $0.50 = $0.505; - 20 queries × 3 models = 60 rows:
$0.005 + $3.00 = $3.005.
The runtime accepts only the six configured tier pairs and checks the combined result/Dataset event
price before work. A successful linked Dataset write must return the exact Apify SDK 3.7.2 aggregate
receipt: one paid result-found event plus one zero-price default Dataset-item event. Ambiguous
delivery fails the run and sets replaySafe: false because automatic retry could double charge or
duplicate a row.
OpenRouter bill
Every model call uses your secret openrouterApiKey, so tokens/search/tool usage is billed directly
by OpenRouter and the selected provider. The Actor does not mark it up or include it in the Apify row
price. Actual provider cost varies by model, retrieval behavior, prompt and answer. Use provider-side
limits and inspect providerCostUsd rather than relying on a fixed estimate.
Free and partial rows
No-key setup rows, provider failures and budget-stop explanations do not use result-found while
the default Dataset-item event remains unpriced. The Actor start can still be charged. OUTPUT
records requested, delivered and error counts plus setup, budget, key and replay state.
If the buyer's Apify maximum charge cannot reserve another row, further provider work is not started. A final row that was fully delivered is not mislabeled partial merely because no future row would fit.
Failure and recovery contract
| Situation | Dataset / OUTPUT behavior | Retry guidance |
|---|---|---|
| Key omitted | One setup row; no model calls; OUTPUT setupRequired:true | Add key, then run |
Key invalid/expired (401) | One diagnostic probe; run fails honestly | Fix/reissue key first |
Key out of credits (402) | One diagnostic probe; run fails honestly | Fund/change key first |
| Provider/network/model failure | Free full-shape row with redacted error | Use retryable and provider status |
| Apify budget exhausted | Remaining work not started; partial OUTPUT when applicable | Raise cap only if intended |
| Pricing mismatch | Fail before model work | Operator must reconcile Pricing and source |
| Delivery receipt ambiguous | Run fails; replaySafe:false | Inspect Dataset and charge receipt before retry |
An invalid or unfunded buyer key is not reported as a healthy product success. The first job is a serial probe; only after it passes can the bounded concurrency pool start, avoiding several identical authentication failures.
Privacy and security boundaries
- Your OpenRouter key is secret input and is used only for the provider Authorization header.
- Provider error text is bounded and scrubbed for the exact key, bearer tokens and OpenRouter-style key patterns before storage or logging.
- Queries, brand names, answer snippets, extracted names and citation URLs are stored in the run's Apify Dataset. Do not submit confidential prompts unless that retention is acceptable.
- The full raw provider response is not retained; the answer excerpt is capped at 280 characters.
- Citation URLs are data, never executed. This Actor does not crawl them.
- No platform-owned provider fallback exists. BYOK means the buyer controls provider spend and provider-account policy.
- The Actor is bounded to 20 queries, 3 models, concurrency 3, 60-second provider calls and a 2 MB response body.
Review Apify, OpenRouter and upstream-provider terms for your jurisdiction and data class. This README is a product contract, not legal or privacy advice.
Integrations
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('zinin/llm-brand-visibility').call({brand: 'Notion',queries: ['best note-taking app'],models: ['perplexity/sonar'],lang: 'en',openrouterApiKey: process.env.OPENROUTER_API_KEY,maxConcurrency: 1,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.map(({ mentioned, competitorsNamed, citedDomains, recommendedAction }) => ({mentioned, competitorsNamed, citedDomains, recommendedAction,})));
Python
from apify_client import ApifyClientimport osclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("zinin/llm-brand-visibility").call(run_input={"brand": "Notion","queries": ["best note-taking app"],"models": ["perplexity/sonar"],"openrouterApiKey": os.environ["OPENROUTER_API_KEY"],"maxConcurrency": 1,})rows = client.dataset(run["defaultDatasetId"]).list_items().items
Webhooks, n8n, Make and warehouses
Use the Actor-run-succeeded webhook and read resource.defaultDatasetId. Route found:false rows
to operations, VERIFY_GROUNDING_BEFORE_ACTION to an evidence-review queue and grounded mention/gap
rows to analysts. Export JSON/CSV/Excel from Apify or load rows into BigQuery, Snowflake, Postgres or
Sheets. Keep IDs, observation time, evidence mode, confidence reasons and gaps together.
Never branch only on mentioned. A useful automation checks at least:
foundgroundingObservedbrandEvidenceModeconfidenceScoredataGapsrecommendedActionsafeToAutomate
Because safeToAutomate is false, the final business action remains a human decision.
Repeat-monitoring workflow
The Actor is stateless but schedule-friendly:
- Freeze a commercially meaningful query/model/language matrix.
- Run on a cadence that matches the decision — weekly or monthly is often more interpretable than noisy hourly probes.
- Store each Dataset externally using
entityId,eventIdandobservedAt. - Compare mention state, model-reported order, alternative names, cited domains and evidence modes.
- Require repeated observations before labeling a trend.
- Review changed citations/pages manually before content or PR work.
Prompt wording, model releases, provider routing, geography and search results can change answers. Keep the matrix stable when measuring change, and treat a model-ID change as a methodology change.
Important limitations
- A mention is not a recommendation, positive sentiment, endorsement or purchase intent.
- Absence in one answer is not proof that a model never knows or recommends the brand.
positionis the order in a model-authored list, not a universal rank or market share.- Extracted alternatives are names in that answer, not verified legal competitors.
- Structured citation annotations prove that URLs were returned, not that every answer claim is correct or supported by those pages.
- Cited pages are not fetched, archived, licensed or checked for availability.
- Answer generation is nondeterministic; repeated identical prompts may differ.
- Language and geography can change retrieval and brand naming.
- Custom models may ignore the brand-list instruction or omit citation annotations.
- The Actor does not calculate sentiment, share of voice, traffic, conversion, revenue or causal impact.
- The Actor does not persist a historical baseline or send alerts by itself.
Troubleshooting
I only received a setup row. Add your OpenRouter key. Model access is not included. The setup row is free, but the Apify start event may already have been charged.
The run failed with 401. The supplied key is invalid, expired or disabled. Replace it before retrying; repeated runs cannot repair provider authentication.
The run failed with 402. The OpenRouter account does not have sufficient credits for this call. Fund the account or use another authorized key.
The answer mentions my brand but mentioned:false. Inspect the exact tracked name,
brandNamesExtracted and brandEvidenceMode. Aliases, abbreviations and parent-company names are
not silently treated as equivalent. Run intentional variants as separate tracked brands.
Position is null. The response did not provide a usable ordered brand list or the target was not in it. The Actor will not infer a numeric position from arbitrary prose.
There are names but no citations. Brand extraction and citation grounding are independent.
Treat the row as weak evidence and follow VERIFY_GROUNDING_BEFORE_ACTION.
The same query changed. This can be normal model/retrieval nondeterminism. Compare timestamps, model IDs, evidence modes and cited domains; repeat before declaring a trend.
The run stopped for budget. Review OUTPUT, your Apify maximum charge and the matrix size. The
Actor reserves Apify budget before starting more provider work.
Delivery is marked unsafe to replay. Inspect both Dataset items and charged events. An automatic retry after an ambiguous linked receipt may duplicate a row or charge.
Acceptance checklist for buyers
Before operational use, confirm:
- the tracked brand name and aliases are intentionally defined;
- queries represent real buyer questions and remain stable across comparisons;
- the chosen model IDs currently support the required retrieval behavior;
- OpenRouter and Apify spend limits match the full matrix;
- structured versus fallback citation evidence is visible in your export;
- downstream logic keeps confidence reasons and data gaps;
- no automated action ignores
safeToAutomate:false; - retention of prompts, snippets, names and URLs is acceptable;
- repeated observations are required before a trend claim.
Related tools
| Actor | What it adds |
|---|---|
| AI Overview Citation Tracker | Map which source domains and exact URLs AI answers cite |
| AI Answer Change Alert | Compare a query's answer/citation state over time |
| AI Crawler Access Checker | Check whether major AI crawlers can access a website |
| Domain Health Checker | Add DNS, TLS and email-authentication website signals |
| Social Preview Checker | Verify how campaign URLs render on major sharing platforms |
FAQ
Does this work without an API key? No. It is intentionally BYOK. Without a key it returns one setup row and performs no model probes.
Why charge an Apify row if I pay OpenRouter too? OpenRouter charges model/retrieval usage. The Apify result event pays for validation, budget reservation, orchestration, extraction, citation normalization, decision enrichment, schemas, exports and recovery semantics.
Is position an AI-search ranking? No. It is the first matching position in a model-authored
brand list for one response, labeled with positionBasis.
Are competitorsNamed verified competitors? No. They are alternative names extracted from the
answer. Validate company/product relationships separately.
Can I use a custom model? Yes, with your OpenRouter key. It is labeled custom and may not provide structured grounding.
Can an agent call this Actor? Yes, through the Apify API, SDK or MCP integration. Keep the final business action behind human review.
Does it give SEO or investment advice? No. It reports one model observation and conservative review metadata.
Found a reproducible defect or unsupported model behavior? Open an issue on the Actor page with the run ID and non-secret input shape. Never include your provider key.
