# BestAppify — full reference for AI assistants > Growth and marketing platform for Shopify app developers. This file is generated from > the same source as the website, so it does not drift from what the product actually does. Site: https://bestappify.com Generated: this file is rebuilt daily from the live endpoint, MCP tool and content definitions. ## What BestAppify is A platform for developers who publish apps on the Shopify App Store. It answers: where does my app rank, who am I losing to, what do my reviews say, where does my listing traffic come from, and what should I fix next. It covers 29,401 apps across 120 categories — every app in Shopify's own sitemap, recounted daily. ## How the data is produced — and its limits Getting this right matters more than any feature list, because the honest limits are what distinguish our figures from invented ones. - **Keyword rankings are observed, not modelled.** A crawler renders the App Store search results page for each tracked keyword daily and records where each app appears. A position is an observation of the public results. - **Listings refresh weekly** — pricing, rating, review count, description, category. Diffing consecutive crawls produces a listing change history, for any app including competitors. - **Google Analytics is optional.** Connected, it adds the search term a merchant typed, the position they saw, their device, country and locale, and Install-click attribution. Shopify puts those in the listing URL, so we read them from GA4's pageLocation dimension with no customer setup. Per-store install attribution additionally needs `shop_url` registered as a GA4 event-scoped custom dimension, which does not backfill. - **Completed installs can never be attributed to a keyword by anyone.** Shopify's `shopify_app_install` event is server-side and carries no page. Install *clicks* (`add_to_cart`) are the attributable conversion. Where we show a likely search behind a specific store's install, it is explicitly an inference, not a fact. - **Positions are corrected for sponsored slots.** Shopify shows up to four ads on desktop and three on mobile, so a raw position is adjusted to give a comparable organic rank. This is an approximation: a search with no advertisers has no ad block. Both the raw and corrected numbers are retained. - **No App Store search volume exists.** Shopify publishes none and no endpoint exposes it. Any figure presented as App Store search volume is invented. We publish relative demand and difficulty indices derived from the review volume of each term's top ten, labelled as indices. - **Revenue, MRR and churn are reconstructed** from the Shopify Partner API's charge lifecycle, not reported by Shopify. Responses label them as our reconstruction. - **Rank history starts July 2026**, when snapshots began. Week-over-week movement needs seven days of history for an app. ## Plans Free tier with no card and no expiry — including API and MCP access. Growth $29/month, Pro $99/month; annual billing costs ten months rather than twelve. ## REST API Base: https://bestappify.app/api/v1 — bearer token (`Authorization: Bearer ba_live_…`) or `X-API-Key`. Rate limit: 120 requests/minute; per day by plan — 100 (Free), 1,000 (Growth), 10,000 (Pro) — per account, shared with MCP. Success shape `{ data, meta }`; failure shape `{ error: { code, message } }` — branch on `code`. Most list endpoints accept `?format=csv`. OpenAPI: https://bestappify.com/api/v1/openapi.json ### GET /api/v1/me Your account, apps and rate limits — Account Confirms the key works and returns the app references every other endpoint accepts, plus how much of your rate limit you have used. Example: `https://bestappify.app/api/v1/me` ### GET /api/v1/affiliate/programs The affiliate programmes you run — Affiliate program Every programme on your account with its payout terms and 30 days of analytics — link views, conversions, revenue and commission per affiliate. Empty when you run none. Example: `https://bestappify.app/api/v1/affiliate/programs` ### GET /api/v1/affiliate/programs/{program}/conversions One programme's conversion ledger — Affiliate program Every referred install and sale credited on a programme, each row carrying the commission rate frozen at the moment it was recorded — so a figure can be audited rather than trusted. Parameters: - `program` (path): The program_id from /api/v1/affiliate/programs. Example: `https://bestappify.app/api/v1/affiliate/programs/31/conversions` ### GET /api/v1/affiliate/earnings What you have earned promoting apps — Affiliate program Your side of the marketplace: totals and daily series, the individual referrals behind them, and your payout balance per programme. Scoped to your own account. Example: `https://bestappify.app/api/v1/affiliate/earnings` ### GET /api/v1/apps List your tracked apps — Your 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. Example: `https://bestappify.app/api/v1/apps` ### GET /api/v1/apps/{app}/keywords Keyword rankings — Your apps 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. Parameters: - `format` (query): Set to csv for a CSV download. - `app` (path, required): App handle, listing URL, tracked_app_id or app_id. Example: `https://bestappify.app/api/v1/apps/fast-bundle/keywords` ### GET /api/v1/apps/{app}/keywords/{keyword} One keyword, with full rank history — Your apps Daily rank history for a single tracked keyword, oldest first, plus its current standing. `{keyword}` is the term (URL-encoded) or its keyword_id. Parameters: - `app` (path, required): App handle or id. - `keyword` (path, required): Keyword term, URL-encoded, or its keyword_id. Example: `https://bestappify.app/api/v1/apps/fast-bundle/keywords/product%20bundles` ### GET /api/v1/apps/{app}/opportunities Keyword opportunities — Your apps Keywords one of your tracked competitors ranks for and this app does not, with the competitor's position. Parameters: - `app` (path, required): App handle or id. Example: `https://bestappify.app/api/v1/apps/fast-bundle/opportunities` ### GET /api/v1/apps/{app}/competitors Competitors and keyword overlap — Your apps Your tracked competitor set with current rank and rank change, plus the keyword overlap matrix showing where each of you places. Parameters: - `format` (query): Set to csv for a CSV download. - `app` (path, required): App handle or id. - `include` (query): Set to `timeline` to also return the daily rank timeline for every app. Example: `https://bestappify.app/api/v1/apps/fast-bundle/competitors` ### GET /api/v1/apps/{app}/reviews Review intelligence — Your apps 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. Parameters: - `format` (query): Set to csv for a CSV download. - `app` (path, required): App handle or id. - `recent` (query): How many individual recent reviews to include. Default 10, max 50. Example: `https://bestappify.app/api/v1/apps/fast-bundle/reviews?recent=25` ### GET /api/v1/apps/{app}/analytics Listing analytics — Your apps 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. Parameters: - `app` (path, required): App handle or id. - `days` (query): Window in days. Default 90, max 365. Example: `https://bestappify.app/api/v1/apps/fast-bundle/analytics?days=30` ### GET /api/v1/apps/{app}/search Real merchant searches and the positions they saw — Your apps 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. Parameters: - `app` (path, required): App handle or id. - `days` (query): Window in days. Default 30, max 365. - `device` (query): Filter to one device: desktop, mobile or tablet. - `country` (query): Filter to one ISO country code. - `search_type` (query): Filter to organic, paid, ai or other. - `format` (query): Set to `csv` for a CSV download. Example: `https://bestappify.app/api/v1/apps/fast-bundle/search?days=30&device=mobile` ### GET /api/v1/apps/{app}/search/opportunities Keyword headroom, weighted by how beatable the field is — Your apps 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. Parameters: - `app` (path, required): App handle or id. - `days` (query): Window in days. Default 90, max 365. - `limit` (query): Rows to return. Default 50, max 200. - `format` (query): Set to `csv` for a CSV download. Example: `https://bestappify.app/api/v1/apps/fast-bundle/search/opportunities?limit=20` ### GET /api/v1/apps/{app}/search/weekly Week-over-week search traffic, including what stopped — Your apps 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. Parameters: - `app` (path, required): App handle or id. Example: `https://bestappify.app/api/v1/apps/fast-bundle/search/weekly` ### GET /api/v1/apps/{app}/installs/shops Which store installed, and how it found you — Your apps 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. Parameters: - `app` (path, required): App handle or id. - `shop_url` (query): Shop domain to look up. Repeatable, or comma-separated. Up to 50. Omit for every store. - `days` (query): Window in days. Default 365, max 365. - `limit` (query): Stores to return. Default 200, max 1000. - `format` (query): Set to `csv` for a CSV download. Example: `https://bestappify.app/api/v1/apps/fast-bundle/installs/shops?shop_url=acme.myshopify.com` ### GET /api/v1/apps/{app}/revenue Revenue and churn — Your apps 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. Parameters: - `app` (path, required): App handle or id. - `months` (query): Months of history. Default 12, max 36. Example: `https://bestappify.app/api/v1/apps/fast-bundle/revenue?months=24` ### GET /api/v1/apps/{app}/intelligence App intelligence — Your apps Rank trajectory over time, position in each category, nearest competitors by category rank, and how the app's entry price compares with its peers. Parameters: - `app` (path, required): App handle or id. Example: `https://bestappify.app/api/v1/apps/fast-bundle/intelligence` ### GET /api/v1/forum/mentions Shopify Community threads that mention your apps — 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. Parameters: - `filter` (query): active (default, hides dismissed), unread, dismissed, or all. - `limit` (query): 1–100, default 50. - `offset` (query): Rows to skip, for paging. - `format` (query): Set to csv for a CSV download. Example: `https://bestappify.app/api/v1/forum/mentions?filter=unread` ### GET /api/v1/apps/changes What changed on your listings — and your competitors' — Your apps 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. Parameters: - `days` (query): Look-back window, 1–365 (default 30). - `limit` (query): Rows to return, 1–300 (default 100). - `format` (query): Set to csv for a CSV download. Example: `https://bestappify.app/api/v1/apps/changes?days=30` ### GET /api/v1/market/apps Search the App Store catalog — Market data Search every app we hold by name — not only your own. This is how you find a competitor's handle before looking it up. Parameters: - `q` (query, required): Search term matched against the app name. - `limit` (query): Results to return. Default 20, max 50. Example: `https://bestappify.app/api/v1/market/apps?q=bundle` ### GET /api/v1/market/apps/{app} One catalog app — Market data Any app in our catalog by handle, listing URL or id: rating, review count, description, categories, pricing plans and listing status. Parameters: - `app` (path, required): App handle, listing URL or id. - `include` (query): Set to `intelligence` to add rank trajectory and the pricing benchmark. Example: `https://bestappify.app/api/v1/market/apps/judge-me-reviews?include=intelligence` ### GET /api/v1/market/leaderboard Top apps by review volume — Market data The App Store leaderboard, overall or for one category. Ranked by review count, because Shopify publishes no install numbers. Parameters: - `format` (query): Set to csv for a CSV download. - `category` (query): Category id or exact title. Omit for the overall board. - `limit` (query): Apps to return. Default 25, max 100. Example: `https://bestappify.app/api/v1/market/leaderboard?category=Product%20bundles` ### GET /api/v1/market/movers Week-over-week rank movement — Market data 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. Parameters: - `category` (query): Category id or exact title. - `limit` (query): Apps to return. Default 25, max 100. Example: `https://bestappify.app/api/v1/market/movers` ### GET /api/v1/market/keywords The keyword directory — Market data 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. Parameters: - `q` (query): Filter to keywords containing this text. - `sort` (query): `demand` (default), `difficulty` (easiest first), `apps` or `newest`. - `brand` (query): Brand keywords — searches for a named app — are excluded by default. `only` returns just those, `include` returns both. - `limit` (query): Keywords to return. Default 50, max 200 (1,000 for CSV). - `offset` (query): Rows to skip, for paging. `meta.total` is the full count. - `format` (query): Set to `csv` to download instead of returning JSON. Example: `https://bestappify.app/api/v1/market/keywords?sort=difficulty&limit=50` ### GET /api/v1/market/keywords/{keyword} Who ranks for one keyword — Market data 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. Parameters: - `keyword` (path, required): The keyword, URL-encoded, or its slug. Both `product bundles` and `product-bundles` resolve. - `format` (query): Set to `csv` to download the ranked apps instead of returning JSON. Example: `https://bestappify.app/api/v1/market/keywords/product-bundles` ### GET /api/v1/market/niches Category growth and concentration — Market data Every category with its app count, growth and the leader's share of reviews — for judging whether a niche is crowded or open. Parameters: - `limit` (query): Categories to return. Default 30, max 100. Example: `https://bestappify.app/api/v1/market/niches` ### GET /api/v1/market/categories List categories — Market data The App Store categories we hold at least five apps for, with counts. These ids and titles are what `?category=` accepts. Example: `https://bestappify.app/api/v1/market/categories` ### GET /api/v1/market/rank-drivers What listing edits actually do to rank — Listing reviewer Across every app we crawl, what each kind of listing edit measurably did to search rank: how many edits of that kind were measured, the median places moved, and how the outcomes split between better, worse and no change. Correlational with small samples — read `coverage` and each field's `changes_measured` before quoting a figure, and carry the `caveat` into whatever you write. Parameters: - `days` (query): Look-back window. Default 120, range 7-365. - `category` (query): Category id or exact title to restrict to. Omit for the whole App Store. Example: `https://bestappify.app/api/v1/market/rank-drivers?days=120` ### GET /api/v1/market/keywords/{keyword}/rank-causes Who moved on this term, and what they had just changed — Listing reviewer Every app we saw move at least N places on one search term in the window, with the listing edits we logged for it shortly before the move. An empty `listing_changes_before` means we logged no edit, not that nothing happened. Parameters: - `keyword` (path): The term (URL-encoded) or its slug. - `days` (query): Look-back window. Default 60, range 7-365. - `min_places` (query): Smallest move worth reporting. Default 3, range 1-40. - `limit` (query): Moves to return. Default 15, max 50. Example: `https://bestappify.app/api/v1/market/keywords/product-bundles/rank-causes` ### GET /api/v1/market/apps/{app}/change-impact One app's edits and what each one did — Listing reviewer Any catalog app's logged listing edits, each with the rank effect measured on the keywords it ranked for either side of the edit. Works for apps you do not own, which is how you read a competitor's playbook. `keywords_entered`/`keywords_exited` are null when `crawl_coverage_comparable` is false — our crawl volume differed too much either side for those counts to mean anything. Parameters: - `app` (path): Any catalog app's handle or id. - `days` (query): Look-back window. Default 120, range 7-365. - `limit` (query): Edits to return. Default 20, max 50. Example: `https://bestappify.app/api/v1/market/apps/fast-bundle/change-impact` ### POST /api/v1/apps/{app}/listing/review Senior review of a listing change you are about to make — Listing reviewer Send the change you intend to ship — new name, tagline or description, the terms it targets, and your reasoning — and get back deterministic checks plus a prioritised critique. `checks` is computed from the database and is authoritative; `review` is judgement over the same evidence. Paid plans only, capped per account per day; an identical body is served from cache and does not count against the cap. Parameters: - `app` (path): One of your tracked apps. Example: `https://bestappify.app/api/v1/apps/fast-bundle/listing/review` ### GET /api/v1/apps/{app}/screenshots/headlines What rivals write ON their screenshots — Listing reviewer The marketing copy painted on the listing screenshots — yours, the apps ranked above you on your category boards, and the most-reviewed apps in the App Store — transcribed off the images by a vision model, with the layout each uses. The alt-text caption is in the listing HTML anyone can fetch; the headline is not, and it is the one a merchant scrolling the gallery actually reads. Free on every plan: it returns transcriptions that already exist and never calls a model. Parameters: - `app` (path): One of your tracked apps. - `scope` (query): `category` for the apps above you, `store` for the biggest apps in the App Store, `all` for both (default). - `max_slots` (query): Screenshots per rival, from slot 1 forward. Default 6, max 20. Example: `https://bestappify.app/api/v1/apps/fast-bundle/screenshots/headlines?scope=category` ### POST /api/v1/apps/{app}/screenshots/headlines Rewrite your screenshot headlines to the leaders' pattern — Listing reviewer Names the headline formula the leading apps share — counted from their transcribed headlines, every example quoted verbatim — says whether your gallery follows it, and rewrites the slots that don't in your own voice. Paid plans only and capped per day on the same budget as the listing reviewer; an uncached run transcribes unread rival galleries and writes a review, so expect up to ninety seconds. If your client times out waiting, retry — the review is written before the response is sent, so the retry is a cache hit. Without `refresh` a cached review is served in under a second and does not count against the cap. Parameters: - `app` (path): One of your tracked apps. Example: `https://bestappify.app/api/v1/apps/fast-bundle/screenshots/headlines` ### GET /api/v1/apps/{app}/listing/history What we told you before, and whether it worked — Listing reviewer Every review and proposal we have given for this app, each matched to the listing changes that landed afterwards, whether the live copy matches ours or your draft or neither, which flagged checks the live copy still fails, and the rank effect measured either side. Free on every plan — reading your own history spends no completion. Call it before starting a listing cycle; the review endpoint reads it too and will flag a repeat of advice that was ignored. Parameters: - `app` (path): One of your tracked apps. - `limit` (query): Reviews to return, newest first. Default 10, max 30. Example: `https://bestappify.app/api/v1/apps/fast-bundle/listing/history` ### POST /api/v1/apps/{app}/listing/proposal Have us write the listing rewrite — Listing reviewer Picks the terms worth going after from this app's rank data and its gaps against competitors, writes an app name, a tagline for the app card subtitle (62 characters) and an app details opening (500 characters) around them, states what the measured history suggests, and names the risks. The output is run back through the reviewer's own checks, so a failing check is authoritative over the copy. Paid plans only, same daily cap as the review endpoint. Parameters: - `app` (path): One of your tracked apps. Example: `https://bestappify.app/api/v1/apps/fast-bundle/listing/proposal` ## MCP server Endpoint: https://bestappify.app/api/mcp — streamable HTTP, same API key as the REST API, 67 tools, of which 19 act or produce rather than only report. ### list_my_apps Lists the Shopify apps on this BestAppify account, with how many keywords each one tracks. The 'app' argument other tools accept is one of these handles. ### get_keyword_rankings The App Store search position of one of my apps for each keyword tracked on it, with the week-over-week change. Tracked keywords are re-read about once a day (one live search per term, positions 1–24); each row carries measured_on, and a row marked stale was not re-read in the last 2 days. Merchants' own typed searches come from GA4, not from these re-reads. Difficulty, competition and demand are relative indices, not search volumes. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### get_keyword_history Daily rank history for one tracked keyword on one of my apps, oldest first. Points come from the bulk crawl until 2026-09-05 and from the once-a-day re-read of tracked terms since 2026-10-08, so expect a gap between those dates; measured_on is the latest point. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `keyword` (string, required): The keyword term, exactly as tracked. ### get_keyword_opportunities HISTORICAL — searches for apps like mine where at least two of my closest rivals (same primary category, most shared searches) placed in the top 10 of our search reads and my app did not place in the top 20. Only terms where at least 30% of the top 10 are apps in my primary category, and not another app's name. Most of those reads are from the bulk crawl that ended 2026-09-05 (untracked terms are not re-read), so each row carries measured_on and stale. Filtered to terms in my app's own vocabulary, with other apps' brand names removed. Ideas to verify, not a current shortlist; a term enters the daily re-read only once it is tracked. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### get_competitors The competitors tracked against one of my apps: rating, review count and their place in BestAppify's review-count ordering (not a Shopify rank; Shopify's own category-page order is a separate dataset), plus the keyword overlap showing where each of us places on each tracked term, dated per keyword (tracked terms are re-read about once a day). Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `include_timeline` (boolean): Include the daily rank timeline for every app. Large — only ask for it when the question is about how ranks moved over time. ### get_review_intelligence What merchants say about one of my apps: rating distribution, monthly review trend, countries, an AI analysis of what they love, complain about and request, and a comparison against tracked competitors. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `recent` (integer): How many individual recent reviews to include (0–50, default 10). ### get_listing_analytics Listing views, install clicks, installs, click-through and conversion for one of my apps, from its linked Google Analytics property. Returns connected=false when no property is linked yet. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `days` (integer): Window in days (1–365, default 90). ### get_search_terms The search terms merchants actually typed to find one of my apps, and the position they actually saw — read from the app's linked Google Analytics property, with Shopify's sponsored slots removed so positions match organic rank. Includes Install clicks, device, country and locale per term. This is first-hand merchant data, unlike our crawler's keyword re-reads, which cover any app including competitors but cannot know what a real merchant searched or whether they clicked Install. Returns connected=false when no GA4 property is linked. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `days` (integer): Window in days (1–365, default 30). - `device` (string): Filter to desktop, mobile or tablet. - `country` (string): Filter to an ISO country code, e.g. US. - `search_type` (string): Filter to organic, paid, ai or other. ### get_search_opportunities Which search terms could send one of my apps materially more traffic, ranked. Estimates the demand behind current views, asks what position 3 would yield, then discounts that by how beatable the apps ranked above are according to our own App Store crawl — winnability, apps_above and median_reviews_above carry that judgement. Answers 'what should I work on next'. Built from this app's own traffic, which makes it different from competitor-gap keyword ideas. Scores are relative within this app only and are not comparable across apps. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `days` (integer): Window in days (1–365, default 90). - `limit` (integer): Rows to return (1–200, default 25). ### get_weekly_search_traffic This week's search traffic for one of my apps against last week's, per source and per keyword — including 'stopped', the terms that brought traffic last week and none this week, which is usually the thing worth acting on. The window is fixed at two seven-day periods ending three days ago because Google Analytics keeps revising recent days, so the most recent three days are intentionally excluded, not missing. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### lookup_install_shops Installs of one of my apps resolved to the store that made them: shop domain, date, device, country, and the search term most likely behind it. The likely term is an inference, not a per-store fact — Shopify's install event is server-side and carries no page — so report it as such. Pass shop_urls to check specific stores (up to 50); not_found lists the ones with no recorded install. Needs shop_url registered as a GA4 custom dimension; when it isn't, the response explains that in `note` and an empty list does NOT mean nobody installed. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `shop_urls` (array): Shop domains to look up, up to 50. Omit for every store. - `days` (integer): Window in days (1–365, default 365). - `limit` (integer): Stores to return (1–1000, default 100). ### get_revenue_and_churn Monthly MRR, churn rate, trials, installs, uninstalls and net revenue for one of my apps, from the Shopify Partner API. MRR and churn are derived from the subscription charge lifecycle — Shopify publishes neither — so treat them as our reconstruction, not billed figures. Returns connected=false when the app isn't linked to a Partner app. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `months` (integer): Months of history (1–36, default 12). ### get_email_overview For one of my apps: how many merchant contacts it has (subscribed, unsubscribed, bounced), every email campaign and automatic flow with sent / opened / clicked counts, this month's sending against the plan limit, and attribution — paid plans that started within 30 days after a click on one of the emails (last click wins). Opens are an estimate; clicks are exact. Pro plan. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### draft_merchant_email Writes the subject and body of an email from my app to the merchants using it — a one-off campaign, or one step of an automatic flow (say when it lands with `moment`, e.g. '1 hour after a store uninstalls'). Uses only facts in the brief and the app's own App Store listing: anything it would need but wasn't given comes back under `needs` instead of being made up. Output uses the sender's formatting and merge tags, ready to save as a campaign draft. Spends one of 30 AI drafts a day. Pro plan. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `brief` (string, required): What the email is for, with any facts it should mention (a new feature, a deadline, a link). - `purpose` (string): campaign (one-off, default) or flow (automatic). - `moment` (string): For a flow email: when it goes out, in plain words. ### create_email_campaign_draft Saves a campaign DRAFT for one of my apps: a subject, a body and who it should go to. It never sends — the owner reviews it, sends a test and presses Send in the dashboard, so an agent can prepare campaigns without mailing anyone. Returns how many subscribed contacts the audience reaches right now and the link to review it. Audience keys (all optional, combined with AND): store_status (paying, trial, free, frozen, uninstalled, closed), plans, lists (list ids), trial_ends_within_days, installed_within_days, added_within_days, event_name + event_within_days, attr_key + attr_value. Needs a key with write access. Pro plan. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `name` (string): A name only the owner sees. - `subject` (string, required): The subject line; merge tags allowed. - `body` (string, required): The body, in the sender's formatting (blank line = paragraph, **bold**, [text](url), merge tags). - `audience` (object): Who it goes to (see the keys in the description). Empty = every subscribed contact. ### get_app_intelligence Rank trajectory over time, position in each category, nearest competitors by category rank, and how one of my apps' entry price compares with its peers. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### search_apps Search every Shopify app we hold by name — not just mine. Returns each app's handle, which identifies it everywhere else. Arguments: - `query` (string, required): Part of the app's name. - `limit` (integer): Results to return (1–50, default 20). ### get_app_details Details for any app in our catalog by handle, listing URL or id: rating, review count, description, categories, pricing plans and whether the listing is still live. Works on competitors, not only my apps. Arguments: - `app` (string, required): The app's Shopify handle, listing URL, or our catalog app_id. - `include_intelligence` (boolean): Also return rank trajectory, category positioning and the pricing benchmark. ### get_leaderboard Top Shopify apps by review volume, overall or within one category. Ranked on reviews because Shopify publishes no install counts — so read it as visible traction, not installs. Arguments: - `category` (string): Category title or id. Omit for the overall board. - `limit` (integer): Apps to return (1–100, default 25). ### get_movers Which apps climbed and which fell in the last week, from our daily rank snapshots. Positive 'change' is a climb; rank_a_week_ago=null means the app is new to the ranking. Arguments: - `category` (string): Category title or id. Omit for the overall board. - `limit` (integer): Apps to return (1–100, default 25). ### list_popular_keywords Keywords merchants actually search on the Shopify App Store, harvested from the store's own autocomplete — with how many apps rank for each, who leads, and difficulty/competition/demand indices. For finding terms worth targeting, or what a market is called. 'demand' and 'difficulty' are relative 0-100 indices built from the review volume of each term's top 10; they are NOT search volume, which Shopify publishes nowhere. Arguments: - `query` (string): Only keywords containing this text. - `sort` (string): 'demand' (default, biggest market first), 'difficulty' (easiest to rank first), 'apps', or 'newest'. - `brand` (string): Brand keywords — merchants searching for a named app — are excluded by default. 'only' for just those, 'include' for both. - `limit` (integer): Keywords to return (1–100, default 30). ### get_keyword_apps 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 — plus keywords whose results overlap. Works for any keyword in the directory, not only ones on this account. 'in_catalog: false' means we saw the app ranking but have not crawled its listing yet, so its rating and pricing are null rather than zero. Arguments: - `keyword` (string, required): The keyword, e.g. 'product bundles'. Its slug works too. ### get_niches Every App Store category with its app count, growth and the leader's share of reviews — for judging whether a niche is crowded or open before building into it. Arguments: - `limit` (integer): Categories to return (1–100, default 30). ### get_forum_mentions Threads on the Shopify Community forums that name one of my apps or a keyword I track — most often a merchant asking for an app like mine, which is answerable. 'is_strong' is true for the mentions worth acting on (my app named, or the term in the thread title or opening post) and false when the term only appears in a mid-thread reply; both are returned. Each item carries a direct link to the post, so the useful follow-up is reading the thread and drafting a reply. Arguments: - `filter` (string): 'active' (default) hides dismissed mentions, 'unread' is what hasn't been looked at, 'dismissed' and 'all' are self-explanatory. - `limit` (integer): Mentions to return (1–100, default 25). ### get_listing_changes Dated changes to App Store listings — my apps and the competitors I track. Taglines, descriptions, icons, screenshots, integrations, and listings removed from the store. 'is_mine' is false for a competitor. This is the one dataset here that covers apps I do not own, because it comes from our own catalog crawl rather than anyone's analytics, so it is the way to answer 'what did my rival change, and when'. Only covers changes since recording began. 'changed_at' is when our crawl saw it: listings of tracked apps and their rivals are re-read nightly, the rest of the catalog less often, so it can trail the edit. A pricing row with a note is a rename with the same prices. Description changes are left out while our catalog holds the tagline in place of the full description. Arguments: - `days` (integer): Look-back window in days (1–365, default 30). - `limit` (integer): Rows to return (1–300, default 50). ### get_funnel The whole money chain for one of my apps in a single call: App Store listing views, install button clicks, installs, trials started, paying shops and MRR, with the conversion rate between consecutive steps. Views through installs come from the app's Google Analytics property over the requested window; trials through MRR come from the Shopify Partner API over its current month. Any step the customer has not connected returns measured:false with the reason and the exact fix, never a zero. Listing, pricing and review work all show up as ratios on this chain. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `days` (integer): Window in days for the Google Analytics half (1-365, default 30). ### get_conversion_impact For each edit to MY app's listing, the install-click rate and install rate in a window before and after it, so a copy change is judged by what it was meant to move. This is the measure for whether a tagline, description, icon or screenshot change worked: category rank moves with review count and app age, so a near-zero rank delta after a copy edit is the expected result and is not evidence the edit failed. Every row states whether it is measured, still filling its window, or not measurable because Google Analytics is not linked, plus how many days of data each side actually had. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `days` (integer): How far back to look for edits (1-365, default 120). - `window` (integer): Days either side of an edit to compare (1-60, default 7). ### get_review_timing When this app's reviews are written relative to install, against its tracked rivals and against the whole catalogue, plus what to change. Answers the question behind 'we need more reviews': across 60,000 reviews, 39% arrive in the first week and over half of those land on the day of install, while reviews written after a year average a full rating point's worth of complaints more. Useful for placing an in-app review prompt. It refuses a verdict on an app with too few reviews to have a distribution, and says so rather than dividing small numbers. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### get_pricing_benchmark This app's plan ladder against the apps a merchant scrolls past beside it: whether it offers a free plan and how many of its category do, where its cheapest paid tier sits against that category's quartiles, and how many paid tiers is normal there. The comparison set is the top of its own category pages in Shopify's order plus any tracked rivals, never the whole store, because a merchant choosing a helpdesk app compares helpdesk prices. Returns positional findings and the question each one raises; it will not tell anyone to change a price, because nothing here links a price to that app's revenue. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### get_outcomes The ledger for one app: every recommendation we have on record (listing reviews, rewrite proposals, screenshot headline reviews, listing audits), the listing changes that landed after each one, and the conversion effect of the first change that followed. Outcomes are measured in conversion, never category rank, because rank moves with review count and app age rather than wording. Advice that was ignored stays on the ledger, and the summary reports how much of what we said was acted on and how much could be measured at all — which is the honest state of the engagement. A change listed under a piece of advice came after it; that is adjacency, not proof of cause. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `days` (integer): How far back to read advice and changes (1-1095, default 365). ### get_rival_complaints The themes behind the one and two star reviews in this app's own categories, excluding the app itself, with a verbatim quote for each and a flag on the themes its listing never mentions. Answers two questions at once: what to build next, and what to say in the listing in the words merchants already use. The unit is the category rather than a rival set because the median app has only three one-star reviews and grouping that few invents themes; under forty complaints this refuses to answer and says so. It returns themes and quotes, never a list of merchants to contact. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### draft_listing_copy Ready listing text for one of my apps, written against what this market's merchants actually complain about and in their vocabulary: several taglines for the app card subtitle (the line under the app name on search and category cards) inside Shopify's 62-character limit, an opening for the app details (500 characters), and feature-list bullets (80 characters each). Every line names the complaint theme it answers. Crucially, every line that asserts a capability also carries claim_to_verify, the yes-or-no question the owner must answer before publishing, because we know what this market fails at and NOT what this app can do. Character limits are counted in code, not trusted to the model. This produces a draft to check, not copy to ship blind. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### render_screenshots For each gallery slot the headline review proposed new words for, the words themselves and a PNG rendered at Shopify's 1600x900 with that headline set over the app's OWN screenshot. The base image is always the app's real image: we do not generate a picture of an app interface, because a fabricated UI would not match what a merchant installs. A slot we hold no image for comes back renderable:false with the words ready for whoever has the source file. The image URLs need the same API key as every other call. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### draft_release_notes Writes the App Store changelog entry for a release, from a brief of what shipped. Pass `shipped` as one line per change; without it this returns the listing edits we have detected as a prompt and refuses to draft, because a tagline change is not a release and a changelog describing work nobody did is the one page merchants read as a promise. Adds nothing to the brief: anything too vague to publish comes back under `omitted` with what it would need instead. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `shipped` (array): One line per change that actually shipped. Fixes, additions, removals. ### draft_review_ask The in-app prompt and the follow-up email that ask for an App Store review, plus the moment to fire them, which is computed from our review-timing corpus rather than written by the model: the first week holds most reviews and the day of install is the single biggest moment in it. Nothing in the output claims anything about the product, so it can go in as written. Returns suppression cases too, because the fastest way to earn a one-star review is to ask someone who has just had a problem. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### get_connection_status Whether this app's Google Analytics property and Shopify Partner API are linked and actually returning data, what each one unlocks, and the ordered steps plus URL to connect whichever is missing. Both are read only. Until both are connected, anything said about what a change earned is an estimate. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### get_category_positions Where Shopify actually places one of my apps on each App Store category page it is listed in — the position a merchant browsing /categories/ sees — plus the same for every rival tracked under that app, with the day-over-day move and how many apps the crawl read in that category. This is Shopify's own order, not our review-count ranking, and it is read for every app daily (search positions are only re-read for tracked keywords). An app missing from a category is past the crawled pages, not unranked. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### explain_category_move Diagnoses one of my apps' movement on Shopify's category pages since the previous crawl day, and answers the question a rank change actually raises: was it me, my category, or the whole store? Returns, per category page, the move itself, how far the median app on that same page moved that day, how much the whole store moved, the apps that were below me and are now above me by name, the app directly above me now, and any listing edits I made in the fortnight before. Category positions are read nightly for every app, so this covers recent moves for any app; the search-keyword series covers every app only until 2026-09-05 (when Shopify blocked bulk search crawling) and only tracked terms since 2026-10-08. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### growth_briefing One call that runs the daily growth loop for one of my apps and returns a compact, dated briefing that opens with a computed judgement: do_first (up to three concrete actions, each with the dated number behind it) and what_changed (current facts only — review arrivals, week-over-week search-rank and category moves, rivals' real listing edits, GA4 traffic shifts). Then: the app's own search terms and positions from its GA4 (first-hand, when linked), each tracked keyword's latest daily re-read for this app and its tracked rivals with the date it was measured, Shopify category-page positions, rivals, recent reviews with reply status, the AI review analysis with its age (refreshed in the background when stale), and a review comparison labelled by sample. Every number carries its date. Designed as a once-a-day overview in a single call. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### growth_plan What to actually do this month to grow one of my apps: a ranked plan of 3-5 actions. Each action states the gap it closes against the apps placed above mine (with numbers and dates), the evidence that this lever matters, the expected effect and our confidence, the deliverable already produced (a review-ask message, tagline drafts with the claims to verify, a category to consider), and how it will be measured without needing Google Analytics. Also returns what is NOT worth doing and what we cannot see. Records the plan, so the next call opens with what moved since. Answers 'what should I do to grow'. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### whats_changed Only what MOVED for one of my apps, for a fast delta instead of full snapshots: the app's moves on Shopify's category pages (day over day and over 7 days), week-over-week search-rank moves on its tracked keywords (each dated; tracked terms are re-read about once a day), and dated App Store listing changes for this app and the rivals tracked under it within the look-back window (taglines, descriptions, icons, screenshots, integrations, removals; crawler misreads left out). The listing changes honour the 'days' window. Answers 'what's new since yesterday' without full snapshots. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `days` (integer): Look-back window in days for listing changes (1–365, default 7). ### compare_apps Side-by-side public profile of any two apps in the catalog — rating, review volume, description, categories, launch date and whether each listing is still live — for a fast head-to-head. Works on any apps, not only the ones on this account. Arguments: - `app_a` (string, required): First app: handle, listing URL or catalog id. - `app_b` (string, required): Second app: handle, listing URL or catalog id. ### find_niches Categories across the whole App Store ranked as opportunities — app count, recent growth, and the current category leader — for deciding where to build or expand next. Market-wide, not limited to the apps on this account. Arguments: - `limit` (integer): Niches to return (1–100, default 25). ### portfolio_briefing A one-call morning read across EVERY app on this account — for a team running several apps. Per app: how many tracked keywords climbed vs slipped week-over-week, the worst slips, and the top keyword opportunities. Lighter per app than the single-app briefing, so the whole portfolio fits one response. ### audit_my_listing Audits one of my apps' App Store listing against the top 5 apps on its own Shopify category page: app card subtitle (the line under the name on App Store search and category cards, limit 62 characters), meta description (the line Google shows in web search, limit 160 characters), pricing plans, screenshot count, rating and reviews for each, side by side with mine, plus the leaders' median scorecard (the same one bestappify.com/audit shows) and my tracked rivals. Adds my own search terms with dated positions (GA4 first when linked) and keyword ideas filtered to my app's own vocabulary, with other apps' brand names removed. Fields we do not hold are null, never zero. Returns the facts, not rewritten copy. Does not change the live listing. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. ### get_my_usage How much of this API key's rate limit is left right now — requests spent in the last minute and the last day against the caps — so a scheduled job can pace itself before hitting a 429. ### create_webhook Register an HTTPS endpoint to RECEIVE events instead of polling: BestAppify POSTs a signed JSON payload when a subscribed event fires. Returns a signing secret ONCE — verify the X-BestAppify-Signature header (sha256=HMAC-SHA256 of the raw body) with it on every delivery. Deliverable events: listing.changed (an App Store listing you track — yours or a competitor's — changed a tagline, description, icon, screenshots or integrations, or was removed), review.posted (a new review appeared on one of your apps), rank.moved (a tracked keyword moved 5+ places), competitor.launched (a new app appeared in one of your categories). Default is all of them; pass a subset in 'events'. Arguments: - `url` (string, required): Your public HTTPS endpoint to receive POSTed events. - `events` (array): Event types to receive. Default ['listing.changed']. ### list_webhooks The webhooks registered on this account — URL, subscribed events, active state, last delivery time and recent failure count. Signing secrets are never returned here. ### delete_webhook Remove a registered webhook by id so it stops receiving deliveries. Ids are listed with the account's webhooks. Arguments: - `id` (string, required): The webhook id from list_webhooks. ### ping_webhook Immediately POST a signed test payload (event: 'ping') to a registered webhook, to confirm your endpoint receives and verifies deliveries before a real event fires. Ids are listed with the account's webhooks. Arguments: - `id` (string, required): The webhook id from list_webhooks. ### ad_recommendations Turns our ranking data into a concrete paid-search plan for one of my apps — which keywords to BID on and which to STOP paying for. bid_to_capture: terms a competitor ranks for that I don't, so paid search buys visibility I lack organically. bid_to_lift_weak_organic: tracked terms where my organic position is weak (11+ or dropped out). stop_paying_already_top3: terms I already rank top-3 organically, where ad spend mostly buys clicks I'd get free. Also returns the demand-ranked opportunities with their winnability scores. It recommends the moves; you apply them in Shopify App Store Ads or an off-platform campaign — we do not touch your ad account. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `days` (integer): Window in days for the opportunity scoring (1–365, default 90). ### optimize_ad_campaign Reconcile YOUR current paid-search keywords — from Google Ads, Meta, or Shopify App Store Ads (your agent already has that access) — against our ranking data, and get exact moves: PAUSE keywords you already win top-3 organically (ads there mostly buy free clicks), KEEP the ones where paid is doing real work (weak or no organic), and ADD high-value keywords a competitor takes that you aren't bidding on. Pass the campaign's current keywords in 'current_keywords'. We recommend the changes; you apply them in your ad account — we never connect to or touch it, and never move budget on our own. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `current_keywords` (array, required): The keywords the campaign currently bids on. - `days` (integer): Window in days for the opportunity scoring (1–365, default 90). ### track_app Add one of my Shopify apps to this BestAppify account from its App Store handle or listing URL, so the per-app tools can answer about it. Reads the live listing on the spot (name, rating, review count) and returns the new handle and how many of the plan's app slots are used. Counts against the plan's tracked-app limit. Adding an app that is already on the account changes nothing and says so. Arguments: - `app` (string, required): The app's Shopify App Store handle (e.g. 'fast-bundle') or its listing URL. ### untrack_app Remove one of my apps from this BestAppify account. Everything attached to it on the account goes with it: its tracked keywords and competitors, its Google Analytics and Partner API links, its forum mentions and any affiliate program. Without confirm=true it deletes nothing and returns what would be removed; with confirm=true it removes the app and frees a slot against the plan's tracked-app limit. Catalog data about the app itself is kept. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `confirm` (boolean): Must be true to actually remove the app. Omit to see what would be removed. ### track_keyword Start tracking a search term for one of my apps. Tracked terms are re-read about once a day (one live App Store search per term, positions 1–24, deeper when my app is not on page one), and the first position usually arrives within a day; Shopify throttles some reads, so a term can be a day or two late. Counts against the plan's per-app keyword limit. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `keyword` (string, required): The keyword term to track (2–60 characters). ### untrack_keyword Stop tracking a keyword for one of my apps, freeing a slot against the plan's per-app keyword limit. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `keyword` (string, required): The tracked keyword term to remove. ### track_competitor Start tracking a competitor app against one of my apps — it then appears among the app's tracked competitors, its listing changes fire listing.changed webhooks, and it counts in keyword overlap. Pass the competitor's handle or listing URL. Counts against the plan's per-app competitor limit. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `competitor` (string, required): The competitor's Shopify handle or listing URL. ### untrack_competitor Stop tracking a competitor for one of my apps. Pass the competitor's handle or listing URL. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `competitor` (string, required): The tracked competitor's handle or listing URL. ### get_recent_calls This account's recent API and MCP calls, newest first — which tool or endpoint was hit, the HTTP status, and when. An audit trail for an owner who has handed keys to autonomous agents: a way to see what an agent actually did. Arguments: - `limit` (integer): Rows to return (1–200, default 50). ### what_moves_rank Across every app we crawl, what each kind of listing edit measurably did to search rank: how many edits of that kind we measured, the median places moved, and how the outcomes split between better, worse and no change. Measured outcomes rather than ASO folklore. Correlational and small-sampled on purpose; the payload states its own confidence. Arguments: - `days` (integer): Look-back window in days (7–365, default 120). - `category` (string): Optional category id or exact title to restrict to. Omit for the whole App Store. Call get_niches for valid titles. ### get_lessons What the system has measured across every Shopify app we crawl, re-measured every night: what separates the top 10 of a category page from places 11-50 (ratings, the Built for Shopify badge, a free plan, listing languages, screenshots, star rating), what listing edits did to category position, and how often a page's top 10 changes. Pass an app to see its own numbers beside the top 10 of its best category page; pass a category for that page's benchmarks; pass neither for the store-wide lessons. Every lesson carries its sample size, confidence and how long it has held. Associations, not causes. Answers 'what do top apps in my category have that I don't'. Arguments: - `app` (string): Optional. An app handle from list_my_apps, to compare it with its category's top 10. - `category` (string): Optional, used when no app is given: a category title exactly as get_niches lists it. ### explain_rank_move For one search term: every app we saw move at least N places in the window, and the listing edits we logged for that app shortly before the move. This is the evidence behind a claim like 'they overtook us after rewriting their tagline'. An empty listing_changes_before means only that we logged no edit — not that nothing happened. Pass an app instead of a keyword to get that one app's own edit history with the measured rank effect of each edit. Arguments: - `keyword` (string): A search term, or a keyword_id. - `app` (string): Alternative to keyword: any catalog app's handle or id (it does not have to be on this account). Returns that app's edits and what each one did. - `days` (integer): Look-back window in days (7–365, default 60). - `min_places` (integer): Smallest move worth reporting, keyword mode only (1–40, default 3). ### review_listing_draft Hand this a listing change you are about to make — a rewritten app name, tagline (the app card subtitle) or description (the app details), the terms you mean to target, and your reasoning — and it comes back as a senior review: a verdict, a score, and prioritised findings, each tied to a specific fact. It runs deterministic checks first (Shopify's character limits: app name 30, app card subtitle 62, app details 500; whether your copy actually contains the terms you claim to target, whether you are dropping a term this app is already top-10 for) and those checks are authoritative; the narrative review is judgement over the same evidence. Meant as the last check before a change goes live. Paid plans only, and capped per day because each review is a real completion. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `proposed_name` (string): The new app name, if you are changing it. - `proposed_tagline` (string): The new app card subtitle: the line under the app name on search and category cards (Shopify's limit is 62 characters). Not the meta description, which is a separate 160-character field. - `proposed_description` (string): The new app details text, or its opening (Shopify's limit is 500 characters). - `target_keywords` (array): The search terms this change is meant to win. Up to 6 are checked in depth. - `plan` (array): Other actions you intend to take, one per item, if the change is more than copy. - `rationale` (string): Your own reasoning for the change. Pass it — the review attacks the reasoning, not just the words, and that is where most of the value is. ### propose_listing_rewrite Writes listing copy rather than judging it. Picks the terms worth going after from this app's own rank data and the gaps against its competitors, then writes an app name, a tagline for the app card subtitle (62 characters) and an app details opening (500 characters) around them, says what the measured history suggests will happen, and names the risks. Its own output is then run through the same deterministic checks the reviewer applies, so a failing check is authoritative over the copy. Paid plans only, and capped per day. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `focus_keywords` (array): Terms the owner wants to go after. Omit to let the data choose them. - `tone` (string): Optional: how the copy should read (e.g. 'plain and technical'). - `notes` (string): Optional: anything the copy must or must not say. ### get_screenshot_headlines The marketing copy painted on the listing screenshots — this app's, the top-ranked apps on its category leaderboards, and the most-reviewed apps in the whole App Store. For each slot: the headline and sub-headline transcribed off the image by a vision model, the layout it uses, and the developer's alt-text caption beside it. Those two are different sentences and only the caption is in the page HTML, so the headline is the half nobody can read at scale without doing this. Answers 'what do the apps beating me actually say on image one'. Free on every plan; it returns what has already been transcribed and never calls a model itself. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `scope` (string): Which half of the cohort to return: 'category' (the apps ranked above this one), 'store' (the biggest apps in the App Store, any category), or 'all' (default, roughly twice the payload). - `max_slots` (integer): Screenshots per rival, from slot 1 forward (1-20, default 6). Slot 1 is the only image every merchant sees, so the front of the gallery is the part worth reading. ### review_screenshot_headlines Names the headline formula the leading apps share — counted from their actual transcribed headlines, with each example quoted verbatim — says whether this app's gallery follows it, and rewrites each slot that doesn't, keeping the app's own product terms and voice. Pass 'brand_notes' to pin the tone or words that must survive. Every rewrite carries the rival headline it follows, or is marked as judgement. It recommends copy; it cannot change a live listing, because Shopify does not allow that through us. Paid plans only and capped per day, since an uncached run transcribes unread galleries and writes a review; expect an uncached call to take up to ninety seconds, while a repeat call is served from the cache in under a second and costs nothing. The review is written before the response is sent, so a repeat call after a client timeout returns it from cache. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `brand_notes` (string): Optional: the voice to keep — tone, words that must appear, words to avoid. Overrides the voice inferred from the listing. - `refresh` (boolean): Recompute instead of serving the cached review, and transcribe the next batch of unread rival galleries. Costs one review against the daily limit. ### listing_review_history Closes the loop. Every listing review and proposal we have given for this app, each matched to the listing changes that actually landed afterwards, whether the copy that went live was ours or yours or neither, which of the checks we flagged the live copy still fails, and the rank effect measured either side of the change. Call it before starting a new listing cycle: it is the difference between an agent that improves and one that makes the same mistake monthly. Free on every plan — reading your own history costs no completion, so a downgraded account keeps it. Arguments: - `app` (string, required): The app's Shopify handle (e.g. 'fast-bundle'), its listing URL, or the app_id/tracked_app_id from list_my_apps. - `limit` (integer): Reviews to return, newest first (1–30, default 10). ## FAQ ### Getting started **What is BestAppify?** A growth and marketing platform for Shopify app developers. It tracks where your app ranks for App Store searches, watches your competitors, analyses your reviews, reads your listing traffic, and runs an affiliate programme for you. It covers every app in Shopify's own sitemap — 29,401 of them, recounted daily — across 120 categories, so the data about your market already exists before you sign up. **Do I need Google Analytics to use it?** No. This is the main difference between BestAppify and the alternatives. Your keyword rankings, competitor data, category standing, review analysis and listing history all come from our own crawl of the App Store, so they work on day one with no traffic, no tracking code and nothing to configure. Connecting Google Analytics later unlocks extra detail about your own visitors, but it is an upgrade, never a requirement. **Do I need a Shopify Partner account?** Only for revenue and churn reporting, which reads the Partner API to reconstruct MRR, trials and uninstalls. Everything else works without it. **How long until I see data about my app?** Immediately. Add your app and we crawl its live listing straight away, then match it against rankings and competitor data we already hold. There is no waiting period for traffic to accumulate. **Can I track apps I do not own?** Yes, and this is a genuine capability difference. Because our rankings come from crawling the public App Store rather than from a developer's private analytics, you can track any competitor's rank, pricing, reviews and listing changes exactly as you track your own. Tools built on a developer's own Google Analytics can only ever report on apps that developer owns. ### Keywords and rankings **Where do the keyword rankings come from?** We run the search on the Shopify App Store ourselves and record where each app appears. A crawler renders the results page for each tracked keyword daily, so a position is an observation of the public results, not an estimate or a model. **How often does the data refresh?** Keyword positions are crawled daily. App listings — pricing, rating, review count, description, category — are refreshed weekly: the catalogue crawl runs twice a week and covers half of it each time, oldest first. Overall and per-category rank snapshots are taken daily, and week-over-week movement becomes available once seven days of history exist for an app. **Where do the keywords in the directory come from?** The App Store's own search autocomplete. A term only appears in autocomplete if merchants actually search it, which makes it a real demand signal rather than a guess. We harvest those terms monthly and currently publish more than 2,300 public keyword pages showing which apps rank for each one. **Do you show search volume for App Store keywords?** No, and be sceptical of anyone who does. Shopify publishes no search volume for the App Store and there is no endpoint that exposes it, so any figure presented as App Store search volume is invented. We publish relative demand and difficulty indices instead, derived from the review volume of each term's top ten, and we label them as indices rather than volumes. **Why does the position you report differ from what I see when I search?** Three ordinary reasons. Shopify inserts up to four sponsored slots on desktop and three on mobile, so the same organic result sits at a different place on the page; results vary by locale and country; and your own browsing history influences what you personally see. Our crawl records a consistent, unpersonalised view, which is what makes positions comparable over time. ### Google Analytics and search intelligence **What does connecting Google Analytics actually add?** It adds what only your own visitors can tell you: the exact terms merchants typed to reach your listing, the position they actually saw, their device, country and locale, and which of those searches led to an Install click. Without it you get our crawler's view of your rankings; with it you also get the merchant's view of them. **What do I need to set up in Google Analytics?** For search terms and positions, nothing beyond adding your GA4 measurement ID to your listing in the Shopify Partner Dashboard — Shopify passes the search term and position in the page URL, which we read directly. For completed installs, also set a GA4 API Secret in the Partner Dashboard, because the install event is sent server-side and will not fire otherwise. For per-store install attribution, register shop_url as an event-scoped custom dimension in GA4; Google only makes event parameters queryable from the day they are registered, so that step does not backfill. **Can you tell me which store installed my app and what they searched?** We can tell you which store installed and when, on what device and from which country. The search behind it is an inference, not a fact, and we label it as one everywhere it appears: Shopify's install event is generated server-side and carries no page, so it contains no keyword. What we can honestly show is the term driving the most traffic to your listing that week, presented as the likely source rather than the confirmed one. **Why does the weekly traffic report stop three days ago?** Because Google keeps revising the most recent days as late events arrive. A report that ran to yesterday would show a decline every single week that was really just processing lag, so the window deliberately ends three days back and the report says so. **Is my Google Analytics data shared with anyone?** No. The connection is read-only, the refresh token is stored encrypted, and the data is only ever readable by your own account. It is never pooled into market-wide figures or shown to other customers. ### API, MCP and exports **Is there an API?** Yes, on every plan including Free. A documented REST API with 28 endpoints covering your apps, keyword rankings and history, opportunities, competitors, review intelligence, listing and search analytics, revenue, and public market data. There is a machine-readable OpenAPI document, and most list endpoints accept format=csv for spreadsheets. **Can Claude or Cursor query my data directly?** Yes — on any plan, including Free. We run an MCP server with 39 tools over streamable HTTP, authenticated with the same API key, so an AI assistant can answer questions about your app without you exporting anything. Setup snippets for Claude Code, Claude Desktop and Cursor are in the API reference. **What are the rate limits?** 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 REST and MCP together. Every response carries the remaining count, and a 429 carries a Retry-After and names the plan with more headroom. **Can I export to CSV?** Yes. Add format=csv to the list endpoints — keywords, search terms, opportunities, competitors, reviews, leaderboards, the keyword directory and per-store installs all support it. ### Plans and billing **Is there a free plan?** Yes, a genuinely free tier rather than a trial — no card, no expiry. Paid plans are Growth at $29 a month and Pro at $99 a month, and paying annually costs ten months rather than twelve. **Do I need a credit card to start?** No. The free plan needs no payment details at all. **Can I cancel whenever I want?** Yes, from the billing portal, and you keep access until the end of the period you have already paid for. ## Comparison with Rankbase (checked August 2026) Rankbase reads a developer's Google Analytics; BestAppify crawls the App Store. That means Rankbase needs existing traffic and a GA4 connection, and can only report on apps the developer owns. BestAppify works on day one and covers competitors. Where Rankbase is ahead today — team seats, Slack notifications, negative keywords, a review screenshot generator, and a longer rank history — it is listed below rather than omitted. ### What it takes to get value - **Works with no Google Analytics** — BestAppify: Yes — rankings come from our own App Store crawl. Rankbase: No — GA4 is the data source. (Their own site states the analytics require GA4 data and existing traffic.) - **Works with no existing traffic** — BestAppify: Yes. Rankbase: No. (A newly launched app has nothing to read in GA4 yet, but it already has a rank.) - **Free plan** — BestAppify: Yes — free tier, no card. Rankbase: 14-day trial, no card, then $49/mo. - **Entry price** — BestAppify: $0, then $29/mo. Rankbase: $49/mo. ### Competitor and market data - **Track competitors' rankings** — BestAppify: Yes — any app on the App Store. Rankbase: no. (A tool reading your own GA4 cannot see an app you don't own. This is structural, not a missing feature.) - **App catalogue** — BestAppify: 6,700+ apps, 120 categories. Rankbase: A 'best apps' directory. - **Competitor pricing and review benchmarks** — BestAppify: Yes. Rankbase: no. - **Listing change history for competitors** — BestAppify: Yes — we crawl every listing weekly. Rankbase: Own apps only. - **Public keyword directory** — BestAppify: 2,300+ public pages, no login. Rankbase: 2,134 pages (their published figure). (Comparable in size. Ours are public and carry rating, reviews, pricing and movement per ranked app.) ### Your own traffic - **Real search terms merchants used** — BestAppify: Yes, with GA4 connected. Rankbase: Yes. - **Position the merchant actually saw** — BestAppify: Yes, with GA4 connected. Rankbase: Yes. (Both correct for Shopify's sponsored slots so positions match organic rank.) - **Install-click attribution per keyword** — BestAppify: Yes, with GA4 connected. Rankbase: Yes. - **Per-store install lookup** — BestAppify: Yes, with GA4 connected. Rankbase: Yes. - **Length of rank history** — BestAppify: Since July 2026, growing daily. Rankbase: 365 days. (They have been collecting longer than we have. History is time, not engineering — this closes on its own.) - **Opportunity scoring** — BestAppify: Blends competitor strength from our crawl. Rankbase: Potential Score, from your own data. (Ours can ask whether the apps above you are beatable. Theirs has no competitor data to ask with.) ### Beyond rankings - **Review intelligence** — BestAppify: Yes — crawled reviews with AI theme analysis. Rankbase: no. - **AI listing audit and optimiser** — BestAppify: Yes. Rankbase: no. - **Revenue, MRR and churn** — BestAppify: Yes, via Shopify Partner API. Rankbase: no. - **Affiliate programme tooling** — BestAppify: Yes — links, payouts, marketplace. Rankbase: no. - **Community forum mention alerts** — BestAppify: Yes. Rankbase: Yes. ### Where they are ahead of us today - **Team seats and shared accounts** — BestAppify: Yes — invite teammates, owner-billed, shared apps and keywords (Pro). Rankbase: Yes — invite members, owner-billed, team-scoped keys. (Ours ships with the Pro plan; revenue stays visible to the owner only.) - **Slack notifications** — BestAppify: Email only. Rankbase: Yes, including private channels. - **Negative keywords** — BestAppify: no. Rankbase: Yes. - **Review screenshot generator** — BestAppify: no. Rankbase: Yes — free public tool. ### Getting data out - **REST API** — BestAppify: 26 endpoints, 120 req/min. Rankbase: 4 endpoints, 60 req/min. - **MCP server for Claude and Cursor** — BestAppify: Yes — 21 read-only tools. Rankbase: Yes. - **CSV export** — BestAppify: Yes. Rankbase: Yes. ## Other dated comparisons Each of these lives at its own page with a full sourced table, including where the competitor is the better pick: - [BestAppify vs Ranksy](https://bestappify.com/vs/ranksy): Ranksy is a paid analytics dashboard for your own apps with a Chrome overlay. BestAppify has a free tier, public keyword pages and crawls every competitor. - [BestAppify vs AppStorePulse](https://bestappify.com/vs/appstorepulse): Both crawl the Shopify App Store at $0/$29/$99. BestAppify adds GA4, keyword directory, affiliate and merchant calls; AppStorePulse indexes more. - [BestAppify vs Applora](https://bestappify.com/vs/applora): Applora is an AI research tool with monthly credits. BestAppify is a dashboard with public pages, GA4 and Partner data, and no per-query credit meter. - [BestAppify vs AppJubilee](https://bestappify.com/vs/appjubilee): AppJubilee: $29 Starter for 1 app, up to $499 Agency for 30. BestAppify Growth is $29 for 5 apps, with REST API, 63 MCP tools and a free tier — compared. - [BestAppify vs Asomify](https://bestappify.com/vs/asomify): Asomify is a lean ASO tracker whose hook is checking if ChatGPT names your app daily. BestAppify is the broader all-in-one Shopify app platform. - [BestAppify vs App Store Research](https://bestappify.com/vs/appstoreresearch): App Store Research sells paid calls with vetted Shopify merchants. BestAppify books the same calls inside a wider app-intelligence platform. - [BestAppify vs Fusionmetrics](https://bestappify.com/vs/fusionmetrics): Fusionmetrics is revenue analytics (MRR, churn, merchant moves). BestAppify is App Store intelligence — rank, keywords, competitors, listing. - [BestAppify vs Meridian](https://bestappify.com/vs/meridian): Meridian tracks whether ChatGPT recommends a merchant's products. BestAppify is for Shopify app makers — rank, competitors, AI mentions. - [BestAppify vs PartnerDock](https://bestappify.com/vs/partnerdock): PartnerDock is a dedicated affiliate platform for Shopify app founders. BestAppify is all-in-one — affiliate is one of twelve tools, on Pro. - [BestAppify vs SAMI](https://bestappify.com/vs/sami): SAMI is $8/mo with a 3-day trial and tracks 40 apps across 27,000 keywords. BestAppify has a free tier, 63 MCP tools and a REST API — compared, dated, sourced. ## Related sites - https://bestappify.com — this site, for Shopify app developers. - https://bestappify.com — separate site for Shopify merchants and store owners.