Scorecard
Returns a single object: "scorecard" for an app — a weighted overall health score, four sub-scores each paired with their breakdown, and prioritised improvement opportunities.
The endpoint 404s with resource_not_found when the addressed app does not exist or is not tracked by your team. When the team follows no competitors yet, the score is computed against a provisional comparison set (embedding-similar → top-category apps) rather than erroring, and the scorecard flags this with is_provisional: true. It reads the scraped catalog, so it is never gated on the Shopify Partner integration.
App health scorecard
The app's composite competitive scorecard — the same computation the dashboard renders. Returns a weighted overall_score (0–100) plus four sub-scores: listing_quality, keyword_performance, reviews_reputation, and visibility. Each sub-score is a { score, breakdown } pair where breakdown carries the per-factor inputs (max-score weights, ratios, the outranked/unranked keyword lists, head-to-head review distribution, ranked-category positions, and so on). improvement_opportunities is a priority-ordered action list and competitor_comparison is the head-to-head against each followed competitor.
The scorecard is cached — the stored row is returned unless it is stale. Pass refresh=true to force a recompute.
is_provisional is true when the score was computed against an embedding-similar → top-category fallback set because the team follows no competitors yet; computed_at is the last-computed ISO-8601 timestamp, or null if never computed.
Path parameter
- Name
app- Type
- string
- Description
The team app's ULID, e.g.
01JN4HKQX0000000000000000.
Query parameters
- Name
refresh- Type
- boolean
- Description
Force a fresh recompute instead of returning the cached (non-stale) scorecard. Accepts the natural query forms (
true/false/1/0/yes/no). Defaultfalse.
Request
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/scorecard \
-H "Authorization: Bearer rk_live_..."
Response
{
"object": "scorecard",
"overall_score": 72,
"listing_quality": {
"score": 68,
"breakdown": {
"characterUtilization": {
"score": 28,
"maxScore": 40,
"averageUtilization": 71.2,
"fields": {
"name": { "length": 28, "limit": 30, "utilization": 93.3 },
"subtitle": { "length": 60, "limit": 62, "utilization": 96.8 },
"introduction": { "length": 90, "limit": 100, "utilization": 90 },
"details": { "length": 320, "limit": 500, "utilization": 64 }
},
"featureCount": 3
},
"antiPatterns": {
"score": 25,
"maxScore": 30,
"count": 1,
"details": { "details": ["Avoid superlatives like \"best\"."] }
},
"keywordPresence": {
"score": 15,
"maxScore": 30,
"found": ["inventory sync"],
"missing": ["stock alerts"],
"source": "traffic"
}
}
},
"keyword_performance": {
"score": 74,
"breakdown": {
"keywordBreadth": { "score": 16, "maxScore": 20, "count": 41 },
"outrankingRatio": { "score": 22, "maxScore": 35, "ratio": 0.63, "trackedWeightApplied": true },
"topTenDensity": { "score": 21, "maxScore": 30, "count": 12, "total": 41, "ratio": 0.293, "trackedWeightApplied": true },
"keywordCoverage": { "score": 11, "maxScore": 15, "ratio": 0.74 },
"outrankedKeywords": [
{
"keyword_id": 5012,
"keyword": "stock alerts",
"yourRank": 14,
"bestCompetitorRank": 3,
"bestCompetitorAppName": "Stocky",
"tracked": true,
"installAttributed": false,
"tier": 2,
"gap": 11
}
],
"unrankedTrackedKeywords": [
{ "keyword_id": 5099, "keyword": "low stock", "installAttributed": true }
],
"outrankedTrackedCount": 4,
"unrankedTrackedCount": 2
}
},
"reviews_reputation": {
"score": 81,
"breakdown": {
"rating": { "score": 30, "maxScore": 35, "value": 4.7, "competitorAvg": 4.5 },
"volume": { "score": 17, "maxScore": 20, "count": 312, "competitorAvg": 540 },
"sentiment": {
"score": 22,
"maxScore": 25,
"positiveRatio": 0.91,
"distribution": { "positive": 284, "neutral": 12, "negative": 16 }
},
"recency": { "score": 12, "maxScore": 20 },
"competitorAdjustment": 1
}
},
"visibility": {
"score": 65,
"breakdown": {
"categoriesRankedIn": {
"score": 20,
"maxScore": 25,
"count": 4,
"categories": [
{ "name": "Inventory management", "rank": 7 },
{ "name": "Stock control", "rank": 18 }
]
},
"bestPosition": { "score": 21, "maxScore": 30, "position": 7 },
"avgPosition": { "score": 13, "maxScore": 25, "position": 12.5 },
"categoryGaps": { "score": 11, "maxScore": 20, "gaps": 3 }
}
},
"is_provisional": false,
"computed_at": "2026-05-30T08:15:00+00:00",
"improvement_opportunities": [
{
"type": "keyword_performance",
"message": "Competitors outrank you on 4 keywords you track: stock alerts, low stock. Improve your listing relevance for these.",
"priority": 1,
"current_value": "37% win rate",
"target_value": "50%+",
"link_to": "/competitors",
"keywords": [
{ "keyword": "stock alerts", "tracked": true, "installAttributed": false }
]
},
{
"type": "listing_quality",
"message": "Your app details field is significantly underutilized. This is the most impactful field for conversions.",
"priority": 1,
"current_value": "320 chars",
"target_value": "500 chars",
"link_to": "/suggestions/listings"
}
],
"competitor_comparison": [
{
"id": 4471,
"name": "Stocky",
"slug": "stocky",
"logo_url": "https://cdn.shopify.com/app-store/listing/stocky/icon.png",
"metrics": {
"rating": { "yours": 4.7, "theirs": 4.5, "winner": "you" },
"reviews": { "yours": 312, "theirs": 540, "winner": "them" },
"keywords": { "yours": 41, "theirs": 38, "winner": "you" },
"categories": { "yours": 4, "theirs": 3, "winner": "you" },
"estInstalls": { "yours": 5200, "theirs": 9100, "winner": "them" }
},
"winsCount": 3
}
]
}
Scorecard fields
- Name
object- Type
- string
- Description
Always
"scorecard".
- Name
overall_score- Type
- integer
- Description
Weighted overall competitive health score, 0–100.
- Name
listing_quality- Type
- object
- Description
Listing-quality sub-score as
{ score, breakdown }.breakdowncarriescharacterUtilization(per-field length/limit/utilization +featureCount),antiPatterns(count + per-field messages), andkeywordPresence(found/missinglists +source).
- Name
keyword_performance- Type
- object
- Description
Keyword-performance sub-score as
{ score, breakdown }.breakdowncarrieskeywordBreadth,outrankingRatio,topTenDensity,keywordCoverage, theoutrankedKeywordsandunrankedTrackedKeywordslists, and theoutrankedTrackedCount/unrankedTrackedCounttotals.
- Name
reviews_reputation- Type
- object
- Description
Reviews & reputation sub-score as
{ score, breakdown }.breakdowncarriesrating,volume,sentiment(with positive/neutral/negativedistribution),recency, and thecompetitorAdjustmentinteger (−5..+5).
- Name
visibility- Type
- object
- Description
Visibility sub-score as
{ score, breakdown }.breakdowncarriescategoriesRankedIn(with per-categoryrank),bestPosition,avgPosition, andcategoryGaps.
- Name
is_provisional- Type
- boolean
- Description
truewhen computed against a provisional comparison set (embedding-similar → top-category apps) because the team follows no competitors yet.
- Name
computed_at- Type
- string
- Description
When the scorecard was last computed (ISO-8601), or
nullif never.
- Name
improvement_opportunities- Type
- array
- Description
Prioritised opportunities (priority 1 = highest first). Each item:
type(one of the four sub-scores),message,priority,current_value/target_value(string/int/null),link_to(string/null), and optionallykeywordschips ({ keyword, tracked, installAttributed }) on keyword items.
- Name
competitor_comparison- Type
- array
- Description
Head-to-head against each followed competitor (empty when none are followed). Each item:
id,name,slug,logo_url, ametricsmap (rating/reviews/keywords/categories/estInstalls→{ yours, theirs, winner }wherewinneris"you"/"them"/"tie"), andwinsCount(0–5).
Errors
Beyond the universal 401 / 403 / 422 / 429 (see Errors), this endpoint returns:
404 resource_not_found— the addressed app does not exist or is not tracked by your team.
The scorecard does not read the Shopify Partner integration or BigQuery — it serves from the scraped catalog — so it never returns the 409 partner errors documented for the metrics endpoints. A bad refresh value surfaces as 422 validation_failed.