Rankings
Two endpoints expose an app's App Store search position. GET /apps/:app/rankings returns a current snapshot of the latest scraped day across keyword and/or category surfaces; GET /apps/:app/rankings/history returns the rank series for one keyword or one category over a trailing window. Both are paginated lists (object: "list"); the row carries rank, change, and the keyword/category it belongs to.
Rankings are scraped App Store data, not the Shopify Partner feed — so these endpoints never return a 409. /rankings degrades gracefully: when nothing is tracked you get an empty data list, not an error. /rankings/history addresses one specific term, so an untracked keyword/category (or unknown app) returns a 404.
Current rankings
A snapshot of the app's current scraped ranks on the latest scraped day. Each row is a keyword rank or a category rank; type chooses which surface(s) to return. Keyword rows carry keyword + is_sponsored; category rows carry category. A rank of 0 means the app was not found in the scraped results for that term. The snapshot is not date-windowed, so the envelope has no coverage block.
Path parameter
- Name
app- Type
- string
- Description
The team app's ULID, e.g.
01JN4HKQX0000000000000000.
Query parameters
- Name
type- Type
- string
- Description
Which ranking surface to return:
all(default — both),keywords, orcategories.
- Name
limit- Type
- integer
- Description
Rows to return. Default
20, minimum1, maximum50.
Request
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/rankings \
-H "Authorization: Bearer rk_live_..." \
-d type=keywords \
-d limit=20
Response
{
"object": "list",
"url": "/api/v1/apps/01JN4HKQX0000000000000000/rankings",
"page": 1,
"per_page": 20,
"total_count": 2,
"has_more": false,
"metadata": { "summary": { "tracked_keywords": 2 } },
"data": [
{
"rank": 7,
"change": 2,
"date": "2026-05-29",
"category": null,
"keyword": { "slug": "product-reviews", "keyword": "product reviews" },
"app": { "slug": "acme-reviews", "name": "Acme Reviews" },
"is_sponsored": false
},
{
"rank": 0,
"change": 0,
"date": "2026-05-29",
"category": null,
"keyword": { "slug": "loyalty-rewards", "keyword": "loyalty rewards" },
"app": { "slug": "acme-reviews", "name": "Acme Reviews" },
"is_sponsored": null
}
]
}
Ranking history
The rank series for one keyword or one category over a trailing window (scraped). type selects the surface; the term is then identified by name (the keyword string, or the category name) or — for categories — a category slug. Each point carries the scraped rank, the change vs the previous observation, and — for keyword history only — the page and is_sponsored. Points carry their own dates inline, so the envelope has no coverage block.
Path parameter
- Name
app- Type
- string
- Description
The team app's ULID, e.g.
01JN4HKQX0000000000000000.
Query parameters
- Name
type- Type
- string
- Description
Required.
keywordorcategory— which surface the history is for.
- Name
name- Type
- string
- Description
The keyword string, or — for
type=category— the category name (fuzzy-matched). Required whentype=keyword. Fortype=categoryit is required unless acategoryslug is supplied.
- Name
category- Type
- string
- Description
A category slug (clean DX), e.g.
store-management. Used fortype=categoryas an alternative toname.
- Name
days- Type
- integer
- Description
Trailing window length in days. Default
30, minimum1, maximum90.
Request
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/rankings/history \
-H "Authorization: Bearer rk_live_..." \
-d type=keyword \
-d name="product reviews" \
-d days=30
Response
{
"object": "list",
"url": "/api/v1/apps/01JN4HKQX0000000000000000/rankings/history",
"page": 1,
"per_page": 30,
"total_count": 2,
"has_more": false,
"metadata": {
"type": "keyword",
"keyword": { "slug": "product-reviews", "keyword": "product reviews" }
},
"data": [
{ "date": "2026-05-28", "rank": 9, "page": 1, "change": null, "is_sponsored": false },
{ "date": "2026-05-29", "rank": 7, "page": 1, "change": 2, "is_sponsored": false }
]
}
Response shapes
Both endpoints return the standard object: "list" envelope. The currency and coverage keys exist on the envelope but are not used here — rankings are not money and not date-windowed, so they are omitted.
Ranking row
A row in the /rankings snapshot. The category and keyword cards are mutually exclusive per row; is_sponsored rides only on keyword rows.
- Name
rank- Type
- integer
- Description
Current scraped rank for this keyword/category.
0means the app was not found in the scraped results for this term.
- Name
change- Type
- integer
- Description
Rank movement vs the previous scrape (positive = improved toward #1);
0when there is no prior data point.
- Name
date- Type
- string | null
- Description
Date this rank was scraped (
YYYY-MM-DD), ornullwhen unknown.
- Name
category- Type
- object | null
- Description
{ slug, name }for the category this rank belongs to; present only for category rows (type=categories), otherwisenull.
- Name
keyword- Type
- object | null
- Description
{ slug, keyword }for the keyword this rank belongs to; present only for keyword rows (type=keywords|all), otherwisenull.
- Name
app- Type
- object | null
- Description
{ slug, name }card for the ranked app; present only when the app relation is resolved on the row, otherwisenull.
- Name
is_sponsored- Type
- boolean | null
- Description
Whether this keyword rank is a sponsored (ad) placement; present only on keyword rows, otherwise
null.
History point
A point in the /rankings/history series. page and is_sponsored are present only for keyword history (type=keyword); category history omits them.
- Name
date- Type
- string
- Description
Date of this rank observation (
YYYY-MM-DD).
- Name
rank- Type
- integer | null
- Description
Scraped rank on this date.
0means the app was not found for this term on that day;nullwhen the rank was not captured.
- Name
page- Type
- integer | null
- Description
Search-results page the app appeared on for this date; keyword history only, otherwise
null.
- Name
change- Type
- integer | null
- Description
Rank movement vs the previous observation (positive = improved toward #1);
nullwhen there is no prior data point.
- Name
is_sponsored- Type
- boolean | null
- Description
Whether this keyword rank was a sponsored (ad) placement; keyword history only, otherwise
null.
Errors
Beyond the universal 401 / 403 / 422 / 429 (see Errors), the rankings endpoints return:
404 resource_not_found— on/rankings/historyonly: the addressed app, keyword, or category does not exist or is not tracked./rankingsinstead returns an emptydatalist when nothing is tracked, so it never404s.422 validation_failed— a bad query parameter. On/rankings/history,typeis required, andnameis required whentype=keyword(orname/categoryfortype=category).
These surfaces are scraped, not Partner-fed, so they never return the 409 that the metric endpoints do.