Docs
How to read AIMentionTracker's numbers
Every rule below describes a way to be wrong that looks exactly like being right. That is why they are documentation and not a footnote.
Card required, nothing charged for 7 days
Why this page exists
A client that misreads this data does not crash. It renders. It produces a chart, an email, a slide in a client review — and the wrong version is indistinguishable from the right one by anyone reading the output, because the output is a number and numbers look equally confident whatever is behind them.
We sell measurement honesty. If our own API makes it easy to publish a confidently wrong figure in a customer's name, the product's claim is refuted by its own integration. So the rules travel with the data: GET /me returns the thresholds in force, every rate carries its denominator, and the three rules below are repeated on five pages rather than one.
Three rules you must not break
These are not style preferences. Breaking them produces a confidently wrong report in your customer's name.
- 1
A null rate means "not enough answers yet". It is NOT zero.
Rates come back as {present, responses, rate, min_sample}. When rate is null, the sample is below the floor. Say “3 of 4 answers, too few to quote a percentage”. Never render it as 0%, and never let it into an average. Reporting “0% visibility” for a brand that was named in 3 of 4 answers is the single most damaging thing you can do with this data.
- 2
Never average the engines.
There is no single visibility score and you must not compute one. ChatGPT, Perplexity and Google AI Overviews are different surfaces that disagree, so a mean describes nothing real. Report per engine. If the user insists on one number, give them the pooled counts (present and responses summed) and say plainly what you did.
- 3
An empty alerts list does NOT mean nothing changed.
A finding is raised only when both comparison windows carry enough answers AND the move is larger than its own margin of error. On a small plan that excludes most real movement. Say “no change large enough to distinguish from noise at this sample size”. GET /me shows the thresholds in force.
Rule one: null is not zero
Every rate in the API is an object, never a bare number, and the denominator is always there:
{
"engine": "perplexity",
"present": 3,
"responses": 4,
"rate": null,
"min_sample": 5
}Three of four Perplexity answers named the brand. The rate is null because four answers is too small a sample to quote a percentage from — 75% and 100% are one answer apart, and next week the same brand could read 50% with nothing having changed but which four answers landed.
A client has three honest options and one wrong one.
- Say the fraction.“Named in 3 of 4 Perplexity answers.” This is almost always the right choice.
- Say the sample is too small.“Not enough answers yet to quote a rate.”
- Show nothing, and say why.A dash with “below the 5-answer floor” beats a confident figure.
- Never render it as 0%. And never feed a null into an average, where it silently becomes a zero one layer down.
Do not hardcode 5. min_sample arrives on every rate and reporting_rules.min_sample arrives on GET /me, so a client that reads them follows a change in the floor without a release.
Rule two: never average the engines
ChatGPT, Claude, Gemini, Perplexity and Google's AI surfaces retrieve differently. One reads the live web on every query; another leans on what it already knows; another is a search result page with an answer on top. They disagree about your brand because they are genuinely looking at different things.
So a mean across them describes no surface a buyer will ever see. Worse, it hides the finding: a brand named in most ChatGPT answers and almost no Perplexity ones has a specific, fixable problem, and averaging turns that into an unremarkable middling number with nothing to act on.
Report per engine. If somebody insists on one figure, pool the counts rather than the rates — sum present, sum responses, divide once — and label it as pooled, because that at least is a real quantity with a real denominator.
const present = engines.reduce((n, e) => n + e.present, 0)
const responses = engines.reduce((n, e) => n + e.responses, 0)
// Say what this is: "named in 21 of 34 answers across 5 engines",
// NOT "62% AI visibility". And skip it entirely below min_sample.GET /me returns reporting_rules.engines_averaged: false. It is always false. It is in the response so a client can state the rule to a user rather than leave them wondering why there is no single score.
Rule three: an empty alerts list is not silence
A finding has to clear two bars before we raise it. Both comparison windows must carry enough answers, and the move must be larger than its own margin of error — a 95% confidence interval on the difference of two proportions. Whichever bar is higher wins.
On a small plan, that suppresses most real movement. This is on purpose. An alerting system that fires on noise trains people to ignore it, and then it fails at the one thing it exists for.
But it means an empty list carries a specific meaning, and it is not “nothing changed”. It is “no change large enough to distinguish from noise at this sample size”. A client that renders the first one is telling a customer something we did not measure.
"reporting_rules": {
"alerts": {
"min_delta_points": ..., // percentage points of change required
"min_sample_each_side": ...,// answers needed on BOTH sides
"also_suppressed_below_statistical_noise": true,
"empty_list_means": "..." // the honest phrasing, ready to surface
}
}empty_list_means is a string you can put in front of a user directly. It exists so the phrasing does not have to be reinvented — correctly — in every client that calls this API.
Our failures are not your absence
A collection can fail. An engine times out, a scrape is blocked, a vendor has an incident. When that happens the run is excluded entirely: it is not in the denominator, and it never appears in GET /answers.
The alternative — counting a failed run as an answer that did not name you — would turn our outage into your visibility drop. You would see a fall, investigate a problem that does not exist, and the number would recover when our vendor did. That is the one direction an error in this product must never point.
outcome: "empty" is the opposite case and it is counted. The engine answered and named nobody. That happened, we watched it happen, and it belongs in the denominator — it is evidence that a prompt produces answers where no brand gets recommended at all, which is a different and often more useful finding than losing to a competitor.
AI visibility metrics people misread
Four more, each one a place where the obvious reading is the wrong one.
avg_rank_when_namedis conditional. It is the mean position on the answers where you appeared, not across all answers, and it is null when you were never named. How often you appear and where you sit when you do are two questions; this field answers only the second.framingis not sentiment. It counts cue phrases and reports how many mentions it could classify at all —classifiedis the denominator, not the total mentions.framing_signalsreturns the phrases behind the judgement so it can be checked. Do not present it as a tone score, because it does not grade tone.citationscounts answers, not links. It is how many answers cited your own domain, so an answer citing you three times counts once. And a citation is not a mention: being read and being named are different, which is the whole point ofanswers_citing_you_without_naming_youon the sources endpoint.mentioned: falserows are data. They are not missing entries. They mean we looked for that brand in that answer and it was absent — which is what makes a competitor comparison meaningful rather than a list of the ones that happened to show up.
Check your client against this
Five minutes, and it catches almost everything. Run each of these against your own integration before it goes in front of a customer.
- Feed it a
rate: nullrow. Does any screen show 0%? - Feed it two engines, one null. Does an average appear anywhere, including in a chart axis or a sparkline?
- Feed it an empty
alertsarray. Does the interface say “no changes”? - Feed it a brand with
configured: false. Does it draw zeroes instead of saying setup is unfinished? - Change
min_samplein the fixture. Does your client follow it, or is 5 hardcoded somewhere?
curl -H "X-API-Key: $AMT_API_KEY" https://app.aimentiontracker.ai/api/v1/meQuestions about reading the data
The ones that decide whether a report is honest.
What does a null rate mean in AIMentionTracker?
Why does AIMentionTracker not give one AI visibility score?
Does a failed collection count as my brand being absent?
What does outcome "empty" mean on an answer?
Does an empty alerts list mean nothing changed?
Is framing a sentiment score?
What is avg_rank_when_named?
7-day trial
Numbers you can put your name on
Every rate arrives with its denominator, every engine is reported separately, and our outages are never your absence. Add your brand and see the answers behind it.
Card required, nothing charged for 7 days.
On every plan
- Every answer stored in full, with its citations.
- Every rate shown with the number of checks behind it.
- Cited-but-not-named reported as its own state.