Prompt metrics
How each individual prompt performed over a window. Join prompt_id against
List prompts for the text — this endpoint returns numbers only, so
the two together are the full picture without either being heavy.
With compare_to_previous you also get a movers block: the prompts that gained and lost the
most. That is usually what you actually want when a headline visibility number has moved and you
need to know which questions caused it.
GET /v1/brands/{brand_id}/prompts/metricsAuthorization
| Header | Type | Required |
|---|---|---|
Authorization | Bearer asky_sk_… | required |
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
brand_id | uuid | required | From List brands |
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | integer | optional | Rows per page, 1 to 100. Defaults to 20. |
cursor | string | optional | Opaque cursor from the previous response. Treat it as a token, never construct one. |
start_date | YYYY-MM-DD | optional | Inclusive lower bound, YYYY-MM-DD in UTC. Narrows the population before metrics are computed. |
end_date | YYYY-MM-DD | optional | Inclusive upper bound, YYYY-MM-DD in UTC. Narrows the population before metrics are computed. |
compare_to_previous | boolean | optional | Also return the prior equal-length period and per-row deltas. |
movers_limit | integer | optional | Max gainers and losers returned, default 10. |
engine | string, repeatable | optional | Restrict to these AI search engines, by slug. From List engines. Narrows the population before metrics are computed. |
country | string, repeatable | optional | Restrict to these execution country codes. Narrows the population before metrics are computed. |
tag_id | uuid, repeatable | optional | Restrict to prompts carrying these tags. From List tags. Narrows the population before metrics are computed. |
tag_match_mode | string | optional | How to combine tag_id values. Defaults to ‘any’. One of: any, all. |
include_ads | boolean | optional | Also return the advertisers running against each prompt as an advertisers array. Caps limit at 25. The advertisers array is the largest field this endpoint returns, so the default 100-row page is refused rather than truncated. |
Request
cURL
curl --request GET \
--url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/prompts/metrics?compare_to_previous=true' \
--header 'Authorization: Bearer <api-key>'Response
200
{
"data": [
{
"prompt_id": "7c2f5a91-3b8e-4d06-9a44-1e7b30c9f852",
"visibility_share": 0.412,
"citation_rate": 0.238,
"avg_ranking": 2.4,
"previous_visibility_share": 0.361,
"visibility_share_delta": 0.051,
"previous_citation_rate": 0.201,
"citation_rate_delta": 0.037,
"previous_avg_ranking": 2.9,
"avg_ranking_delta": -0.5
}
],
"pagination": {
"limit": 20,
"has_more": true,
"next_cursor": "eyJ2IjoxLCJvIjoyMCwibCI6MjB9"
},
"meta": {
"period": {
"start_date": "2026-07-14",
"end_date": "2026-08-13"
},
"movers": {
"top_gainers": [
{
"prompt_id": "7c2f5a91-3b8e-4d06-9a44-1e7b30c9f852",
"visibility_share": 0.412,
"previous_visibility_share": 0.361,
"visibility_share_delta": 0.051
}
],
"top_losers": []
},
"newly_active": [],
"newly_inactive": []
},
"request_id": "req_9b3c07e5f1284ad6b0c9"
}Response fields
| Field | Type | Description |
|---|---|---|
data.period | object | required. { start_date, end_date } actually used. Defaults differ between endpoints, so read it before comparing |
data.metrics | object[] | required |
data.metrics[].prompt_id | uuid | required |
data.metrics[].visibility_share | number | required. Share of answers to this prompt naming you |
data.metrics[].citation_rate | number | required |
data.metrics[].avg_ranking | number | null | 1-based, lower is better. null when never named |
data.metrics[].chatgpt_response_count | integer | required. ChatGPT answers collected for this prompt in the window |
data.metrics[].ad_eligible_response_count | integer | required. Of those, the ones in a market where OpenAI actually serves ads. The denominator behind ad_rate |
data.metrics[].ads_response_count | integer | required. Answers that carried at least one sponsored card |
data.metrics[].ad_rate | number | null | 0 to 100. null, not 0, when ad_eligible_response_count is 0 — there is no denominator, which is different from “ads never appeared” |
data.metrics[].advertisers | object[] | Present only with include_ads. Up to 25 {domain, name, n, is_own_brand}, your own brand first and then most frequent, where n is how many answers that advertiser appeared in. is_own_brand is true when the ad points at one of your own domains, i.e. you are bidding against your own prompt. domain is null when the card carried no link and the group fell back to the advertiser name |
data.total | integer | required |
data.limit | integer | required |
data.offset | integer | required |
data.has_more | boolean | required |
data.movers | object | Only with compare. { top_gainers, top_losers } |
data.newly_active | uuid[] | Prompts with data this period but not the previous one |
data.newly_inactive | uuid[] | The reverse. Often the more urgent list |
request_id | string | required. Also returned as the x-request-id header. Quote it when contacting support |
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | A parameter is unknown or malformed. The message names it |
| 401 | invalid_token | The key is missing, malformed, or does not exist |
| 401 | token_expired | The key passed its expiry date |
| 401 | token_revoked | The key was revoked |
| 404 | not_found | The brand does not exist, or this key is not allowed to reach it. The two are deliberately indistinguishable |
| 429 | rate_limited | Over 300 requests per minute. See the Retry-After header |
Notes
A prompt with no completed execution in the window is absent, not zero. Do not read a missing row as a score of nought — it means the prompt did not run.
movers and the newly-active lists are computed over the full set, not the page you fetched.
Paging never changes which prompts are reported as movers.
Rates are fractions, not percentages. 0.412 is 41.2%.