Shopify Store API & Scraper
The Shopify Store API returns products, variants, prices and collections from any public Shopify store as clean JSON.
🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.
The primary products endpoint returns each product's id, title, handle, vendor, type, tags, description, options and variants (price, SKU, availability, compare-at price) — a store's full catalog. You can also pull a single product, collections and their products, run a search, get recommendations and read store_info. It is built for competitor-catalog monitoring, price tracking and dropshipping tools that need Shopify store data without a scraper. One ReefAPI key, one shared credit pool, the standard envelope.
Addressing a store, and the types you actually get back
Two things trip people up here. The first is which domain to send, because the obvious answer is the wrong one. The second is that Shopify's own public JSON returns prices as quoted strings and this API does not. Everything below was measured against allbirds.com in one session.
| Field | Type as returned | Measured value |
|---|---|---|
| store (input) | The public storefront domain or URL | allbirds.com works; allbirds.myshopify.com returned TARGET_BLOCKED |
| product.id, variant.id, collection.id | A string of digits, not a number | "7218356060240", "41334293889104", "263506919504" |
| variant.price, price_min, price_max | JSON number, parsed from Shopify's string | 130.0, not the "130.00" the raw storefront JSON serves |
| product.currency | The store's own currency, on the product and on every variant | USD on two US stores, AUD on an Australian one, GBP on a British one - filled from the storefront, never guessed from the domain |
| variant.compare_at_price | null when the variant is not discounted | null, alongside on_sale false and discount_percent 0.0 |
| variant.inventory | Object of {quantity, management, policy, available} | {0, "shopify", "deny", false} on a sold-out size |
| published_at, updated_at | ISO 8601 with the store's local offset, not Z | "2026-06-16T11:02:10-07:00" |
| limit | Clamped at 250, never rejected | limit=400 returned meta.limit 250 and 250 records |
meta.pagination gives you {page, has_more} and no total, so page until has_more is false or set max_items and let it walk for you. The one place a total does exist is the collection action, which returned products_count 960 for the "mens" collection.
Real request and response JSON
Captured from the indexed primary action, products, on .
{
"method": "POST",
"url": "https://api.reefapi.com/shopify/v1/products",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"store": "allbirds.com",
"limit": 5
}
}{
"ok": true,
"meta": {
"api": "shopify",
"endpoint": "products",
"mode": "live",
"latency_ms": 739.4,
"record_count": 5,
"bytes": 37799,
"cache_hit": false,
"stop_reason": "limit_reached",
"store": "https://allbirds.com",
"page": 1,
"limit": 5,
"has_more": true,
"filters_applied": [],
"pagination": {
"page": 1,
"has_more": true
}
},
"data": {
"__trimmed": "response capped for page display"
}
}What the Shopify Store API does
| Action | Description | Concrete use case | Key params |
|---|---|---|---|
| products | Paginated product catalog from any public Shopify store: title, vendor, variants, prices, inventory status, tags, and images. | Pricing teams call products to get paginated product catalog from any public Shopify store. | store, page, limit, max_items, vendor, ... |
| product | Full detail for a single Shopify product by its handle (URL slug) or product page URL: title, vendor, variants, prices, images, and inventory. | Marketplace operators call product to get full detail for a single Shopify product by its handle (URL slug) or product page URL. | store, handle |
| collections | Paginated list of public collections from a Shopify store: collection id, title, handle, description, and cover image. | Catalog enrichment teams call collections to get paginated list of public collections from a Shopify store. | store, page, limit, max_items |
| collection_products | Paginated products within a specific Shopify collection — same product shape as the products action, filterable and sortable. | Retail analysts call collection_products to get paginated products within a specific Shopify collection. | store, handle, page, limit, max_items, ... |
| search | Predictive search across a Shopify store: matching products (title, price, variants, image) plus optional collection, page, and autocomplete query suggestions. | Pricing teams call search to get predictive search across a Shopify store. | store, query, limit, page, max_items, ... |
| recommendations | Related or complementary products that a Shopify store recommends for a given product — the store's own 'you may also like' / 'goes well with' set, same rich product shape. | Marketplace operators call recommendations to get related or complementary products that a Shopify store recommends for a given product. | store, handle, intent, limit |
| collection | Metadata for a single Shopify collection by handle: title, description, cover image, published/updated dates, and product count. | Catalog enrichment teams call collection to get metadata for a single Shopify collection by handle. | store, handle |
| pages | Content pages published on a Shopify store (About, FAQ, Shipping, size guides, etc.): title, handle, URL, and HTML/plain-text body. | Retail analysts call pages to get content pages published on a Shopify store (About, FAQ, Shipping, size guides, etc.). | store, page, limit, max_items |
| store_info | Rich profile for a Shopify store: name, currency, country/city, product & collection counts, accepted card brands, social links, myshopify domain, and platform confirmation. | Pricing teams call store_info to get rich profile for a Shopify store. | store |
Call products from your stack
curl -X POST https://api.reefapi.com/shopify/v1/products \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"store":"allbirds.com","limit":5}'import requests
r = requests.post(
"https://api.reefapi.com/shopify/v1/products",
headers={"x-api-key": REEF_KEY},
json={
"store": "allbirds.com",
"limit": 5
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/shopify/v1/products", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"store": "allbirds.com",
"limit": 5
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.shopify.products with {"store":"allbirds.com","limit":5}.Who uses this API and why
- Price-monitoring tools call products to track a competitor Shopify store's prices and stock across variants.
- Dropshipping and catalog tools use collection_products to mirror a store's product structure.
- Market researchers pull store_info and products to profile a brand's full Shopify catalog.
Questions developers ask before integrating
Should I pass the myshopify.com domain or the store's own domain?
The store's own domain. A live products call on allbirds.com succeeded and reported meta.store "https://allbirds.com", while the identical call on allbirds.myshopify.com failed with TARGET_BLOCKED. Shopify's admin-canonical myshopify hostname is not the surface the public JSON is served from once a custom domain is attached. Send the domain a customer would type, with or without the scheme.
Is price a string, the way Shopify's own products.json returns it?
No. Shopify's public endpoint serializes prices as quoted decimal strings, and this API parses them into JSON numbers before returning them. A measured Allbirds variant came back as "price": 130.0, and price_min and price_max on the parent product are numbers too. You can do arithmetic on them directly, and the currency travels beside them on the same row.
What currency are the prices in, and can I trust it across stores?
Each row states it. currency is filled on the product and on every variant, taken from what the storefront itself declares rather than inferred from the domain, so it is the store's real trading currency: two US stores returned USD on 40 of 40 products and all 322 variants between them, an Australian store returned AUD and a British one GBP. It is filled on the store's own predictive search too. If the storefront cannot be asked, the field stays null rather than being guessed - so a null means unknown, never a default.
Why do search results come back with an empty variants array?
Because search runs against Shopify's predictive-search endpoint, which returns a summary row rather than the full product record. A measured search for "wool runner" on allbirds.com returned the product with price_min, price_max, available, featured_image and url populated but variants length 0, while the product action on the identical handle returned all seven variants. products, collection_products and recommendations all carry full variants; only search does not. Use search to find handles, then fetch by handle.
Why is inventory_quantity null in a product listing but a real number for the same variant elsewhere?
The listing endpoint and the single-product endpoint expose different amounts of detail, and that shows through. Variant 41334293889104 was fetched both ways at the same moment: through the product action it returned inventory_quantity 0, inventory_management "shopify", inventory_policy "deny", weight 2.0264 and a barcode; through the products listing the same variant returned null for all five. price, sku, grams and available were identical on both paths. If you need stock numbers, weights or barcodes, fetch the product by handle.
I set only_on_sale and got zero products from a store that runs promotions. Why?
Because vendor, tag, price, sale and stock filters are applied after the fetch, over whatever pages were actually pulled. A measured only_on_sale call on allbirds.com returned 0 products with meta.filters_applied ["only_on_sale"] and stop_reason "cap_reached", meaning nothing on the pages it walked had a discounted variant. Set max_items high enough for the walk to reach the discounted products before concluding the store has no sales.
What happens on a store that is not Shopify, or that turned the public JSON off?
You get a clear NOT_FOUND rather than an empty list. A measured products call on nike.com returned ok:false with the message "https://nike.com has disabled Shopify public JSON for products". That distinction is worth handling: ok:true with zero products means the store is reachable and genuinely has nothing matching, while NOT_FOUND means the endpoint is closed to you.
How do the collections and recommendations actions relate to products?
collections lists every public collection with its handle, which is what collection_products and collection take. Be ready for internal ones: the first page on Allbirds included a collection titled "$109 Tree Dashers for Outlet Discount Code" and one titled just "98". recommendations takes a product handle, resolves it to a product_id reported in meta, and returns the store's own related set - for a men's Wool Runner it came back with three women's Wool Runners, because that is what the store recommends, not something the API chose.
What is the Shopify Store API?
Shopify Store API is a ReefAPI endpoint group for shopify store It returns live JSON through POST requests under /shopify/v1.
Is the Shopify Store API free to try?
Yes. ReefAPI starts with 1,000 free credits, no card required. Shopify Store calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Shopify Store login or account?
No login to Shopify Store is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Shopify Store data?
The page example is captured from a live products call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Shopify Store API use?
Shopify Store actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Shopify Store from an AI assistant or MCP client?
Yes. Connect ReefAPI once through MCP and your assistant can call shopify actions with the same key, credit pool and JSON envelope used by normal REST requests.