shopify-admin-rfm-customer-segmentation

SkillCommerce & finance

Read-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.

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

ParameterTypeRequiredDefaultDescription
storestringyesStore domain (e.g., mystore.myshopify.com)
days_backintegerno365Lookback window for order history
segmentsintegerno5Number of quintile buckets per dimension (3 or 5)
min_ordersintegerno1Minimum orders for a customer to be scored
tag_customersbooleannofalseIf true, add RFM segment tag to customer (requires write_customers scope)
formatstringnohumanOutput format: human or json

Safety

ℹ️ Read-only by default. If tag_customers: true, will add tags via customerUpdate mutation — use dry_run: true first.

RFM Segment Definitions

SegmentR ScoreF ScoreM ScoreDescription
Champions555Best customers — recent, frequent, high spend
Loyal Customers3-54-54-5Consistent buyers with strong spend
Potential Loyalists4-52-32-3Recent buyers who could become loyal
New Customers511-2Just made first purchase
Promising41-21-2Recent but low frequency — nurture them
Need Attention333Average across all dimensions — slipping
About to Sleep2-322Below average recency and frequency
At Risk1-24-54-5Were great customers, haven't bought recently
Hibernating1-21-21-3Low on all dimensions — nearly lost
Lost11-21-5Haven't bought in a very long time

Workflow Steps

  1. OPERATION: orders — query Inputs: query: "created_at:>='<NOW - days_back days>'", first: 250, select createdAt, totalPriceSet, customer { id, email, firstName, lastName, numberOfOrders }, pagination cursor Expected output: All orders in window with customer linkage; paginate until complete

  2. Aggregate per customer:

    • Recency = days since last order
    • Frequency = total number of orders in window
    • Monetary = total spend in window
  3. 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])
  4. Map (R, F, M) score combination to named segment using the definitions above

  5. 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

ErrorCauseRecovery
THROTTLEDAPI rate limit exceededWait 2 seconds, retry up to 3 times
Guest ordersOrders without customerSkip — cannot attribute to RFM profile
Single-order customersNew or one-time buyersInclude with F=1; they'll naturally score low on frequency

Best Practices

  • Use days_back: 365 for most stores to capture seasonal buying patterns. Use days_back: 180 for 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-back skill.
  • Export Lost segment to an exclusion list to stop wasting ad spend on them.
  • Cross-reference with customer-cohort-analysis for cohort-level RFM trends over time.
  • Use with customer-spend-tier-tagger to 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