Churn states
Six mutually exclusive states derived from a user's latest billing events — never stored, so they can't go stale.
| State | Meaning |
|---|---|
in_trial | Inside a free trial that hasn't resolved. |
converted | Paid — a trial that converted, or a direct purchase. |
cancelled | Auto-renew switched off; access continues until the period ends. |
expired | Access has actually ended. |
billing_issue | A payment failed and the card is being retried. |
none | No billing history at all. |
States are derived on read from the billing event stream — RevenueCat and Stripe webhooks — rather than written to a column, so a late-arriving event corrects history automatically. An UNCANCELLATION restores the state the user was in before they cancelled.
Cancelled ≠ expired
The distinction runs through the whole product (and the billing webhook): cancelled users still have access and are the win-back window; expired users don't. Treating the two as one state undercounts your recoverable revenue.
You'll meet the same states in the Trial outcomes card, on each row of the Users table, on the single-user page, and as the cohort axis in Cohort compare. Trial conversion rate is trial users who paid ÷ all trial users.
Cohort compare
The same behavioral metrics, side by side across billing outcomes — what did the users who converted do that the ones who churned didn't?
How attribution works
A six-rung waterfall that resolves on every event batch, not just at install — so a user who arrives with no signal can still resolve later.