Stripe knows exactly who cancelled, who stopped paying, and who downgraded, but the churn rate you read off the dashboard is subscriber churn over a trailing window, which is rarely the number a SaaS team needs. How to compute logo churn, revenue churn and involuntary churn from Stripe data, the six mistakes that quietly distort each, and one API change that silently broke renewal dates for everyone.
Short answer
How do you measure churn in Stripe correctly?
Stripe reports subscriber churn (logo churn over a trailing window). To get the numbers a SaaS team actually needs, compute three things from subscription and invoice data: logo churn (subscriptions ended ÷ active at the start of the period), revenue churn (MRR lost to cancellations and downgrades ÷ MRR at the start), and involuntary churn (subscriptions whose cancellation_details.reason is payment_failed, plus anything past_due or unpaid). Then avoid the six distortions below.
Stripe is the most honest record of churn most SaaS companies have. It knows who cancelled, who stopped paying, who downgraded, and when. It also produces a churn rate on the dashboard that is technically correct and rarely the number anyone meant to ask for. This post is about the gap between the two: what Stripe measures, what you probably need, how to compute it, and the six ways the calculation goes wrong quietly.
Stripe's Billing analytics show subscriber churn: the subscriptions that ended in a period as a share of those active when it began, over a trailing window. That is logo churn. It is useful, and it is one of three numbers. Stripe does not present revenue churn, gross versus net retention, or involuntary churn as headline figures. Those come from the data, not the dashboard.
| Metric | Formula | Stripe source |
|---|---|---|
| Logo churn | Subscriptions ended in period ÷ subscriptions active at START of period | Subscription status and ended_at / canceled_at |
| Revenue (gross) churn | (MRR cancelled + MRR downgraded) ÷ MRR at START of period | Subscription items: price × quantity, normalised to monthly |
| Involuntary churn | Subscriptions ended with reason payment_failed, plus past_due / unpaid, ÷ active at start | cancellation_details.reason; invoice attempts with outcome failed |
The third row is the one Stripe makes uniquely possible. A subscription that ended carries cancellation_details.reason: payment_failed means the charges kept failing until the subscription lapsed, cancellation_requested means somebody chose to cancel. Nobody outside your billing system can make that distinction, and it is the distinction that decides what to do, because involuntary churn is typically 20-40% of the total and the only kind that a sequence of emails reliably recovers.
Dividing churned MRR by end-of-month MRR flatters the rate, because the end-of-month figure includes the month's new sales. The denominator is always the MRR, or the subscriber count, at the start of the period. This is the most common error and the easiest to make in a spreadsheet, where the end-of-month total is the cell you happen to have.
A subscription in trialing that ends without converting is a failed trial, not a churned customer. It never paid. Counting it inflates logo churn and, on a product with a free trial, can double it. Filter to subscriptions that had at least one paid invoice before they ended.
On a month-to-month plan, an invoice paying is not a decision. The card was charged. Treating every monthly invoice as a renewal produces a renewal rate in the high nineties that means nothing, and buries the accounts whose real decision point is an annual term or a contract end date. Monthly plans are continuous; renewal analysis belongs to terms with an actual end.
Logo churn cannot see a customer who dropped from $2,000 a month to $400. Revenue churn must. A downgrade is a change in subscription items or quantity; the lost MRR is the difference between the old and new monthly value, and it belongs in the numerator alongside outright cancellations. Skipping it is how a book with “3% churn” loses 15% of its revenue.
When a subscription ends, the customer row does not vanish. In an export, or in any system that mirrors Stripe, a churned customer often keeps the MRR they used to pay until something explicitly zeroes it. Every read of “total MRR” or “revenue at risk” then has to exclude ended subscriptions, and the one that forgets quietly reports revenue from customers who left months ago.
This one is specific and worth knowing. In API version 2025-03-31, Stripe moved current_period_start and current_period_end from the subscription object onto each subscription item. Code that reads them from the subscription gets nothing back, and a missing field is not an error. Every renewal date downstream becomes a guess, with no log line to say so. We found it the hard way: 500 customers synced from a real account, zero contracts with a term. Read the period from items.data[].current_period_end.
Say the book on 1 August has 400 active paid subscriptions worth $180,000 MRR. During August, 12 subscriptions end: 8 with cancellation_requested (worth $4,100 MRR), 4 with payment_failed ($1,300). Six more customers downgrade, for $2,600 of lost MRR. Three trials expire without converting.
Once involuntary churn is separated out, it stops being a retention problem and becomes a billing-operations one, with a known fix: a decline-code-aware recovery sequence with a one-click pay link. The rest, the cancellations that were decisions, is where health scoring and outreach earn their keep, and it is smaller than the headline number suggested.
One caution on projecting recoveries. A backtest can tell you how many of your past failed payments never settled and what they were worth. It cannot tell you what share a sequence would have recovered, because that depends on your customers, your pay link, and your timing. A tool that quotes a recovery percentage before it has run on your book is quoting somebody else's.
Stripe's Billing analytics report subscriber churn: subscriptions that ended in a period divided by subscriptions active at the start of it, shown over a trailing window. That is logo churn. Stripe does not compute revenue churn, gross versus net retention, or involuntary churn as separate headline figures, so a SaaS team that needs those has to derive them from subscription and invoice data, with a start-of-period denominator and the cancellation reason on each subscription.
In Stripe, a subscription that ended carries cancellation_details.reason. The value payment_failed means the subscription lapsed because the charges kept failing, which is involuntary churn; cancellation_requested means the customer or your team cancelled it, which is voluntary. Subscriptions in past_due or unpaid status are involuntary churn in progress: the customer has not decided anything, their card has.
There is no Stripe-specific good churn rate; the benchmark depends on contract value. Roughly, top-quartile gross revenue churn is under 5% annually for enterprise, 5-8% annually for mid-market, and 5-7% monthly for self-serve SMB. What Stripe changes is not the benchmark but the measurement: it lets you separate involuntary churn, which is usually 20-40% of the total and the cheapest to recover, from the churn where a customer actually decided to leave.
Stripe's churn rate and a home-grown one usually differ for one of six reasons: a different denominator (end-of-period instead of start-of-period), trials counted as churn, monthly renewals counted as renewal decisions, downgrades missing from revenue churn, churned customers still carrying their old MRR in the export, or subscription period dates that came back empty after Stripe's 2025-03-31 API change moved them onto subscription items.
Stripe's API version 2025-03-31 moved current_period_start and current_period_end from the subscription object onto each subscription item. Code that still reads them from the subscription gets nothing back, and because a missing field is not an error, the failure is silent: every renewal date downstream becomes a guess. Read the period from items.data[].current_period_end instead.
A monthly Stripe invoice is not a renewal decision. On a month-to-month plan the customer has not chosen anything when the invoice pays; the card was charged. Counting every monthly invoice as a renewal inflates renewal rates and hides the accounts whose real decision point is an annual term or a contract end date. Treat monthly plans as continuous and reserve renewal analysis for terms with an actual end.
The six distortions are the ones Exeechain's Stripe sync has had to correct in its own reads, each found by comparing what the sync wrote against the Stripe account it read from. The benchmark ranges in the FAQ are industry ranges, not measurements Exeechain took. To get your own numbers, the leak scan reads a Stripe account read-only and reports the failed payments that never settled, by customer, with the dollars attached.
Keep reading
Customer success
10 min read · Sep 17, 2026
Retention metrics
9 min read · Sep 17, 2026
Retention metrics
9 min read · Sep 17, 2026
First scores in 15 minutes. Full accuracy in 24 hours. From $299/mo. Read-only Stripe connection, involuntary churn separated, recoveries under your approval.
Not ready to switch? Size your leak from your MRR and churn rate, with no billing access at all.