Claude-code-plugins-plus shopify-rate-limits
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/shopify-pack/skills/shopify-rate-limits" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-shopify-rate-limits && rm -rf "$T"
plugins/saas-packs/shopify-pack/skills/shopify-rate-limits/SKILL.mdShopify Rate Limits
Overview
Shopify uses two distinct rate limiting systems: leaky bucket for REST and calculated query cost for GraphQL. This skill covers both with real header values and response shapes.
Prerequisites
- Understanding of Shopify's REST and GraphQL Admin APIs
- Familiarity with the
library@shopify/shopify-api
Instructions
Step 1: Understand the Two Rate Limit Systems
REST Admin API -- Leaky Bucket:
| Plan | Bucket Size | Leak Rate |
|---|---|---|
| Standard | 40 requests | 2/second |
| Shopify Plus | 80 requests | 4/second |
The
X-Shopify-Shop-Api-Call-Limit header shows your bucket state (e.g., 32/40 means 32 of 40 slots used). When full, you get HTTP 429 with Retry-After header.
GraphQL Admin API -- Calculated Query Cost:
| Plan | Max Available | Restore Rate |
|---|---|---|
| Standard | 1,000 points | 50 points/second |
| Shopify Plus | 2,000 points | 100 points/second |
Every GraphQL response includes cost info in
extensions.cost with requestedQueryCost (worst-case estimate), actualQueryCost (real cost, often much lower), and throttleStatus (available points and restore rate). When currentlyAvailable drops to 0, you get THROTTLED.
Step 2: Implement GraphQL Cost-Aware Throttling
Client-side rate limiter that tracks the query cost bucket and pre-emptively waits before sending requests that would be throttled. Updates available points from each response's
throttleStatus.
See Cost-Aware Rate Limiter for the complete
ShopifyRateLimiter class.
Step 3: Implement Retry with Backoff for 429s
Generic retry wrapper handling both REST 429 responses and GraphQL THROTTLED errors. Uses
Retry-After header when available, otherwise exponential backoff with jitter (max 30s).
See Retry with Backoff for the complete implementation.
Step 4: Reduce Query Cost
Prune unused fields and lower
first: page sizes to reduce requestedQueryCost. A query dropping from first: 250 to first: 50 with fewer nested fields can go from ~5,500 to ~112 cost.
See Query Cost Reduction for before/after examples and the debug curl command.
Output
- Rate limit-aware client that prevents 429 errors
- Retry logic with proper backoff for both REST and GraphQL
- Optimized queries with lower calculated cost
- Debug headers for cost analysis
Error Handling
| Scenario | REST Indicator | GraphQL Indicator |
|---|---|---|
| Approaching limit | | |
| At limit | HTTP 429 + | |
| Recovering | Wait for seconds | Wait for to refill |
Examples
Queue-Based Bulk Operations
For large data exports, use Shopify's bulk query API which bypasses rate limits entirely:
import PQueue from "p-queue"; const BULK_QUERY = ` mutation bulkOperationRunQuery($query: String!) { bulkOperationRunQuery(query: $query) { bulkOperation { id status url } userErrors { field message } } } `; await client.request(BULK_QUERY, { variables: { query: `{ products { edges { node { id title variants { edges { node { id sku price } } } } } } }`, }, });