For developers
Everything BestAppify knows about your apps is available over HTTP, and over MCP so Claude and Cursor can query it for you. Same data, same numbers as the dashboard — it all reads from one layer.
Create a key in Dashboard → API & MCP and send it as a bearer token. Keys are shown once and stored only as a hash, so if you lose one, create another. X-API-Key works too, if a header called Authorization is awkward where you are.
curl -H "Authorization: Bearer ba_live_xxx" \
https://bestappify.app/api/v1/appsA key can read everything on your account, including revenue. Keep it server-side.
Every success is { data, meta } and every failure is { error: { code, message } }. Branch on code, not on the message — codes are stable, wording is not.
{
"data": {
"app": { "app": "fast-bundle", "name": "FBP | Fast Bundle Product", "app_id": 6174 },
"keywords": [
{
"keyword": "product bundles",
"keyword_id": 31,
"position": 12,
"last_known_position": 12,
"previous_position": 17,
"change": 5,
"as_of": "2026-07-28",
"is_current": true,
"difficulty": 68,
"competition": 41,
"demand": 73
}
]
},
"meta": { "generated_at": "2026-07-28T09:14:22.031Z", "count": 1 }
}Three habits worth knowing, because they run through the whole API. A position of null means the app was not in the search results we captured — not that it has no rank. is_current: false means the rank history matched to your app lags the newest crawl, usually by a day, when a crawl saw the listing before matching it to our catalog — position is still the live figure. And where a number is reconstructed rather than reported (MRR, churn, trials, keyword demand), the response says so rather than presenting it as Shopify's own.
120 requests per minute on every plan, and a daily allowance by tier — 100 on Free, 1,000 on Growth, 10,000 on Pro — counted per account across all your keys. Every response carries X-RateLimit-Remaining; a 429 carries Retry-After in seconds and names the plan with more headroom. MCP tool calls draw on the same allowance.
One endpoint — https://bestappify.app/api/mcp — over streamable HTTP, authenticated with the same key, on every plan including Free. 40 tools (all read-only unless your key has write scope): your apps, keyword rankings and history, opportunities, competitors and overlap, review intelligence, listing analytics, revenue and churn, real merchant search terms with the positions they saw, search headroom, week-over-week traffic and which store installed, plus forum mentions, catalog search, app details, the leaderboard, movers and niches.
The dialog opens pre-filled. Swap YOUR_API_KEY for a key from your dashboard — free plan included, no card.
Claude Code
claude mcp add --transport http bestappify https://bestappify.app/api/mcp --header "Authorization: Bearer YOUR_API_KEY"Cursor / Windsurf — ~/.cursor/mcp.json
{
"mcpServers": {
"bestappify": {
"url": "https://bestappify.app/api/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}Claude Desktop — claude_desktop_config.json
{
"mcpServers": {
"bestappify": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://bestappify.app/api/mcp",
"--header",
"Authorization: Bearer YOUR_API_KEY"
]
}
}
}Then ask things like
Base URL https://bestappify.app. Every {app} accepts the handle, the listing URL, or an id from /api/v1/apps.
/api/v1/meYour account, apps and rate limits
Confirms the key works and returns the app references every other endpoint accepts, plus how much of your rate limit you have used.
GET /api/v1/me
/api/v1/appsList your tracked apps
Every app on your account. The `app` field is the handle used in the paths below; `tracked_app_id` and `app_id` are returned for callers that prefer ids.
GET /api/v1/apps
/api/v1/apps/{app}/keywordsKeyword rankings
Your tracked keywords for one app with today's position, the week-over-week change, and the difficulty, competition and demand indices. `position` is the live standing and is null when the app did not appear in the latest crawl. `last_known_position` and `change` come from the rank history keyed to your app in our catalog; `is_current: false` means that history is a little behind the newest crawl, not that the app stopped ranking.
GET /api/v1/apps/fast-bundle/keywords
/api/v1/apps/{app}/keywords/{keyword}One keyword, with full rank history
Daily rank history for a single tracked keyword, oldest first, plus its current standing. `{keyword}` is the term (URL-encoded) or its keyword_id.
GET /api/v1/apps/fast-bundle/keywords/product%20bundles
/api/v1/apps/{app}/opportunitiesKeyword opportunities
Keywords one of your tracked competitors ranks for and this app does not, with the competitor's position.
GET /api/v1/apps/fast-bundle/opportunities
/api/v1/apps/{app}/competitorsCompetitors and keyword overlap
Your tracked competitor set with current rank and rank change, plus the keyword overlap matrix showing where each of you places.
GET /api/v1/apps/fast-bundle/competitors
/api/v1/apps/{app}/reviewsReview intelligence
Rating distribution, monthly review trend, countries, the AI theme analysis (what merchants love, complain about and ask for) and a comparison against your tracked competitors.
GET /api/v1/apps/fast-bundle/reviews?recent=25
/api/v1/apps/{app}/analyticsListing analytics
Listing views, install clicks, installs, click-through and conversion from the Google Analytics property linked to the app, daily and totalled. Returns `connected: false` when no property is linked.
GET /api/v1/apps/fast-bundle/analytics?days=30
/api/v1/apps/{app}/searchReal merchant searches and the positions they saw
The search terms merchants actually typed to reach your listing, the position they actually saw (with Shopify's sponsored slots removed so it matches organic rank), plus device, country, locale and Install clicks per term. Read from the Google Analytics property linked to the app. This is the merchant's own answer, not our crawler's — `/keywords` is the crawler, works for any app including competitors, and needs no setup. Add `?format=csv` for a spreadsheet. Returns `connected: false` when no property is linked.
GET /api/v1/apps/fast-bundle/search?days=30&device=mobile
/api/v1/apps/{app}/search/opportunitiesKeyword headroom, weighted by how beatable the field is
Ranks the terms already sending you traffic by how much more they could send. Estimates the demand behind your current views, asks what position 3 would have yielded, then discounts it by how strong the apps ranked above you are according to our own weekly crawl — `winnability`, `apps_above` and `median_reviews_above` are that discount, and no GA4-only tool can compute them. Scores are relative within one app's keywords, never across apps. Add `?format=csv` for a spreadsheet.
GET /api/v1/apps/fast-bundle/search/opportunities?limit=20
/api/v1/apps/{app}/search/weeklyWeek-over-week search traffic, including what stopped
The same comparison as the Tuesday email, as data: views and Install clicks this week against last, per traffic source and per keyword, with `gained`, `lost`, `new` and — the one most worth automating against — `stopped`, the terms that drove traffic last week and none this week. The window is fixed at two seven-day periods ending three days ago because Google keeps revising recent days; `window` gives the exact dates.
GET /api/v1/apps/fast-bundle/search/weekly
/api/v1/apps/{app}/installs/shopsWhich store installed, and how it found you
Installs resolved to the store that made them: shop domain, shop id, date, device, country, and the search term most likely behind it (labelled as the inference it is — Shopify's install event is server-side and carries no page). Pass `shop_url` up to 50 times, or once comma-separated, to check specific stores; `not_found` lists the ones we have no install for. Needs `shop_url` registered as a GA4 custom dimension — when it isn't, the response says so in `note` rather than returning an empty list that looks like zero installs.
GET /api/v1/apps/fast-bundle/installs/shops?shop_url=acme.myshopify.com
/api/v1/apps/{app}/revenueRevenue and churn
Monthly MRR, churn rate, trials, installs, uninstalls and net revenue from the Shopify Partner API. MRR and churn are derived from the subscription charge lifecycle — the Partner API publishes neither directly. Returns `connected: false` when the app is not linked to a Partner app.
GET /api/v1/apps/fast-bundle/revenue?months=24
/api/v1/apps/{app}/intelligenceApp intelligence
Rank trajectory over time, position in each category, nearest competitors by category rank, and how the app's entry price compares with its peers.
GET /api/v1/apps/fast-bundle/intelligence
/api/v1/forum/mentionsShopify Community threads that mention your apps
Forum posts matching your apps' names or the keywords you track — most usefully, merchants asking for an app like yours. `is_strong` marks the ones we would email you about (your app named, or the term in a thread title or opening post) as opposed to a term appearing in a mid-thread reply; both are returned so you can apply your own bar. Add ?format=csv for a spreadsheet.
GET /api/v1/forum/mentions?filter=unread
/api/v1/apps/changesWhat changed on your listings — and your competitors'
Dated App Store listing changes for your apps and the rivals you track: taglines, descriptions, icons, screenshots, integrations, and listings leaving the store. `is_mine` separates yours from theirs. Covers competitors because it reads our own catalog crawl rather than your analytics — so these are events you can line up against your rank history. Only includes changes since we began recording. Add ?format=csv for a spreadsheet.
GET /api/v1/apps/changes?days=30
/api/v1/market/appsSearch the App Store catalog
Search every app we hold by name — not only your own. This is how you find a competitor's handle before looking it up.
GET /api/v1/market/apps?q=bundle
/api/v1/market/apps/{app}One catalog app
Any app in our catalog by handle, listing URL or id: rating, review count, description, categories, pricing plans and listing status.
GET /api/v1/market/apps/judge-me-reviews?include=intelligence
/api/v1/market/leaderboardTop apps by review volume
The App Store leaderboard, overall or for one category. Ranked by review count, because Shopify publishes no install numbers.
GET /api/v1/market/leaderboard?category=Product%20bundles
/api/v1/market/moversWeek-over-week rank movement
Which apps climbed and which fell over the last week, from our daily rank snapshots. `change` is positive for a climb; `rank_a_week_ago: null` marks an app new to the ranking.
GET /api/v1/market/movers
/api/v1/market/keywordsThe keyword directory
Every keyword merchants search on the App Store, harvested from the store's own autocomplete, with how many apps rank for it, who leads, and the difficulty, competition and demand indices. `demand` and `difficulty` are relative 0-100 indices built from the review volume of each term's top 10 — not search volume, which Shopify publishes nowhere. Add `format=csv` for a spreadsheet.
GET /api/v1/market/keywords?sort=difficulty&limit=50
/api/v1/market/keywords/{keyword}Who ranks for one keyword
Every app ranking for one App Store search, in order, with its rating, review count, entry price, category and the position it held a week earlier. Works for any keyword in the directory, not only ones you track.
GET /api/v1/market/keywords/product-bundles
/api/v1/market/nichesCategory growth and concentration
Every category with its app count, growth and the leader's share of reviews — for judging whether a niche is crowded or open.
GET /api/v1/market/niches
/api/v1/market/categoriesList categories
The App Store categories we hold at least five apps for, with counts. These ids and titles are what `?category=` accepts.
GET /api/v1/market/categories
| Code | HTTP | Meaning |
|---|---|---|
| missing_api_key | 401 | No Authorization header or X-API-Key header was sent. |
| invalid_api_key | 401 | The key does not exist or has been revoked. |
| rate_limited | 429 | More than 120 requests in the last minute. Retry-After says when to try again. |
| daily_limit_reached | 429 | More than 10,000 requests in the last 24 hours. |
| app_not_found | 404 | The app reference is not one of your tracked apps. |
| keyword_not_tracked | 404 | That keyword is not tracked for the given app. |
| keyword_not_found | 404 | No keyword in the public directory matched that term or slug. |
| category_not_found | 404 | No category matched the id or title given. |
| missing_query | 400 | A required query parameter was absent. |
| app_not_in_catalog | 409 | The app is tracked but our crawler has not matched it to a listing yet. |
| service_unavailable | 503 | The API is misconfigured or the database is unreachable. Safe to retry. |
| internal_error | 500 | An unexpected failure on our side. |
Keys take a few seconds to create, and the same one drives the API and the MCP server.
Create an API key