$npx -y skills add 40RTY-ai/shopify-admin-skills --skill shopify-admin-checkout-abandonment-reportAggregate abandoned checkout data for a time range, broken down by cart value bucket and hour of day (UTC).
| 1 | ## Purpose |
| 2 | Aggregates abandoned checkout data broken down by cart value bucket and hour of day (UTC). Helps identify when and at what price point customers are most likely to abandon checkout. Scoped to what the `abandonedCheckouts` API provides — device type and geographic location are not available in this API and are not reported. |
| 3 | |
| 4 | ## Prerequisites |
| 5 | - Authenticated Shopify CLI session: `shopify auth login --store <domain>` |
| 6 | - API scopes: `read_checkouts` |
| 7 | |
| 8 | ## Parameters |
| 9 | |
| 10 | | Parameter | Type | Required | Default | Description | |
| 11 | |-----------|------|----------|---------|-------------| |
| 12 | | store | string | yes | — | Store domain (e.g., mystore.myshopify.com) | |
| 13 | | format | string | no | human | Output format: `human` or `json` | |
| 14 | | dry_run | bool | no | false | Preview operations without executing mutations | |
| 15 | | date_range_start | string | yes | — | Start date in ISO 8601 (e.g., `2025-01-01`) | |
| 16 | | date_range_end | string | yes | — | End date in ISO 8601 (e.g., `2025-01-31`) | |
| 17 | | cart_value_buckets | array | no | [0, 25, 50, 100, 250] | Array of thresholds defining cart value bands (e.g., `[0,25,50,100,250]` creates bands: $0–25, $25–50, $50–100, $100–250, $250+) | |
| 18 | |
| 19 | ## Workflow Steps |
| 20 | |
| 21 | 1. **OPERATION:** `abandonedCheckouts` — query |
| 22 | **Inputs:** `first: 250`, `query: "created_at:>='<date_range_start>' created_at:<='<date_range_end>'"`, pagination cursor |
| 23 | **Expected output:** All abandoned checkouts in range with `totalPrice` and `createdAt`; paginate until `hasNextPage: false`; then aggregate in-memory: (1) count by cart value bucket, (2) count by hour of day (UTC, 0–23) |
| 24 | |
| 25 | ## GraphQL Operations |
| 26 | |
| 27 | ```graphql |
| 28 | # abandonedCheckouts:query — validated against api_version 2025-04 |
| 29 | query AbandonedCheckoutsReport($first: Int!, $after: String, $query: String) { |
| 30 | abandonedCheckouts(first: $first, after: $after, query: $query) { |
| 31 | edges { |
| 32 | node { |
| 33 | id |
| 34 | createdAt |
| 35 | totalPriceSet { |
| 36 | shopMoney { |
| 37 | amount |
| 38 | currencyCode |
| 39 | } |
| 40 | } |
| 41 | customer { |
| 42 | defaultEmailAddress { |
| 43 | emailAddress |
| 44 | } |
| 45 | } |
| 46 | lineItems { |
| 47 | edges { |
| 48 | node { |
| 49 | title |
| 50 | quantity |
| 51 | variant { |
| 52 | price |
| 53 | } |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | } |
| 58 | } |
| 59 | pageInfo { |
| 60 | hasNextPage |
| 61 | endCursor |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | ``` |
| 66 | |
| 67 | ## Session Tracking |
| 68 | |
| 69 | **Claude MUST emit the following output at each stage. This is mandatory.** |
| 70 | |
| 71 | **On start**, emit: |
| 72 | ``` |
| 73 | ╔══════════════════════════════════════════════╗ |
| 74 | ║ SKILL: checkout-abandonment-report ║ |
| 75 | ║ Store: <store domain> ║ |
| 76 | ║ Started: <YYYY-MM-DD HH:MM UTC> ║ |
| 77 | ╚══════════════════════════════════════════════╝ |
| 78 | ``` |
| 79 | |
| 80 | **After each step**, emit: |
| 81 | ``` |
| 82 | [N/TOTAL] <QUERY|MUTATION> <OperationName> |
| 83 | → Params: <brief summary of key inputs> |
| 84 | → Result: <count or outcome> |
| 85 | ``` |
| 86 | |
| 87 | **On completion**, emit: |
| 88 | |
| 89 | For `format: human` (default): |
| 90 | ``` |
| 91 | ══════════════════════════════════════════════ |
| 92 | OUTCOME SUMMARY |
| 93 | Total abandoned: <n> |
| 94 | Date range: <start> to <end> |
| 95 | Errors: 0 |
| 96 | Output: none |
| 97 | ══════════════════════════════════════════════ |
| 98 | ``` |
| 99 | |
| 100 | For `format: json`, emit: |
| 101 | ```json |
| 102 | { |
| 103 | "skill": "checkout-abandonment-report", |
| 104 | "store": "<domain>", |
| 105 | "started_at": "<ISO8601>", |
| 106 | "completed_at": "<ISO8601>", |
| 107 | "dry_run": false, |
| 108 | "steps": [ |
| 109 | { "step": 1, "operation": "AbandonedCheckoutsReport", "type": "query", "params_summary": "<date_range_start> to <date_range_end>", "result_summary": "<n> checkouts", "skipped": false } |
| 110 | ], |
| 111 | "outcome": { |
| 112 | "total_abandoned": 0, |
| 113 | "date_range_start": "<date_range_start>", |
| 114 | "date_range_end": "<date_range_end>", |
| 115 | "by_cart_value": [ |
| 116 | { "range": "$0 – $25", "count": 0, "pct": 0.0 } |
| 117 | ], |
| 118 | "by_hour_utc": [ |
| 119 | { "hour": "00:00", "count": 0, "pct": 0.0 } |
| 120 | ], |
| 121 | "errors": 0, |
| 122 | "output_file": null |
| 123 | } |
| 124 | } |
| 125 | ``` |
| 126 | |
| 127 | ## Output Format |
| 128 | |
| 129 | Two tables displayed inline (no CSV): |
| 130 | |
| 131 | **Table 1: Abandonment by Cart Value Bucket** |
| 132 | |
| 133 | | Cart Value Range | Abandoned Checkouts | % of Total | |
| 134 | |-----------------|---------------------|------------| |
| 135 | | $0 – $25 | ... | ... | |
| 136 | | $25 – $50 | ... | ... | |
| 137 | | $50 – $100 | ... | ... | |
| 138 | | $100 – $250 | ... | ... | |
| 139 | | $250+ | ... | ... | |
| 140 | |
| 141 | **Table 2: Abandonment by Hour of Day (UTC)** |
| 142 | |
| 143 | | Hour (UTC) | Abandoned Checkouts | % of Total | |
| 144 | |-----------|---------------------|------------| |
| 145 | | 00:00 | ... | ... | |
| 146 | | 01:00 | ... | ... | |
| 147 | | 02:00 | ... | ... | |
| 148 | | ... | | | |
| 149 | |
| 150 | For `format: json`, `by_cart_value` is an array of `{range, count, pct}` objects; `by_hour_utc` |