How to predict churn from Stripe data
Last updated 1 November 2026
You can predict a large share of SaaS churn from Stripe alone, with no tracking script, no data warehouse and no model. Stripe records the events that precede most cancellations weeks before the subscription ends. The work is reading them in one place, every day, and ranking the accounts so you call the right ones first. This guide walks through the signals, how to weigh them, how to check that they work on your own history, and how to automate it.
Seven things Stripe records before a customer churns
- A scheduled cancellation.
cancel_at_period_endis true, orcancel_atis set. The customer has decided. They will stop paying at the end of the period, which can be weeks away on monthly plans and months on annual. If they cancelled through the Customer Portal and your portal asks why,cancellation_detailsholds the reason and their comment. - A failed payment. An open invoice with failed
payment_intentattempts, a subscription inpast_due, or a customer markeddelinquent. Stripe will retry, and many of these recover, but a card that fails on the first try is the single most common path to involuntary churn. - A card about to expire. The default payment method’s
exp_monthandexp_year. A card that expires before the next renewal, with no replacement on file, is a failed payment waiting to happen. Stripe’s card account updater catches some of these; not all issuers participate. - A smaller invoice than last time. Compare the latest renewal invoice to the one before it, after discounts. A drop of more than about ten percent means fewer seats, a lower plan, or a removed add-on. Downgrades precede cancellations often enough to be worth a conversation.
- A refund or a dispute. A dispute in the last six months or a refund in the last three is a customer who was unhappy enough to ask for money back. Disputes in particular rarely end in a renewal.
- A trial ending with no payment method.
trial_endwithin a week and no default payment method on the subscription or the customer. That trial will not convert unless someone acts. - A discount about to end. A recurring coupon whose
endis within the next six weeks, especially one taking a quarter or more off the price. The customer is about to see a bigger charge.
Two more are about timing rather than a change: an annual renewal within the next 30 to 60 days, when the customer is likely to re-evaluate, and a customer in their first 90 days, when churn is highest almost everywhere.
Turning signals into a score
Give each signal points in proportion to how strongly it predicts a cancellation and how urgent it is. A scheduled cancellation is close to certain, so it should put the account at high risk on its own. A failed payment is urgent but often recovers, so it is worth a bit less. A new customer is a background risk worth a nudge, not an alarm. Cap the total so a pile of weak signals can’t outrank one strong one.
The ranking matters more than the absolute number. The question the score answers is “who do I call first this morning”, and for that, consistent ordering beats calibrated probability.
Keep every rule explainable. The person reading the list has to be able to see “Card expires in 12 days, renews on the 23rd” and know what to do. A probability with no reason is not actionable.
Check it on your own churn before you trust it
Any rule set will flag accounts. The question is whether it flags the right ones early enough. Take every customer who cancelled in the last twelve months, rebuild how their account looked on each of the 90 days before the end from Stripe’s history (invoice dates, payment attempts, when the cancel was requested, refunds), and run the rules on each day. For each rule you get how many of the churned accounts it caught and how many days before the end it first fired. Mute rules that catch nothing on your data and tighten the ones that fire the day before, when it is too late. This is a backtest, and it is the step most teams skip.
One caveat: Stripe does not keep the history of a card’s expiry date, so the card rule can’t be replayed. Report it as not measurable rather than as a miss.
Automating it
Doing this by hand once is a useful afternoon. Doing it every morning is the point, and that needs a script or a product. Whatever you use should:
- read Stripe with a restricted key that can only read Customers, Subscriptions, Invoices, Charges and PaymentMethods, so it can never change anything;
- sync daily and, ideally, listen to the
customer.subscription.updatedandinvoice.payment_failedwebhooks so a cancellation or a failed card reaches you within minutes rather than the next morning; - send the list where you already look, email or Slack, with the reason next to every account, and let you record what you did about it;
- re-check the outcome a month later, so you know how much flagged revenue was actually saved.
Churnahead does all of this, with the rules above, the backtest, and the morning email, from a read-only Stripe connection. It also works with Paddle and Lemon Squeezy. It is free up to 25 paying customers. The exact rules and points are in the documentation.