Why this matters
Most CRM programmes send the same message to everyone, or segment on demographics that barely predict behaviour. RFM fixes that with three numbers almost every business already has in its order table.
The logic comes from catalogue and direct-mail marketers, who learned long before email that past buying behaviour is the best predictor of the next purchase. A customer who bought last week is far more likely to buy again than one who bought last year. Someone who has bought ten times is more likely than someone who bought once. And the value of a response depends on how much the customer spends.
What makes RFM worth learning in 2026 is not the model itself. It is that RFM gives every team a shared language. “We have 4,200 At Risk customers worth 18% of last year’s revenue” is a sentence finance, CRM and product can all act on.
The framework
The three dimensions
| Letter | Question | D2C measure | Score 5 means |
|---|---|---|---|
| Recency | How recently did they buy? | Days since last order | Bought most recently |
| Frequency | How often do they buy? | Number of orders in the lookback window | Most orders |
| Monetary | How much do they spend? | Total or average net revenue in the window | Highest spend |
Use a fixed lookback window, usually 12 or 24 months, so old one-off buyers do not dilute the ranking. Use net revenue (after discounts and returns), since COD refusals and returns can make gross spend misleading, especially in India.
From 125 cells to named segments
Three scores of 1 to 5 give 125 cells. Nobody runs 125 campaigns. Map them into about ten named segments driven mostly by R and F, with M used to prioritise inside a segment.
| Segment | Rule (R, F) | Who they are | Primary action |
|---|---|---|---|
| Champions | R 4-5, F 4-5 | Recent, frequent, high spend | Early access, referral ask, reviews, no discounts |
| Loyal | R 3-5, F 3-5 | Steady repeat buyers | Cross-sell, loyalty tier, subscription offer |
| Potential loyalists | R 4-5, F 2-3 | Recent, a few orders | Second-category nudge, membership pitch |
| New | R 5, F 1 | Just made a first order | Onboarding and second-order journey |
| Promising | R 4, F 1 | First order a little while ago | Social proof, replenishment timing, light incentive |
| Need attention | R 3, F 3 | Middling on both | Personalised recommendations, limited-time content |
| About to sleep | R 2-3, F 1-2 | Fading, low frequency | Reminder of value, bestsellers, small offer |
| At risk | R 1-2, F 3-5 | Used to buy often, gone quiet | Win-back series with tested offer |
| Can’t lose them | R 1, F 5, high M | Best customers now lapsing | Personal outreach, service recovery |
| Hibernating | R 1-2, F 1-2 | Low and old | Low-cost seasonal sends, then sunset |
| Lost | R 1, F 1 | One order, long ago | Suppress from paid channels, one last try, then remove |
Segment playbooks
Goal: keep them buying and turn them into a growth channel.
Do:
- Give early access to launches and limited drops
- Ask for reviews and referrals right after a delivered order
- Invite them to a VIP tier or customer advisory group
Avoid: blanket discounts. They would have bought anyway, so a discount is pure margin loss.
Goal: recover customers who used to buy often before they become Lost.
Trigger the journey when a customer moves from Loyal or Potential loyalist into At risk, not on a calendar.
- Message 1: what is new since their last order, no offer
- Message 2: their usual product with a one-tap reorder link
- Message 3: a time-boxed offer, tested against a 10 to 20% holdout
Success metric: share who return to R 3 or better within 60 days, minus the holdout rate.
Goal: get the second order. In most D2C businesses the first-to-second order step is where the biggest share of customers is lost.
- Delivery and usage tips sent when the product arrives, not when it ships
- Replenishment reminder timed to the product's use-up cycle
- One complementary product recommendation based on the first basket
Measure: second-order rate within your typical inter-purchase window.
Goal: spend as little as possible while keeping a door open.
- Include them only in big seasonal moments such as Diwali or year-end sales
- Remove them from paid retargeting audiences to save budget
- After two ignored seasonal sends, move them to a sunset flow and suppress
Sunsetting protects email deliverability and WhatsApp quality ratings for everyone else.
Step-by-step playbook
- Pull one row per customer. Customer ID, last order date, number of orders and net revenue, all inside the lookback window. Exclude cancelled, refused (COD) and fully returned orders.
- Choose the scoring method per dimension. Recency and monetary are continuous, so quintiles work. Frequency is lumpy (most customers have one or two orders), so use fixed thresholds such as 1, 2, 3 to 4, 5 to 9, and 10 or more.
- Score and label. Compute R, F and M scores, then apply the segment rules from the table above. Keep the rules in one shared file so analysts and CRM use the same definitions.
- Size each segment in customers and revenue. You will usually find a small group of Champions and Loyal customers carrying a large share of revenue. That tells you where a 1 point change matters most.
- Assign one owner and one action per segment. Each segment gets a goal metric, a journey and a guardrail (for example, maximum discount depth).
- Automate the refresh. Recompute daily or weekly and sync to your email, push and WhatsApp tools. Trigger journeys on segment changes, especially into At risk and out of New.
- Track migration monthly. Build a matrix of segment last month versus segment this month. The most important cells are New to Potential loyalist (second order) and Loyal to At risk (early churn signal).
- Prove incrementality. Keep a random 10% holdout per segment out of promotional sends for a full cycle. Compare revenue per customer, not open rates.
Building it in SQL
-- One row per customer, 24-month lookback, net of refusals and returns
WITH base AS (
SELECT
customer_id,
DATE_DIFF(CURRENT_DATE(), MAX(order_date), DAY) AS recency_days,
COUNT(DISTINCT order_id) AS orders,
SUM(net_revenue) AS monetary
FROM orders
WHERE order_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 24 MONTH)
AND status NOT IN ('cancelled', 'rto', 'refunded')
GROUP BY customer_id
),
scored AS (
SELECT
*,
6 - NTILE(5) OVER (ORDER BY recency_days ASC) AS r_score, -- most recent = 5
CASE
WHEN orders >= 10 THEN 5
WHEN orders >= 5 THEN 4
WHEN orders >= 3 THEN 3
WHEN orders = 2 THEN 2
ELSE 1
END AS f_score, -- fixed thresholds
NTILE(5) OVER (ORDER BY monetary ASC) AS m_score
FROM base
)
SELECT
*,
CASE
WHEN r_score >= 4 AND f_score >= 4 THEN 'Champions'
WHEN r_score = 1 AND f_score = 5 AND m_score >= 4 THEN 'Cant lose them'
WHEN r_score <= 2 AND f_score >= 3 THEN 'At risk'
WHEN r_score >= 3 AND f_score >= 3 THEN 'Loyal'
WHEN r_score >= 4 AND f_score BETWEEN 2 AND 3 THEN 'Potential loyalists'
WHEN r_score = 5 AND f_score = 1 THEN 'New'
WHEN r_score = 4 AND f_score = 1 THEN 'Promising'
WHEN r_score = 3 AND f_score <= 2 THEN 'About to sleep'
WHEN r_score = 2 AND f_score <= 2 THEN 'Hibernating'
ELSE 'Lost'
END AS segment
FROM scored;
The order of the CASE rules matters: specific segments (Can’t lose them) must be tested before the broad ones that would otherwise catch them. The syntax shown is BigQuery. In Postgres, replace the date functions with CURRENT_DATE - MAX(order_date) and CURRENT_DATE - INTERVAL '24 months'.
Building it in a spreadsheet
With one customer per row (recency days in column B, orders in C, revenue in D, 5,000 customers):
- Recency score:
=6-MAX(1,ROUNDUP(PERCENTRANK.INC($B$2:$B$5001,B2)*5,0)) - Monetary score:
=MAX(1,ROUNDUP(PERCENTRANK.INC($D$2:$D$5001,D2)*5,0)) - Frequency score:
=IF(C2>=10,5,IF(C2>=5,4,IF(C2>=3,3,IF(C2=2,2,1))))
Then a lookup table maps each R and F pair to a segment name. A pivot table on segment gives counts and revenue share.
Worked example
Say a D2C coffee brand has 20,000 customers who ordered in the last 24 months and ₹6 crore of net revenue in that window.
After scoring:
| Segment | Customers | Avg orders | Avg net order value | Revenue | Share |
|---|---|---|---|---|---|
| Champions | 1,600 | 12 | ₹900 | ₹1.73 cr | 29% |
| Loyal | 2,800 | 6 | ₹850 | ₹1.43 cr | 24% |
| At risk | 2,400 | 5 | ₹850 | ₹1.02 cr | 17% |
| All others | 13,200 | 1.6 | ₹860 | ₹1.82 cr | 30% |
The arithmetic for Champions: 1,600 x 12 x ₹900 = ₹1,72,80,000, about ₹1.73 crore, or 29% of revenue from 8% of customers.
Now size the At risk opportunity. These 2,400 customers averaged 5 orders but have gone quiet. Suppose a three-step win-back brings back 15% of them for one order of ₹850, while a 10% holdout shows only 5% would have returned anyway. Incremental return rate = 15% - 5% = 10 points. Incremental orders = 2,400 x 0.90 (the treated share) x 0.10 = 216. Incremental revenue = 216 x ₹850 = ₹1,83,600 from one order each, before counting the repeat orders a recovered regular tends to place.
Compare that with sending the same offer to all 20,000 customers. Champions would redeem it on orders they were already going to place, which is pure margin loss. Segmenting first is what makes the economics work.
B2B SaaS vs D2C: what changes
In SaaS, customers pay on a schedule whether or not they use the product, so purchase recency is useless. Swap in usage.
| Dimension | D2C | B2B SaaS equivalent |
|---|---|---|
| Recency | Days since last order | Days since the account last did the key value action (sent a campaign, ran a report, shipped a build) |
| Frequency | Orders in 12 to 24 months | Active days in the last 28, or weekly active users divided by paid seats |
| Monetary | Net revenue | ARR, or paid seats |
| Extra dimension | Category breadth | Feature breadth: number of core features used |
Segment names change too. “At risk” becomes “high ARR, falling usage”, which goes to customer success with a 60 to 90 day lead on renewal. “Champions” become expansion and case study candidates. “Low ARR, no recent usage” gets automated re-onboarding rather than a human call.
How to measure it
| Metric | Definition | Window |
|---|---|---|
| Segment size and revenue share | Customers in segment, and their net revenue / total net revenue | Lookback window, refreshed monthly |
| Segment migration rate | Customers who moved from segment A to B / customers in A at start | Month over month |
| Second-order rate (New) | New customers who placed a second order / new customers | Within your inter-purchase window |
| At risk recovery rate | At risk customers who returned to R 3 or better / At risk customers at start | 60 days, compared with a holdout |
| Incremental revenue per customer | Revenue per treated customer minus revenue per holdout customer | One full purchase cycle |
Report migration as a matrix, not a list. A healthy programme moves customers up and to the left over time. If At risk grows faster than Loyal for three months in a row, your retention problem is getting worse, regardless of what the total revenue line says.