Data science · 10 min read
How to predict which Shopify customers will churn
Define churn for a store without contracts, score customers with RFM, BG/NBD probability alive or gradient boosting, and act on it in email flows.
Subscription businesses know exactly when a customer leaves: they cancel. A typical Shopify store never gets that signal. Customers simply stop ordering, and you only notice months later, when a win-back email is already too late. Predicting churn in this setting means estimating, for each customer, how likely it is that they have quietly stopped buying, and doing it early enough to matter.
How do you define churn when customers have no contract?
You choose a definition, and the choice should come from your own purchase rhythm rather than a number someone else uses.
- For every customer with two or more orders, compute the days between consecutive orders.
- Look at the distribution of those gaps. A coffee or supplement brand might see most reorders within a few weeks; a furniture brand might see gaps of a year or more.
- Pick a window that covers most genuine repeat purchases, for example the 80th or 90th percentile of the gap.
- A customer is churned (for modeling) if they have not ordered within that window after their last order.
Two refinements help. First, treat one-time buyers separately: “never came back” and “used to buy regularly, then stopped” are different problems with different fixes. Second, accept that the label is noisy. Some “churned” customers will come back on their own, which is exactly why probabilistic models are useful here.
If you have not looked at retention by acquisition cohort yet, start there: our guide on cohort retention analysis for Shopify shows how, and it tells you whether churn is a broad problem or concentrated in specific cohorts.
Is RFM good enough to spot at-risk customers?
RFM scores each customer on recency (days since last order), frequency (number of orders) and monetary value (total or average spend), usually as quintiles from 1 to 5. Customers with high frequency and value but poor recency are your classic at-risk group.
Shopify includes an RFM customer analysis report. According to Shopify’s documentation it gives each customer a three-digit score with each digit from 1 to 5, and assigns them to one of 11 RFM groups, such as Champions, Loyal, At risk, Almost lost and Dormant. The group is based on the recency score and the average of the frequency and monetary scores.
RFM’s strengths are speed and explainability: a marketer can see why someone is “At risk”. Its weakness is that recency is judged on the same scale for everyone. Sixty days of silence means nothing for a customer who orders twice a year and a lot for one who orders every three weeks.
How does BG/NBD estimate the probability a customer is still active?
The BG/NBD model (Fader, Hardie and Lee, 2005) fixes RFM’s blind spot by modeling each customer’s own rhythm. Its assumptions, from the original paper:
- While active, a customer makes purchases according to a Poisson process with their own rate.
- Purchase rates vary across customers following a gamma distribution.
- After any purchase, a customer becomes inactive with some probability, which also varies across customers following a beta distribution.
From those assumptions the model gives each customer a probability alive: the chance they have not yet dropped out, given their history. It needs only three numbers per customer: frequency (repeat purchases), recency (time from first to last purchase) and T (time from first purchase to the end of the observation period). A customer who bought every month and has now been silent for five months gets a low probability; a customer who buys yearly and was last seen five months ago does not.
In Python, the lifetimes library fits it in a few lines:
from lifetimes import BetaGeoFitter
from lifetimes.utils import summary_data_from_transaction_data
rfm = summary_data_from_transaction_data(
orders, "customer", "created", observation_period_end="2026-09-30"
)
bgf = BetaGeoFitter(penalizer_coef=0.001)
bgf.fit(rfm["frequency"], rfm["recency"], rfm["T"])
rfm["p_alive"] = bgf.conditional_probability_alive(
rfm["frequency"], rfm["recency"], rfm["T"]
)
PyMC-Marketing offers the same model as BetaGeoModel, with an expected_probability_alive method and Bayesian uncertainty around the parameters. Whichever you use, validate it: fit on a calibration period and check predicted against actual purchases in a holdout period, as described in our article on LTV forecasting with short histories. The same fitted model also gives expected future purchases, which is the basis of customer lifetime value.
One limitation to keep in mind: BG/NBD knows only purchase timing. It cannot tell that a customer’s last order was refunded, that they only buy during sales, or that they stopped opening emails.
When does gradient boosting beat the simpler models?
A supervised classifier earns its place when you have enough history to build training examples and features that carry information RFM and BG/NBD cannot see. The approach is a snapshot design:
- Pick a cutoff date in the past. Compute features using only data up to that date.
- Label each customer by whether they ordered in the churn window after the cutoff.
- Repeat for several cutoff dates to get more training rows and capture seasonality.
- Train on earlier cutoffs and evaluate on the latest one. Never shuffle customers randomly across time; that leaks the future into training.
from sklearn.ensemble import HistGradientBoostingClassifier
model = HistGradientBoostingClassifier(class_weight="balanced", max_iter=300)
model.fit(X_train, y_train) # snapshots before the last cutoff
scores = model.predict_proba(X_test)[:, 1]
scikit-learn’s HistGradientBoostingClassifier handles missing values natively and, per its documentation, is much faster than the classic GradientBoostingClassifier on datasets of 10,000 rows or more, which covers most customer tables worth modeling.
Compare it against RFM and BG/NBD on the same holdout using metrics that match how you will use the scores: precision among the top 10% or 20% of customers you would actually contact, and calibration (do customers scored at 0.3 churn about 30% of the time?). If the boosted model is not clearly better, ship the simpler one.
Which features from Shopify data predict churn?
Most of the useful signal is already in your orders, customers and products data:
| Feature group | Examples |
|---|---|
| Purchase rhythm | days since last order, number of orders, mean and latest gap between orders, ratio of current silence to the customer’s usual gap |
| Value | average order value, total net spend, spend trend over the last orders |
| Discount behavior | share of orders with a discount code, average discount depth on the first order |
| Returns | share of orders with refunds, refunded amount |
| Products | category of first purchase, number of distinct categories bought, whether they bought a consumable that should run out |
| Channel and context | order source or sales channel, shipping country, whether the customer accepts marketing |
| Tenure | days since first order, first-order month (to capture seasonal cohorts) |
If you can join engagement data from your email or SMS platform, such as days since last email open or click, it is often among the strongest predictors. Add the BG/NBD probability alive as a feature too: it is a compact summary of each customer’s purchase timing that the boosted model can refine with everything else.
Two cautions. Every feature must be computable as of the cutoff date; using a customer’s total lifetime orders when the label is about the future is a common leak. And mark wholesale, staff and subscription customers explicitly or exclude them, because their reorder patterns are different by design.
How do you act on churn scores in Klaviyo-style flows?
A score is only useful once it changes who gets which message. A workable pattern:
- Write the score back where your marketing tools can read it. On Shopify, customer tags (for example
churn-risk-high) can be used to build customer segments; if your email or SMS platform stores custom fields on contacts, you can send the score there instead. Check how your platform picks up tags or fields from Shopify and how often it syncs before you rely on it. - Segment by risk and value together. High value and rising risk is where a personal, early intervention pays. Low value and very high risk may not justify a discount at all.
- Time the message to the customer’s rhythm. Trigger the flow when silence exceeds the customer’s usual gap, not at a fixed day count for everyone.
- Keep a holdout. Randomly exclude a share of each targeted segment from the flow. Comparing reorder rates between the two groups is the only way to know whether the flow creates purchases or just discounts orders that would have happened anyway.
- Refresh the scores on a schedule that matches your buying cycle, weekly for fast-moving consumables, monthly for slower categories.
The holdout matters more than the model. A highly accurate churn model attached to a flow that changes nobody’s behavior produces nothing but discount cost; a mediocre model attached to a tested flow can produce measurable incremental orders.
Where should a Shopify brand start?
Start with the churn definition and the Shopify RFM report, add BG/NBD probability alive once you have a few months of repeat purchases, and only move to a gradient-boosted model when you have multiple years of history and the engineering to rebuild snapshots reliably. Asabisoft builds this progression for Shopify brands as part of LTV and retention analytics work, when a team wants the scores maintained and tested rather than run once.
Key takeaways
- Without a contract, churn is a modeling choice: pick an inactivity window from your own time-between-orders distribution, not a generic 90 days.
- RFM is a fast, explainable baseline; Shopify already ships an RFM customer analysis report.
- BG/NBD gives every customer a probability of still being active from just frequency, recency and customer age.
- Gradient boosting earns its place when you have several years of orders and richer features than RFM, and only if it beats the simpler models on a time-based holdout.
- Score customers by risk and value, and always keep a randomly held-out group so you can measure the incremental effect of win-back flows.
FAQ
How do you define churn for an e-commerce store without subscriptions?
Pick an inactivity threshold from your own data: look at the distribution of days between consecutive orders and choose a window that covers most genuine repeat purchases, often the 80th or 90th percentile of the gap. A customer with no order in that window is treated as churned for modeling purposes.
What is probability alive in the BG/NBD model?
It is the model's estimate that a customer has not yet silently dropped out, given how many repeat purchases they made, when the last one was, and how long they have been a customer. A frequent buyer who has gone quiet for much longer than usual gets a low probability.
Is machine learning better than RFM for churn prediction?
Sometimes. A gradient-boosted model can use product, discount, refund, channel and engagement features that RFM ignores, but it needs enough history to build training snapshots and must be validated on a later time period. If it does not clearly beat RFM and BG/NBD on that holdout, use the simpler model.
Should win-back emails go to the customers most likely to churn?
Not automatically. Some high-risk customers will not respond to anything, and some low-risk ones would have bought anyway. Combine risk with customer value, and test the flow against a holdout group so you know which segments actually respond.
Sources
- Fader, Hardie & Lee (2005), “Counting Your Customers” the Easy Way: An Alternative to the Pareto/NBD Model, Marketing Science 24(2)
- lifetimes — BetaGeoFitter API reference
- PyMC-Marketing — BetaGeoModel API reference
- scikit-learn — HistGradientBoostingClassifier
- Shopify Help Center — Customers reports (RFM customer analysis)
- Shopify Help Center — Customer tags