Subscription analytics
Revenue, trials, renewals, churn and MRR from AppRefer Billing’s own records of App Store, Google Play and Stripe purchases.
Open Revenue in an app’s dashboard. Choose an inclusive UTC date range (up to 731 days), daily, Monday-based weekly or calendar-month buckets, and a store. Production is shown by default; the sandbox toggle shows sandbox purchases only. The numbers come from AppRefer Billing, so the app needs billing in shadow or primary mode.
Metric definitions
| Metric | Meaning |
|---|---|
| Gross / refunds / net | Gross is paid initial purchases, trial conversions, renewals (including recovered billing), one-time purchases and charged App Store or Google Play upgrades, in USD. Trials and family-shared purchases add no revenue. Refunds are shown as a positive value; net = gross − refunds. Amounts are what the store reports, before store fees; Stripe amounts exclude tax. |
| New paid subscriptions | Paid initial purchases of subscription products plus trial conversions. One-time purchases are not included. |
| Trials and conversion | Trial starts are initial purchases in a trial period. Conversion is the share of trials started in a bucket that went on to a paid payment by the end of the selected range. Recent cohorts are still maturing: this is observed conversion, not a forecast. |
| Renewals | Paid renewals (including recovered billing), excluding family sharing. |
| Cancellations | Auto-renew switched off. Access usually continues until expiry. |
| Expirations / churn | Expirations count expiry events. Churn is paid subscriptions active at the start of a period and not active at its end, divided by those active at the start. A subscription that lapses and is active again by the end of the period isn’t churned. No subscribers at the start gives 0%. |
| Active subscribers / trials | Subscriptions with access at the end of the period, excluding family sharing and one-time products. Grace periods count while they give access. Paid and trial subscriptions are counted separately. Counts are subscriptions, not people: one customer with two store subscriptions counts twice. |
| MRR | Monthly recurring revenue in USD from active paid subscriptions, including cancelled ones until they expire, at each subscription’s latest paid price (not the trial price). The period comes from billing.products[productId].period (ISO P1W, P1M, P1Y…), then hints in the product id, then the observed purchase-to-expiry length. Yearly ÷ 12, weekly × 52 ÷ 12. Subscriptions with an unknown period or price are left out and counted in quality.unknownMrrPeriods. |
| 30-day revenue | Net revenue for the 30 days ending at the selected end date, whatever the start date. |
Data sources and history
Every recorded store event is copied to the BigQuery billing_ledger table once it is processed. A failed copy never rejects the store event; a recovery job retries it. Readers remove duplicates by event id and count the SDK report and the store notification for one sale once.
Period-end counts are rebuilt from the state saved with each event and the current subscription records. Periods before state was saved with events can’t be fully rebuilt: the response sets quality.stateIncomplete and the dashboard flags them. If BigQuery is unavailable, metrics fall back to the operational records (400 days of events, at most 100,000, using current exchange rates), and source says firestore. Revenue in an unknown currency is reported in quality.unknownRevenue rather than treated as USD. Results are cached for five minutes.
Self-hosting: create the tables with web/scripts/setup-bigquery.sh, then backfill with npx tsx scripts/backfill-billing-ledger.ts from web/ (safe to re-run), and schedule GET /api/cron/billing-warehouse every 15 minutes.
Comparing with RevenueCat (shadow mode)
While an app is in shadow mode, the “vs RevenueCat” table compares daily counts and USD values per event type between AppRefer’s ledger and what RevenueCat delivered, from a daily reconciliation. It appears for production with all stores selected. RevenueCat events that AppRefer Billing produced itself are excluded. Stripe values show as AppRefer-only unless RevenueCat’s own Stripe integration was also in use. These comparison values follow the reconciliation’s rules, so they are not the net revenue chart. See Moving from RevenueCat.
API and MCP
GET /api/v1/apps/{appId}/subscriptions/metrics with an organization key that has apps:read. Parameters: start and end (YYYY-MM-DD, inclusive; default the last 30 days; end is capped at today), bucket (day, week, month), store (all, app_store, play_store, stripe) and sandbox (true/false). It returns options, series, revenueByStore, revenueByProduct, kpis, quality, source and the shadow parity rows. The admin MCP tool get_subscription_metrics takes the same fields plus appId.
GET /api/v1/apps/app_example/subscriptions/metrics?start=2026-09-01&end=2026-09-30&bucket=week&store=all
Authorization: Bearer ak_live_…To check that billing is set up before a release, use the billing readiness endpoint.