8.1 KiB
| name | description |
|---|---|
| store-analytics | Take store analytics snapshots for a mobile app or game (App Store impressions, product page views, downloads and conversion through the Analytics Reports API; Google Play store listing visitors, acquisitions and installs from the Play reports bucket) and compare them with listing, screenshot and experiment changes from git; download App Store sales / finance reports and Play earnings / sales reports with a summary per product and currency. Use when the user asks whether a listing change, new screenshots or a store experiment worked, wants install / conversion numbers, sets up store reporting, or wants sales, proceeds or earnings numbers. |
Store analytics
CLI: storebound analytics setup | snapshot | compare. MCP: analytics_snapshot, analytics_compare (offline),
analytics_setup. Read-only on both stores except setup (creates the App Store report request). Snapshots go to
.storebound/analytics/<date>.json (gitignored; they are your business numbers).
What is possible (and what is not)
- App Store: the Analytics Reports API. An Admin key creates one ONGOING report request (
storebound analytics setup); the first reports come 1-2 days later, then daily, and Apple keeps instances for 35 days, so take a snapshot at least monthly (weekly is better). A request left unread for a long time stops (stoppedDueToInactivity);setupmakes a new one. storebound reads "App Store Discovery and Engagement" (Event Impression / Page view, Counts and Unique Counts) and "App Store Downloads" (First-time Download, Redownload; updates are left out), checks each segment's md5 checksum and keeps, per day, the newest processing of that day. Conversion = (first-time downloads + redownloads) / unique impressions. App Usage (sessions, active devices, crashes) comes from the "App Sessions" and "App Crashes" reports of the same request. Source: https://developer.apple.com/documentation/appstoreconnectapi/downloading-analytics-reports - Google Play: there is no API for store listing statistics (the Play Developer Reporting API only has
vitals). Play Console writes monthly CSV exports into your own Cloud Storage bucket; storebound reads them with
the service account. Setup: Play Console > Download reports > Statistics > Copy Cloud Storage URI and put the
bucket into
play.reportsBucket(pubsite_prod_rev_<number>); the service account needs "View app information and download bulk reports" (Play Console Help answer 6135870). Files appear with a few days' delay; the current month's file grows daily. Conversion = store listing acquisitions / store listing visitors. - Not possible through any API: Play store listing experiment results and App Store Product Page Optimization
results (read them in the consoles;
storebound apple ppo statusshows the App Store test state), Play "Explore" search terms beyond the traffic source file.
For a collector (store-only config, JSON on stdout)
A script that reads many apps needs no project: a config with apple.appId (bundleId null or left out) and
play.packageName is valid for analytics and reports reads (every write still needs the bundle id).
storebound analytics snapshot --store apple|play --days 30 --config <virtual.json> --account <profile> --jsonprints the snapshot as one JSON document on stdout (logs go to stderr); the file in--diris still written, add--no-writeto skip it. A store that failed carries{ "error": ... }; when every store failed the JSON is printed and the exit code is 1. Non-fatal gaps are innotes.- Play bucket without
play.reportsBucket: envPLAY_REPORTS_BUCKET, else the credential profile'sreportsBucket(a bucket name, not a secret). Same forreports play-*. - Active users, per day. App Store:
sessions,activeDevices,sessionSeconds,crashesfrom the App Usage reports (App Sessions, App Crashes;activeDevicesis the sum of the rows' Unique Devices, so a device seen in two rows, e.g. two app versions, counts twice; totals:sessions,crashes,activeDevicesAvg). They appear a day or two after the report request exists; until then the snapshot has the rest and anotesline. Play:installs(Daily User Installs),activeDeviceInstalls(Active Device Installs) andtotalUserInstalls(Total User Installs) from the installs overview file (all countries; else the country file summed). The last two are stock numbers: totals take the newest day, never a sum. - Revenue per day:
storebound reports apple-sales --days 30 --json(or--from 2026-10-01 [--to 2026-10-25]) reads the daily SALES reports of the range (4 at a time):days[]withsummaryper SKU and currency andtotalsper currency,totalsfor the range per currency,missing(days with no report: no sales, or not out yet; never an error).storebound reports play-sales --days 30 --jsongroups the estimated sales by order charged date and currency of sale:orders,refunds,itemPrice,taxes,charged(tax included),refunded(negative),net, plusemptyDaysandmissingMonths. Play's earnings (proceeds after Google's fee) are monthly only.
Flow
- Once:
storebound analytics setup(App Store) andplay.reportsBucket(Play). - Weekly:
storebound analytics snapshot(default the last 28 days;--dryprints totals only). - Change the listing as usual and commit it (
store/appstore.md,store/listing.md,store/shots/..., the config). One change at a time, with a clear commit subject ("new first screenshot: boss fight"), makes the comparison readable. storebound analytics compare(or--mdfor a report): for every commit that touched the store files, daily impressions (App Store) or visitors (Play) and conversion in the 7 days before vs the 7 days from the change (--days 14for small apps).
Sales and finance reports
storebound reports <apple-sales | apple-finance | play-earnings | play-sales> downloads one report into
.storebound/reports/ (gitignored: these files hold per-order rows and buyer locations) and prints a summary per
product and currency plus <name>.summary.csv (or --csv <file>); totals are never added across currencies. --dry
shows the request only. MCP: reports.
- App Store:
apple-sales [--type SALES] [--frequency DAILY|WEEKLY|MONTHLY|YEARLY] [--date ...](Sales and Trends; other types: PRE_ORDER, SUBSCRIPTION, SUBSCRIPTION_EVENT, SUBSCRIBER, SUBSCRIPTION_OFFER_CODE_REDEMPTION, WIN_BACK_ELIGIBILITY, each with Apple's fixed frequency and version) andapple-finance --month YYYY-MM(Apple fiscal month; consolidated region ZZ,--detailfor the Financial Detail report, region Z1). Needs a team API key (not an individual key) with access to reports, and the vendor number (App Store Connect > Payments and Financial Reports) asASC_VENDOR_NUMBERin the environment, a credential profile (--account) or.storebound/credentials.json, never in the config. A 404 means "no report for that date" (no sales, or not out yet: daily reports come the next day). - Google Play:
play-earnings --month YYYY-MM/play-sales --month YYYY-MMreadearnings/earnings_YYYYMM*.zipandsales/salesreport_YYYYMM*.zipfromplay.reportsBucketand unzip them. The service account needs "View financial data" in Play Console (Users and permissions). Earnings arrive early in the next month; estimated sales update daily. - Money numbers are the owner's: never paste them into issues, commits or public text.
Read it honestly
- Small numbers swing: under a few hundred page views a week, a 20 % change is noise. Say so.
- Seasonality, featuring, ads campaigns, a rating drop and price changes move the same numbers. Look at the same weekday span and mention other things that changed in that window.
- A before / after comparison is not an experiment. For a real answer use the store tests: Play store listing
experiments (Console) and App Store Product Page Optimization (
storebound apple ppo, store-screenshots skill). - Never present estimates as facts to the owner, and never put these numbers into public text (listings, replies).