RFM segmentation
AI for data and analytics · Facts checked 28 October 2026
RFM segmentation groups customers by three facts from their order history: recency (days since their last purchase), frequency (number of orders) and monetary value (total spend). Each is scored, usually 1 to 5 by quintile, and the three scores combine into a code such as 545 that maps to a named segment like Champions or At risk.
What is RFM segmentation?
RFM comes from direct mail, where catalogue companies had to decide who got the next expensive mailing. Three facts from the order history did most of the work: how recently someone bought, how often, and how much. Arthur Hughes' Strategic Database Marketing (first published 1994) popularised the version most teams still use: score each of the three in quintiles, 1 to 5, and you get 125 cells from 111 to 555.
- Recency: days since the customer's last order, counted back from a fixed analysis date. Fewer days scores higher.
- Frequency: number of orders in the window. More scores higher.
- Monetary: total spend in the window (some teams use average order value). More scores higher.
RFM ranks customers by what they have done. It doesn't forecast what they'll do. Fader, Hardie and Lee's 2005 paper RFM and CLV is the standard bridge between the two: it uses the same three inputs in a probability model to estimate each customer's future value, and shows that customers with quite different RFM histories can be worth the same. If the question is "how much is this customer worth?", that's lifetime value. If the question is "who should get which email?", RFM is usually enough.
How to score RFM with quintiles
Quintile scoring sorts customers on each measure separately and splits them into five equal groups. IBM's SPSS Modeler calls this independent binning: each measure is ranked without regard to the other two. Here bin 5 is the best: most recent, most frequent, highest spend.
A worked example
Ten customers of an online shop, scored on 1 October 2026 over the previous 12 months. With ten customers, each quintile holds two. The figures are invented to show the method.
| Customer | Days since last order | Orders | Spend | R | F | M | Code | Segment |
|---|---|---|---|---|---|---|---|---|
| A | 5 | 12 | £1,840 | 5 | 5 | 5 | 555 | Champions |
| B | 12 | 8 | £960 | 5 | 4 | 4 | 544 | Champions |
| C | 20 | 3 | £410 | 4 | 3 | 3 | 433 | Loyal |
| D | 34 | 6 | £1,120 | 4 | 4 | 4 | 444 | Champions |
| E | 48 | 2 | £150 | 3 | 2 | 2 | 322 | New or recent |
| G | 110 | 1 | £60 | 3 | 1 | 1 | 311 | New or recent |
| H | 160 | 4 | £520 | 2 | 3 | 3 | 233 | At risk |
| F | 200 | 9 | £2,300 | 2 | 5 | 5 | 255 | At risk |
| I | 240 | 1 | £95 | 1 | 1 | 1 | 111 | Lost |
| J | 300 | 2 | £180 | 1 | 2 | 2 | 122 | Lost |
Recency first. Sorted by days since the last order, A and B (5 and 12 days) are the most recent fifth and score 5; I and J score 1. Frequency and monetary are sorted the other way, so F's nine orders and £2,300 put F in the top fifth on both.
Customer F is why people use RFM. On spend alone F is the best customer in the table. On RFM, F is a 255: valuable, and gone quiet for 200 days. That's a different email from the one A should get.
Note what the scores are: ranks within this group of customers at this date. A 5 for recency means "in the most recent fifth", not "bought within a week". Rescore next month and the cut-offs move.
See which orders put each customer in a segment
Connect your warehouse or order export, ask Count in plain English, and open the Reasoning Chain behind every segment: which orders, which refunds, which window.
The named RFM segments
Codes like 255 are hard to act on, so teams group them into named segments. There is no standard list. Names, the number of segments and the score rules all vary by tool and by author, so treat any table of segments, including this one, as a starting point.
The rules used in the example above, applied in this order:
| Segment | Rule | Usual action |
|---|---|---|
| Champions | R ≥ 4 and F ≥ 4 | Early access, referrals, no discounts needed |
| Loyal | R ≥ 3 and F ≥ 3 | Cross-sell, loyalty perks |
| New or recent | R ≥ 3, F ≤ 2 | Second-order nudge |
| At risk | R ≤ 2 and F ≥ 3 | Win-back, personal outreach for high M |
| Needs attention | R = 2, F ≤ 2 | Reminder, light offer |
| Lost | R = 1, F ≤ 2 | Low-cost reactivation, or stop mailing |
For comparison, Klaviyo's RFM report scores each measure 1 to 3 rather than 1 to 5, and uses six groups: Champions, Loyal, Recent, Needs attention, At risk and Inactive, each defined by its own list of score combinations. Its At risk is a customer who hasn't bought recently with a low or medium spending score, which isn't quite the rule above. Same names, different customers. If two teams compare segment sizes, compare the rules first.
RFM in SQL with NTILE
Most warehouses can do this in one query. Here is a short orders table:
| order_id | customer_id | order_date | amount | status |
|---|---|---|---|---|
| 1001 | A | 2026-09-26 | 160.00 | completed |
| 1002 | F | 2026-03-15 | 240.00 | completed |
| 1003 | G | 2026-06-13 | 60.00 | completed |
| 1004 | I | 2026-02-03 | 95.00 | completed |
| 1005 | E | 2026-08-14 | 70.00 | refunded |
The query below is PostgreSQL (subtracting two dates gives days; in BigQuery use DATE_DIFF). It builds one row per customer, scores each measure with NTILE(5), then names the segment.
WITH customers AS (
SELECT
customer_id,
DATE '2026-10-01' - MAX(order_date) AS days_since_last,
COUNT(DISTINCT order_id) AS orders,
SUM(amount) AS spend
FROM orders
WHERE status = 'completed'
AND order_date >= DATE '2025-10-01'
AND order_date < DATE '2026-10-01'
GROUP BY customer_id
),
scored AS (
SELECT
*,
NTILE(5) OVER (ORDER BY days_since_last DESC) AS r,
NTILE(5) OVER (ORDER BY orders) AS f,
NTILE(5) OVER (ORDER BY spend) AS m
FROM customers
)
SELECT
CASE
WHEN r >= 4 AND f >= 4 THEN 'Champions'
WHEN r >= 3 AND f >= 3 THEN 'Loyal'
WHEN r >= 3 THEN 'New or recent'
WHEN f >= 3 THEN 'At risk'
WHEN r = 2 THEN 'Needs attention'
ELSE 'Lost'
END AS segment,
COUNT(*) AS customers,
SUM(spend) AS spend
FROM scored
GROUP BY 1
ORDER BY 2 DESC;
Recency sorts by days descending, so the customers who bought longest ago land in bucket 1 and the most recent in bucket 5. Frequency and monetary sort ascending for the same reason. On the ten customers above it returns Champions 3, Loyal 1, New or recent 2, At risk 2, Lost 2.
NTILE splits rows as evenly as it can. BigQuery's documentation says bucket sizes differ by at most one, with the remainder going to the lowest buckets first. That evenness is exactly the problem with frequency, as the next section explains.
Traps that make RFM scores wrong
The time window. Lifetime data lets a customer who bought weekly in 2019 score 5 on frequency today. A 12-month window fixes that, but it also caps frequency and drops anyone whose last order fell outside it, so they vanish from Lost rather than appearing in it. Pick the window on purpose, fix the analysis date in the query instead of using CURRENT_DATE, and write both in the output.
Returns and refunds. An order returned in full should count towards neither frequency nor spend. Net partial refunds off the amount. Klaviyo's RFM report, for example, only counts orders with a positive value, so fully discounted orders are left out. If refunds sit in a separate table, join them before you aggregate, or a serial returner will look like a Champion.
One-off B2B orders. A single £40,000 wholesale order makes a customer an M of 5 and an F of 1, and drags the monetary cut-offs up for everyone else. Score trade accounts separately, or score at the company level rather than per contact, and look at the top ten spenders by hand before trusting the cut-offs.
Ties in NTILE. In a shop where most customers have bought once, NTILE still makes five equal groups, so identical one-order customers get split across buckets 1, 2 and 3 by whatever order the database happens to return them in. PostgreSQL's documentation only promises that NTILE divides the rows "as equally as possible"; BigQuery's own example shows tied rows landing in different buckets. Run it twice and a customer can change segment without placing an order. Two fixes:
- Use fixed thresholds for frequency: 1, 2, 3 to 4, 5 to 9, 10 or more orders.
- Use
CEIL(5 * CUME_DIST() OVER (ORDER BY orders)). Peers (rows with equal values) always get the sameCUME_DIST, so ties stay together. The buckets come out uneven, which is the honest result.
Duplicate customers. Guest checkouts and changed email addresses split one person into several low scorers. Deduplicate before scoring.
Comparing months. Because quintiles are relative, the share of customers scored 5 stays at roughly a fifth whatever happens. To track whether more customers are lapsing, fix the cut-offs once and reuse them.
Asking Claude to build your RFM segments
Claude writes RFM SQL quickly. Left to itself, it will also pick the window, ignore refunds, use NTILE on a frequency column that is mostly ones and present the segment counts without saying any of that. The fix is to make each of those choices yours, and to make it show the counts at every step. More on that pattern in text-to-SQL and prompts for data analysis.
With Count's MCP server connected, Claude can run the query against your warehouse or spreadsheet itself and show the SQL behind every number. Paste this and fill in the brackets:
Build RFM segments from [schema.orders] in [warehouse].
Read only. Analysis date: [2026-10-01]. Window: the 12 months before it.
1. Before writing SQL, tell me which columns you'll use for customer,
order ID, order date, amount and status, and the grain of the
table (one row per what). Ask me if any is unclear.
2. Exclude cancelled and fully refunded orders, and net partial
refunds off the amount. Report how many orders and how much
revenue each exclusion removed.
3. Show how many customers have 1, 2, 3, 4 and 5+ orders. If more
than 20% share one value, score frequency with
CEIL(5 * CUME_DIST() OVER (ORDER BY orders)) instead of NTILE,
and say so.
4. Score recency, frequency and monetary 1 to 5, with 5 the best.
5. Name segments with exactly these rules, in this order:
[paste your rules]
6. Run it. Show one table: segment, customers, share, total spend,
median days since last order.
7. List the 10 highest spenders with their orders and scores, and
flag any single order over [£ amount].
8. Show every query in full, with the row count after each step.
Step 7 catches the B2B order and the refund you forgot. Step 3 catches the ties. If the segment counts change when you run it twice, step 3 wasn't followed.
In Count, every segment count comes with its Reasoning Chain: the query, the filters and the orders behind it. When the CRM team asks why a customer is At risk, you can show them which orders put them there. For using the segments in your CRM, see AI for CRM data.
Sources
- Hughes, Strategic Database Marketing (McGraw-Hill; first published 1994)
- Fader, Hardie and Lee (2005), RFM and CLV: Using Iso-Value Curves for Customer Base Analysis
- IBM Documentation: RFM Analysis node
- Klaviyo Help Center: Understanding scoring and customer groups in the RFM report
- PostgreSQL Documentation: Window functions
- Google Cloud: BigQuery numbering functions (NTILE)
