Get AI visibility data for a specific check
Changed onGet full AI visibility data for a specific historical check: the market map as it stood at this check under summary.marketMap, and each competitor's mention rate and AI Visibility Score across every AI model we query under summary.competitorRankings — in the order to render, nothing positional. The score counts only the top 5 positions in an answer, evenly spaced — first place the most, the last scoring position the least — and nothing below them. It is a reading of WHERE a brand lands when it is named, never of who is ahead: a standing claim — "you lead", "you trail", "the leader is X" — rests on how often each brand is named (presence on the market map, or mentionRate within one check) and never on this score, which can favour a brand named half as often. A score of 0 for a brand the answers did name means it was named only below the top 5, or too seldom inside them for the average to register. These rows name other companies, so reporting a 0 as 'never named' is a false claim about a third party published under CompetLab's name. Read mentionRate beside a 0 score: a non-zero rate means the brand was named, and a 0 rate means no counted answer named it. Rates here divide by the answers that came back, not the queries sent, and the queries-sent figure is not on summary — describe a rate as a share of the answers counted, never as a share of every query asked. Set includeAnswers=true to also get what the models actually said: every prompt sent, and every brand each model named in rank order with its stated reasoning, plus providerStatus and (where the check recorded its ask) answerCoverage. That block is large, and how large depends on the project. An entry is one brand a model named, at about 1,500 characters each — so the block grows with three things at once: how many prompts the project asks — 8 on every plan and in the trial — times five models, how many models answered, and how many companies each answer named. No figure quoted here can stand in for summary.totalEntries; read it and size the fetch from it. Google AI Overviews answers additionally carry the overview text and the pages Google cited, which totalEntries does not predict and which the brand filter keeps by design. Then prefer brand=<domain> (one competitor across every answer) or provider= (one model) over fetching everything; promptIndex= narrows to a single prompt. provider and promptIndex narrow the answers array; brand does not — it reduces the brands list inside each answer, so every answer still comes back and the ones that did not name that domain arrive with an empty brands, which is a finding rather than an absence. No filter changes any number under summary: those are stored, computed over the whole check, and never recomputed for a filtered view. Ranks are stable under filtering. Queries that produced no usable answer are listed separately in unansweredQueries rather than appearing as answers naming nobody, and queries the model was read for and had no answer to show — today, prompts Google showed no AI Overview for — in noAnswerShown, excluded from every count and not a failure; those are three different facts, and an empty brands under a brand filter is none of them. summary.customer.perPrompt breaks the customer's result down per prompt at no extra cost — use it before reaching for includeAnswers.
Request
- Base URL: https://api.competlab.com
- URL: https://api.competlab.com/v1/projects/{projectId}/ai-visibility/history/{checkId}
- Auth: API key in header CL-API-Key
Path parameters
Check ID
Project ID
Query parameters
Set true to include the models' raw answers — every prompt sent and every brand each model named, with its stated reasoning. Off by default because the block is large, and how large depends on the project. An entry is one brand a model named, at about 1,500 characters each — so the block grows with three things at once: how many prompts the project asks — 8 on every plan and in the trial — times five models, how many models answered, and how many companies each answer named. No figure quoted here can stand in for summary.totalEntries; read it and size the fetch from it. Google AI Overviews answers additionally carry the overview text and the pages Google cited, which totalEntries does not predict and which the brand= filter keeps by design. The prose it returns is the model's wording about the brands it named, not CompetLab's assessment.
Return only this model's answers. Requires includeAnswers=true. Does not change any number under summary, and does not narrow providerStatus.
Return only the entries for this domain, across every answer. Requires includeAnswers=true. Matches brands[].domain, case-insensitively; brand NAMES are the model's own wording and vary between answers, so they are never matched. EVERY answer is still returned — the ones that did not name this domain come back with an empty brands, because 'this model answered and did not name them' is a finding, not an absence of data. A query that produced no answer at all is in unansweredQueries instead and asserts nothing about anyone. Ranks are unaffected: an entry keeps the position it held in the full answer. This is the cheapest way to ask where a competitor wins and where they are invisible: it keeps at most one brand entry per answer instead of every brand the model named, and none at all on the answers that did not name it. Compare summary.totalEntries with the answer count to see the saving on this check. Google AI Overviews answers still carry their overview text and cited pages, which this filter keeps by design.
Return only the answers for this prompt, across every model. Requires includeAnswers=true. Zero-based, matching the per-prompt index used elsewhere in this dimension.
How much of the response to return. compact: summary.marketMap.brands is one page of rows — the core by default — with summary.marketMap.brandsPage saying where it sits; the customer's own row and every tracked competitor's are always included. Every other field is unchanged, and untrackedCoreBrands and customerStanding are still read from the whole map. full: every row of every list, as stored — large, and meant for export rather than for reading. Omitted, the API's default view applies: compact on /v1.
Rows of summary.marketMap.brands to skip, in the order the list is stored. Default 0. Pages the compact view: sent without view it selects the compact view, and beside view=full it is refused with paging_requires_compact_view.
Rows of summary.marketMap.brands to return, 1 to 200. Default the core size (summary.marketMap.coreSize), and never fewer than 10. Pages the compact view: sent without view it selects the compact view, and beside view=full it is refused with paging_requires_compact_view.
Whether to return summary. Omitted, /v1 returns it unless includeAnswers=true — a read for the answers rarely needs the summary again, and the summary is most of the response — and a param that pages a summary list returns it too. Set it explicitly to override; false beside a paging param is refused with paging_requires_summary.
Response
Example response
{
"item": {
"readingGuide": {
"summary.pages": "Pages the engines RETRIEVED while answering, never pages they cited."
},
"checkId": "507f1f77bcf86cd799439011",
"completedAt": "2026-03-15T10:00:00.000Z",
"summary": {
"customer": {
"domain": "mycompany.com",
"mentionRate": 66.7,
"mentionCount": 6,
"aiScore": 73,
"perProvider": {
"openai": {
"mentioned": true,
"mentionCount": 3,
"answersCounted": 3
},
"claude": {
"mentioned": true,
"mentionCount": 3,
"answersCounted": 3
},
"gemini": {
"mentioned": true,
"mentionCount": 3,
"answersCounted": 3
},
"perplexity": {
"mentioned": true,
"mentionCount": 3,
"answersCounted": 3
},
"google_ai_overviews": {
"mentioned": true,
"mentionCount": 3,
"answersCounted": 3
}
},
"perPrompt": [
{
"promptLabel": "best sales forecasting platforms for mid-market teams",
"mentionedBy": [
"openai",
"claude"
],
"score": 61
}
]
},
"topCompetitor": {
"domain": "competitor.com",
"name": "Competitor Inc",
"mentionRate": 88.9
},
"mentionRateGap": -22.2,
"totalCompetitorsFound": 8,
"totalQueries": 12,
"totalEntries": 45,
"competitorRankings": [
{
"domain": "competitor.com",
"name": "Competitor Inc",
"mentionCount": 7,
"mentionRate": 77.8,
"aiScore": 68
}
],
"promptMarket": {
"explanation": {
"code": "rivals_found_across_answers",
"text": "Your prompts are describing your market well. The AI answers we collected mention companies you already track, so the numbers here are measuring the right competition."
},
"answersNamingAnyRival": 34,
"answersMatchingCurrentPromptText": 60,
"checksAnalysed": 5,
"perPrompt": [
{
"promptId": "7f3c1a2e-9d44-4c8b-9f0e-2b6a5c9d7e10",
"promptTextInProject": "best sales forecasting platforms for mid-market teams",
"explanation": {
"code": "rivals_found_across_answers",
"text": "Your prompts are describing your market well. The AI answers we collected mention companies you already track, so the numbers here are measuring the right competition."
},
"answersNamingAnyRival": 1,
"answersMatchingCurrentPromptText": 20
}
]
},
"marketMap": {
"checksAnalysed": 5,
"answersReceived": 60,
"tailIsProvable": true,
"coreSize": 9,
"perEngine": {
"openai": {
"answersReceived": 15
},
"claude": {
"answersReceived": 15
},
"gemini": {
"answersReceived": 15
},
"perplexity": {
"answersReceived": 15
},
"google_ai_overviews": {
"answersReceived": 15
}
},
"profileEngines": [
"openai",
"claude",
"gemini",
"perplexity"
],
"brands": [
{
"answersNaming": 31,
"answersReceived": 60,
"presence": 52,
"presenceLow": 40,
"presenceHigh": 63,
"domain": "sienge.com.br",
"name": "Sienge",
"rankByPresence": 2,
"perEngine": {
"openai": {
"answersNaming": 31,
"answersReceived": 60,
"presence": 52,
"presenceLow": 40,
"presenceHigh": 63
},
"claude": {
"answersNaming": 31,
"answersReceived": 60,
"presence": 52,
"presenceLow": 40,
"presenceHigh": 63
},
"gemini": {
"answersNaming": 31,
"answersReceived": 60,
"presence": 52,
"presenceLow": 40,
"presenceHigh": 63
},
"perplexity": {
"answersNaming": 31,
"answersReceived": 60,
"presence": 52,
"presenceLow": 40,
"presenceHigh": 63
},
"google_ai_overviews": {
"answersNaming": 31,
"answersReceived": 60,
"presence": 52,
"presenceLow": 40,
"presenceHigh": 63
}
},
"endorsement": {
"value": 64,
"answersRead": 9,
"low": 51,
"high": 77
},
"pricePerception": {
"value": 64,
"answersRead": 9,
"low": 51,
"high": 77,
"tier": "mid_range",
"tierAnswers": 6
}
}
],
"brandsPage": {
"limit": 10,
"total": 96,
"hasMore": true
}
}
},
"answers": [
{
"provider": "openai",
"promptText": "best sales forecasting platforms for mid-market teams",
"answerText": "For mid-market sales teams, forecasting platforms such as Competitor Inc, Rival Software and Example Analytics combine CRM data with AI-driven projections.",
"askedIn": {
"locationName": "United States",
"languageName": "English"
},
"sources": [
{
"url": "https://www.g2.com/categories/sales-forecasting",
"domain": "g2.com",
"title": "Best Sales Forecasting Software"
}
],
"brands": [
{
"rank": 1,
"name": "Competitor Inc",
"domain": "competitor.com",
"description": "Cloud platform for pipeline forecasting aimed at mid-market sales teams.",
"rankingRationale": "Listed first because it integrates directly with the major CRMs.",
"sentiment": "recommended",
"mentionContext": "direct_recommendation",
"targetAudience": "Mid-size B2B sales teams",
"pricingSignal": "mid_range",
"positionConfidence": 0.9,
"features": [
"pipeline forecasting",
"CRM sync"
],
"differentiation": {
"axis": "technology",
"uniqueValue": "Only platform with native two-way CRM sync"
},
"messaging": {
"keywords": [
"automation",
"mid-market",
"self-serve"
],
"credibilitySignals": [
"SOC 2 Type II",
"used by 400+ teams"
],
"differentiationClaims": [
"fastest setup in category"
]
}
}
]
}
],
"unansweredQueries": [
{
"provider": "gemini",
"promptIndex": 2,
"promptText": "best sales forecasting platforms for mid-market teams",
"reason": "no_usable_answer"
}
],
"noAnswerShown": [
{
"provider": "google_ai_overviews",
"promptIndex": 1,
"promptText": "best sales forecasting platforms for mid-market teams",
"reason": "no_ai_overview_shown"
}
],
"providerStatus": {
"openai": {
"reported": true,
"completedAt": "2026-03-15T10:00:00.000Z",
"answersCounted": 3,
"brandsNamed": 21
},
"claude": {
"reported": true,
"completedAt": "2026-03-15T10:00:00.000Z",
"answersCounted": 3,
"brandsNamed": 21
},
"gemini": {
"reported": true,
"completedAt": "2026-03-15T10:00:00.000Z",
"answersCounted": 3,
"brandsNamed": 21
},
"perplexity": {
"reported": true,
"completedAt": "2026-03-15T10:00:00.000Z",
"answersCounted": 3,
"brandsNamed": 21
},
"google_ai_overviews": {
"reported": true,
"completedAt": "2026-03-15T10:00:00.000Z",
"answersCounted": 3,
"brandsNamed": 21
}
},
"answerCoverage": {
"queriesSent": 12,
"answersCounted": 8
}
}
}Changes
- breaking
the response property
/////////////became nullable for the status - breaking
the response property
/became optional for the status - warning
added the new
nothing_to_returnenum value to the/response property for the response status - warning
added the new
paging_requires_compact_viewenum value to the/response property for the response status - warning
added the new
paging_requires_summaryenum value to the/response property for the response status - info
added the new optional
queryrequest parameterincludeSummary - info
added the new optional
queryrequest parametermapLimit - info
added the new optional
queryrequest parametermapOffset - info
added the new optional
queryrequest parameterview - info
added the optional property
/to the response with the status - info
added the optional property
///////////to the response with the status
- breaking
- warning
added the new
bad_requestenum value to the/response property for the response status - warning
added the new
not_foundenum value to the/response property for the response status
- warning