shopify-admin-rfm-customer-segmentation
SkillCommerce & financeRead-only: scores every customer on Recency, Frequency, and Monetary value to segment them into actionable groups (Champions, Loyal, At-Risk, Lost).
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the shopify-admin-rfm-customer-segmentation skill
What this skill tells your AI
The instructions your AI receives, as published by 40rty-ai/shopify-admin-skills in skills/customer-ops/shopify-admin-rfm-customer-segmentation/SKILL.md and read by ahel’s review.
Purpose
Performs full RFM (Recency, Frequency, Monetary) analysis across the entire customer base. Each customer is scored 1-5 on three dimensions — how recently they purchased, how often they purchase, and how much they spend — then classified into actionable segments: Champions, Loyal Customers, Potential Loyalists, At-Risk, Hibernating, and Lost. Read-only — no mutations.
Prerequisites
- Authenticated Shopify CLI session:
shopify store auth --store <domain> --scopes read_orders,read_customers - API scopes:
read_orders,read_customers
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| store | string | yes | — | Store domain (e.g., mystore.myshopify.com) |
| days_back | integer | no | 365 | Lookback window for order history |
| segments | integer | no | 5 | Number of quintile buckets per dimension (3 or 5) |
| min_orders | integer | no | 1 | Minimum orders for a customer to be scored |
| tag_customers | boolean | no | false | If true, add RFM segment tag to customer (requires write_customers scope) |
| format | string | no | human | Output format: human or json |
Safety
ℹ️ Read-only by default. If
tag_customers: true, will add tags via customerUpdate mutation — usedry_run: truefirst.
RFM Segment Definitions
| Segment | R Score | F Score | M Score | Description |
|---|---|---|---|---|
| Champions | 5 | 5 | 5 | Best customers — recent, frequent, high spend |
| Loyal Customers | 3-5 | 4-5 | 4-5 | Consistent buyers with strong spend |
| Potential Loyalists | 4-5 | 2-3 | 2-3 | Recent buyers who could become loyal |
| New Customers | 5 | 1 | 1-2 | Just made first purchase |
| Promising | 4 | 1-2 | 1-2 | Recent but low frequency — nurture them |
| Need Attention | 3 | 3 | 3 | Average across all dimensions — slipping |
| About to Sleep | 2-3 | 2 | 2 | Below average recency and frequency |
| At Risk | 1-2 | 4-5 | 4-5 | Were great customers, haven't bought recently |
| Hibernating | 1-2 | 1-2 | 1-3 | Low on all dimensions — nearly lost |
| Lost | 1 | 1-2 | 1-5 | Haven't bought in a very long time |
Workflow Steps
-
OPERATION:
orders— query Inputs:query: "created_at:>='<NOW - days_back days>'",first: 250, selectcreatedAt,totalPriceSet,customer { id, email, firstName, lastName, numberOfOrders }, pagination cursor Expected output: All orders in window with customer linkage; paginate until complete -
Aggregate per customer:
- Recency = days since last order
- Frequency = total number of orders in window
- Monetary = total spend in window
-
Score each dimension 1-5 using quintile bucketing:
- Sort all customers by each metric
- Divide into N equal-sized groups (quintiles)
- Assign scores (5 = best for recency [most recent], frequency [most frequent], monetary [highest spend])
-
Map (R, F, M) score combination to named segment using the definitions above
-
OPERATION:
customers— query (enrichment) Inputs: Customer IDs from each segment for contact details Expected output: Email, name, tags for top customers in each segment
GraphQL Operations
# orders:query — validated against api_version 2025-01
query OrdersForRFM($query: String!, $after: String) {
orders(first: 250, after: $after, query: $query) {
edges {
node {
id
createdAt
totalPriceSet { shopMoney { amount currencyCode } }
customer {
id
email
firstName
lastName
numberOfOrders
}
}
}
pageInfo { hasNextPage endCursor }
}
}
# customers:query — validated against api_version 2025-01
query CustomerDetails($query: String, $after: String) {
customers(first: 250, after: $after, query: $query) {
edges {
node {
id
email
firstName
lastName
numberOfOrders
totalSpentV2 { amount currencyCode }
tags
createdAt
}
}
pageInfo { hasNextPage endCursor }
}
}
Session Tracking
Claude MUST emit the following output at each stage. This is mandatory.
On start, emit:
╔══════════════════════════════════════════════╗
║ SKILL: RFM Customer Segmentation ║
║ Store: <store domain> ║
║ Started: <YYYY-MM-DD HH:MM UTC> ║
╚══════════════════════════════════════════════╝
After each step, emit:
[N/TOTAL] <QUERY|MUTATION> <OperationName>
→ Params: <brief summary of key inputs>
→ Result: <count or outcome>
On completion, emit:
For format: human (default):
══════════════════════════════════════════════
RFM SEGMENTATION REPORT (<days_back> days)
Customers scored: <n>
─────────────────────────────
Champions: <n> (<pct>%) Avg spend: $<n>
Loyal Customers: <n> (<pct>%) Avg spend: $<n>
Potential Loyalists: <n> (<pct>%) Avg spend: $<n>
At Risk: <n> (<pct>%) Avg spend: $<n>
Hibernating: <n> (<pct>%) Avg spend: $<n>
Lost: <n> (<pct>%) Avg spend: $<n>
Top Champions:
<name> (<email>) R:<n> F:<n> M:<n> Spend: $<n>
Top At-Risk (win-back candidates):
<name> (<email>) Last order: <date> Lifetime: $<n>
Output: rfm_segments_<date>.csv
══════════════════════════════════════════════
For format: json, emit:
{
"skill": "rfm-customer-segmentation",
"store": "<domain>",
"period_days": 365,
"customers_scored": 0,
"segments": {
"champions": { "count": 0, "pct": 0, "avg_spend": 0 },
"loyal": { "count": 0, "pct": 0, "avg_spend": 0 },
"at_risk": { "count": 0, "pct": 0, "avg_spend": 0 },
"lost": { "count": 0, "pct": 0, "avg_spend": 0 }
},
"output_file": "rfm_segments_<date>.csv"
}
Output Format
CSV file rfm_segments_<YYYY-MM-DD>.csv with columns:
customer_id, email, first_name, last_name, recency_days, frequency, monetary, r_score, f_score, m_score, rfm_segment
Error Handling
| Error | Cause | Recovery |
|---|---|---|
THROTTLED | API rate limit exceeded | Wait 2 seconds, retry up to 3 times |
| Guest orders | Orders without customer | Skip — cannot attribute to RFM profile |
| Single-order customers | New or one-time buyers | Include with F=1; they'll naturally score low on frequency |
Best Practices
- Use
days_back: 365for most stores to capture seasonal buying patterns. Usedays_back: 180for fast-fashion or consumables. - Champions and Loyal segments are ideal targets for exclusive offers and early access campaigns.
- At-Risk customers should receive win-back campaigns immediately — use with
customer-win-backskill. - Export Lost segment to an exclusion list to stop wasting ad spend on them.
- Cross-reference with
customer-cohort-analysisfor cohort-level RFM trends over time. - Use with
customer-spend-tier-taggerto auto-tag customers based on RFM segment.
Signals
- GitHub stars
- 187
- Forks
- 18
- Last commit
- Aug 2026
ahel review
S4info
community integration — published by 40rty-ai, not shopify
Automated review, not a security audit. Ruleset v1.
Advanced
- Catalog kind
- skill
- Gateway key
shopify-admin-rfm-customer-segmentation- Source
- github.com/40rty-ai/shopify-admin-skills