Subscription analytics

Open Subscriptions in an app’s dashboard to inspect App Store, Google Play and Stripe billing. Choose an inclusive UTC date range, daily, Monday-based weekly or calendar-month buckets, and a store. Production is the default; the dashboard sandbox toggle selects sandbox only.

Metric definitions#

MetricMeaning
Gross / refunds / netGross is paid initial purchases, trial conversions, renewals and one-time purchases in USD. Trials and family-shared purchases contribute no revenue. Refund value is positive; net = gross − refunds. These are store-reported gross amounts, before fees or tax deductions.
New paid subscriptionsNon-trial initial purchases plus trial conversions; one-time purchases excluded.
Trials and conversionTrial starts are initial trial purchases. Conversion is the proportion of trials started in the bucket that paid by the selected end date. Includes later paid renewals for the same store subscription. Recent cohorts are immature; this is observed conversion, not a fixed-window forecast.
RenewalsPaid renewal lifecycle events, excluding family-shared purchases.
CancellationsAuto-renew switched off; access may continue until expiration.
Expirations / churnExpirations count expiration events. Churn is opening paid subscriptions absent at closing, divided by opening paid subscriptions. Resubscribed customers still active at closing are not churned. Zero opening subscribers produces zero percent.
Active subscribers / trialsEntitled subscription rows at period end, excluding family sharing and one-time products. Grace periods count while entitled. Paid rows and trials are separate; multiple store subscriptions owned by one customer count separately.
MRRMonthly-normalized recurring gross USD for active paid subscriptions, including cancelled subscriptions until expiry. Uses billing.products[productId].period (ISO P1W/P1M/P1Y etc), then product-name period hints, then observed purchase-to-expiry duration. Annual ÷ 12, weekly × 365.2425 ÷ 84. Unknown periods/prices are omitted and reported in quality. Uses latest paid price, not the trial price.
30-day revenueRolling 30-day net revenue ending at the selected end date, independent of the selected start date.

Warehouse and history#

Processed store events are written to BigQuery billing_ledger after the operational claim completes. Warehouse failure is logged and never rejects a store event. Streaming insert IDs are deterministic; readers also deduplicate event IDs and SDK/store reports sharing a sale transaction. Run scripts/setup-bigquery.sh before enabling warehouse writes, then npx tsx scripts/backfill-billing-ledger.ts from web with existing credentials. Backfill sends processed events only and can be rerun safely for analytics.

Period-end charts use event state snapshots and billing_subscriptions current state when it predates the requested boundary. Events predating snapshots cannot reconstruct every past period: quality.stateIncomplete and the dashboard flag those periods. Firestore fallback has 400-day event retention, and uses cached daily FX instead of historical warehouse FX; historical currency results may differ. Warehouse history persists. Unknown FX is reported rather than silently treated as USD.

Shadow parity#

In shadow mode, the vs RevenueCat table compares daily lifecycle counts and USD values using the reconciliation cron’s type mapping, trial separation and SDK/store sale deduplication. RevenueCat rows exclude events whose properties.source is apprefer_billing. Stripe ledger-only values are expected when there is no RevenueCat Stripe integration. Comparison values follow the reconciliation contract; they are not the net-revenue chart. Unavailable comparison queries are displayed separately.

API and MCP#

GET /api/v1/apps/{appId}/subscriptions/metrics requires an organization key with apps:read and access to the app. Parameters: start/end (YYYY-MM-DD), bucket (day/week/month), store (all/app_store/play_store/stripe), sandbox (true/false). Defaults to 30 days. Maximum range is 731 days. Returns options, series, revenueByStore, revenueByProduct, kpis, quality, source and shadow parity. The admin-authenticated MCP tool get_subscription_metrics accepts 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_…