$npx -y skills add 40RTY-ai/shopify-admin-skills --skill shopify-admin-cross-sell-opportunity-finderRead-only: identifies products with high single-purchase rates that could benefit from cross-sell pairing based on category and price affinity.
| 1 | ## Purpose |
| 2 | Finds products that are almost always purchased alone (single-item orders) and identifies potential cross-sell partners based on category affinity, price complementarity, and customer overlap. While `frequently-bought-together` finds existing patterns, this skill finds MISSING patterns — products that SHOULD be cross-sold but aren't. Read-only — no mutations. |
| 3 | |
| 4 | ## Prerequisites |
| 5 | - Authenticated Shopify CLI session: `shopify store auth --store <domain> --scopes read_orders,read_products` |
| 6 | - API scopes: `read_orders`, `read_products` |
| 7 | |
| 8 | ## Parameters |
| 9 | |
| 10 | | Parameter | Type | Required | Default | Description | |
| 11 | |-----------|------|----------|---------|-------------| |
| 12 | | store | string | yes | — | Store domain | |
| 13 | | days_back | integer | no | 180 | Order lookback window | |
| 14 | | solo_threshold | float | no | 70 | % of orders where product is bought alone to flag as "solo" | |
| 15 | | min_orders | integer | no | 10 | Minimum orders for a product to be analyzed | |
| 16 | | format | string | no | human | Output format: `human` or `json` | |
| 17 | |
| 18 | ## Safety |
| 19 | |
| 20 | > ℹ️ Read-only skill — no mutations are executed. Safe to run at any time. |
| 21 | |
| 22 | ## Workflow Steps |
| 23 | |
| 24 | 1. **OPERATION:** `orders` — query |
| 25 | **Inputs:** `query: "created_at:>='<NOW - days_back days>'"`, `first: 250`, select `lineItems { product { id, title, productType, vendor }, quantity, originalTotalSet }`, pagination cursor |
| 26 | **Expected output:** All orders with product data |
| 27 | |
| 28 | 2. For each product, calculate: |
| 29 | - Total orders containing this product |
| 30 | - Solo orders (product is the only item) vs. multi-item orders |
| 31 | - Solo rate = solo_orders / total_orders × 100 |
| 32 | - Average order value when solo vs. when multi-item |
| 33 | |
| 34 | 3. Flag products with solo rate ≥ solo_threshold as "cross-sell candidates" |
| 35 | |
| 36 | 4. **OPERATION:** `products` — query (enrichment) |
| 37 | **Inputs:** Product IDs for solo items and potential partners |
| 38 | **Expected output:** Product type, vendor, price, collections for affinity matching |
| 39 | |
| 40 | 5. For each solo product, suggest cross-sell partners: |
| 41 | - Same vendor, different product type (complementary) |
| 42 | - Same product type, different price tier (good-better-best) |
| 43 | - Products bought by the same customer cohort in separate orders |
| 44 | - Price complementarity: partner price should be 20-50% of main product price (impulse add-on range) |
| 45 | |
| 46 | ## GraphQL Operations |
| 47 | |
| 48 | ```graphql |
| 49 | # orders:query — validated against api_version 2025-01 |
| 50 | query OrdersForCrossSell($query: String!, $after: String) { |
| 51 | orders(first: 250, after: $after, query: $query) { |
| 52 | edges { |
| 53 | node { |
| 54 | id |
| 55 | customer { id } |
| 56 | lineItems(first: 50) { |
| 57 | edges { |
| 58 | node { |
| 59 | product { id title productType vendor } |
| 60 | quantity |
| 61 | originalTotalSet { shopMoney { amount currencyCode } } |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | } |
| 66 | } |
| 67 | pageInfo { hasNextPage endCursor } |
| 68 | } |
| 69 | } |
| 70 | ``` |
| 71 | |
| 72 | ```graphql |
| 73 | # products:query — validated against api_version 2025-01 |
| 74 | query ProductEnrichment($ids: [ID!]!) { |
| 75 | nodes(ids: $ids) { |
| 76 | ... on Product { |
| 77 | id |
| 78 | title |
| 79 | productType |
| 80 | vendor |
| 81 | priceRangeV2 { |
| 82 | minVariantPrice { amount currencyCode } |
| 83 | } |
| 84 | totalInventory |
| 85 | status |
| 86 | } |
| 87 | } |
| 88 | } |
| 89 | ``` |
| 90 | |
| 91 | ## Session Tracking |
| 92 | |
| 93 | **Claude MUST emit the following output at each stage. This is mandatory.** |
| 94 | |
| 95 | **On start**, emit: |
| 96 | ``` |
| 97 | ╔══════════════════════════════════════════════╗ |
| 98 | ║ SKILL: Cross-Sell Opportunity Finder ║ |
| 99 | ║ Store: <store domain> ║ |
| 100 | ║ Started: <YYYY-MM-DD HH:MM UTC> ║ |
| 101 | ╚══════════════════════════════════════════════╝ |
| 102 | ``` |
| 103 | |
| 104 | **After each step**, emit: |
| 105 | ``` |
| 106 | [N/TOTAL] <QUERY|MUTATION> <OperationName> |
| 107 | → Params: <brief summary of key inputs> |
| 108 | → Result: <count or outcome> |
| 109 | ``` |
| 110 | |
| 111 | **On completion**, emit: |
| 112 | |
| 113 | For `format: human` (default): |
| 114 | ``` |
| 115 | ══════════════════════════════════════════════ |
| 116 | CROSS-SELL OPPORTUNITY REPORT (<days_back> days) |
| 117 | Products analyzed: <n> |
| 118 | High solo-rate products: <n> |
| 119 | ───────────────────────────── |
| 120 | TOP CROSS-SELL OPPORTUNITIES: |
| 121 | |
| 122 | "<product A>" (solo rate: <pct>%, <n> orders) |
| 123 | → Suggested partner: "<product B>" (same vendor, complementary type) |
| 124 | → Price fit: $<main> + $<partner> = $<combined> |
| 125 | → Potential AOV lift: +$<amount> per order |
| 126 | |
| 127 | Revenue opportunity: $<total> (if <pct>% of solo orders add partner) |
| 128 | |
| 129 | Output: cross_sell_opportunities_<date>.csv |
| 130 | ══════════════════════════════════════════════ |
| 131 | ``` |
| 132 | |
| 133 | ## Output Format |
| 134 | CSV file `cross_sell_opportunities_<YYYY-MM-DD>.csv` with columns: |
| 135 | `product_id`, `product_title`, `total_orders`, `solo_ord |