A Stripe export tells you what was billed, paid, failed and cancelled. It cannot tell you why a customer left, whether an email of yours saved someone, what happened in another billing system, or whether your trial users ever used the product. Knowing those limits is what keeps a leak number honest.
What does Stripe data show well?
A lot. Customers, subscriptions, invoices, charges and refunds give you the exact timeline of money: when an invoice was created, how many attempts it took, whether it was paid, when a subscription started, trialled, changed plan and ended. Decline codes sit on failed charges, and cancellations may carry a reason and feedback value.
That is enough to count failed payments and their outcome, split cancellations into involuntary and voluntary, value downgrades and size unconverted trials. The rest of this article is about where it stops.
Can it show saves made by email or support?
No. If a customer was won back by a message from another tool, an in-app prompt or a support conversation, Stripe shows only that the subscription continued. If a customer was not saved, Stripe shows the cancellation. So when my report counts cancellations with "no visible save", it means no discount and no pause in Stripe within 45 days before the cancel. The true number of unsaved cancellations is lower than what is visible, which is why I call it an upper bound.
The fix is to ask. Before I send a report I ask the customer whether they already send failed-payment emails or have a cancel flow. I cannot see either, and the answer changes how to read the numbers.
Can it show why someone cancelled?
Only if your flow records it. Stripe has a place for a cancellation reason and a feedback value on the subscription. If your cancel page never sets them, the field is empty. If it does, the choices need to be stable over time. Otherwise the reasons from this month cannot be compared with last month's.
I use the reason in one place: a cancellation with payment_failed counts as involuntary. The rest of the classification uses invoice behaviour. See voluntary vs involuntary churn.
Can it show who actually used the product?
No. Stripe knows billing. It does not know whether a trial user connected an account, created a first project or returned on day three. That matters because the mechanism I work from is that trials reaching a first moment of value tend to convert. To act on trials you need product events from your own app. A billing export can size the trial gap but cannot explain it.
More in how to calculate trial-to-paid conversion.
What about coupons, currencies and usage-based plans?
- Coupons: I value at list price times quantity, which slightly overstates customers with heavy discounts.
- Currencies: amounts in currencies other than USD are excluded unless an agreed rate is supplied, and the report states how many were excluded.
- Usage-based plans: with no fixed unit price, I use the last paid invoice.
What does it miss about the account itself?
Cancellations handled in another billing system do not appear, because Stripe never saw them. The history is limited to what Stripe holds for that account. And the tool covers a single account, not marketplace child accounts.
It also depends on the permissions you grant: customers, subscriptions, invoices, and charges and refunds at read. A missing permission fails the run with an error rather than returning zeros. That is deliberate, since a wrong zero is worse than no answer.
How does it handle very small accounts?
Poorly, and I say so. With fewer than about 30 events in a bucket, a figure is direction, not a result. A small account's monthly numbers can swing on a handful of customers. If you are well below roughly 2,000 paying customers, I would count by hand and read each case.
Does any of this make the report useless?
No, but it changes how to read it. Each number carries its caveat on page two of the report, next to how it is computed, so that you can see what could make it wrong. I also check totals against what you know: active recurring revenue should land within about 10% of your dashboard, the cancel counts should look plausible, and a recovery rate of exactly 0% or 100% means something is off in the data.
The report is a read of history. It cannot prove that a fix would work. For that you need a test, as in what a holdout group is.
Which of these limits matters most?
It depends on what you are deciding. For the cancel flow, the invisible saves matter most, since they change how large the gap really is. For trials, the missing product data matters most. For payments, Stripe sees almost everything, which is why I usually start there. A limit that does not touch the decision at hand can be left in the caveat list.
What should I add to the export myself?
Three things, if you have them: a note of every retention message you already send, your cancel flow's reason list, and an activation event for trial users. With them, the Stripe numbers become something you can act on. The Revenue Leak Report costs $490 and arrives within 48 hours of my having a restricted read-only key. Its synthetic sample shows where each caveat sits.
Want your own numbers?
The Revenue Leak Report puts failed payments, unconverted trials, cancellations and downgrades in dollars per month, read from a restricted read-only Stripe key. $490, delivered within 48 hours of receiving the key. Nothing in your account is changed.
Get the Revenue Leak Report - $490 See a sample (synthetic data)