How to Scrape Shopify Product Catalogs and Prices in 2026
A practical guide to extracting full product catalogs, variants and pricing from any Shopify store using the public /products.json endpoint — no browser, no API key.
Every Shopify store on the planet exposes its entire public product catalog through a single, undocumented-but-stable JSON endpoint. No login, no API token, no browser automation, no anti-bot wall. If you do competitive intelligence, price tracking, or dropshipping research, this is the cheapest, fastest data source in e-commerce — once you know the endpoint exists and how to traverse it. This guide covers exactly that, plus how to turn the raw JSON into a clean catalog you can diff over time.
The endpoint that makes this trivial
Shopify powers millions of stores on one platform, and that platform ships a consistent public route on every store:
https://store-domain.com/products.json?limit=250&page=1
That’s it. Hit it and you get back a JSON array of products — the same data the storefront renders, structured and paginated. Because it’s a direct JSON fetch, there’s no browser to launch, which is the entire performance story: a headless-browser scraper spends 90% of its compute rendering pages you don’t need. Hitting /products.json with a raw HTTP client is an order of magnitude cheaper and faster.
Two endpoint details matter:
limitcaps at 250 products per page. Above that you paginate withpage=2,page=3, until you get an empty array.- Some stores disable it. A small fraction of merchants block
/products.jsonor proxy it through a custom route. For those, you fall back to the collection or sitemap routes — but the vast majority of Shopify stores leave it wide open.
There’s also a collection-scoped variant — /collections/<handle>/products.json — if you only want one category rather than the whole catalog.
What each product record contains
The payload is rich. Per product you get:
- Identity — product ID,
title,handle(the URL slug),vendor,product_type,tags. - Variants — an array, each with its own variant ID,
title(e.g. “Large / Blue”),price,compare_at_price(the strikethrough price),sku, andavailableflag. - Pricing range — derived min/max across variants, plus currency.
- Media — image URLs and alt text.
- Timestamps —
created_at,updated_at,published_at.
The updated_at field is the secret weapon for incremental scraping: instead of re-pulling the whole catalog every run, you fetch only products updated since your last run, which keeps cost and noise down.
▶ Run the Shopify Competitor Spy — pulls full product catalogs, variants, price ranges, inventory status and images from any Shopify store via direct JSON. No browser, low compute cost, built for bulk store extraction.
Why no-browser matters for cost
This actor’s whole design thesis is no headless browser. Here’s why that’s not just a nice-to-have:
- A browser-based scraper allocates ~1–2 GB of memory per worker and burns CPU rendering React, fonts, and images you’ll never use. A raw HTTP fetch of
/products.jsonneeds a fraction of that. - On Apify, compute is metered. Less memory and less time per request means dramatically lower compute-unit (CU) cost per product — the difference between cents and dollars per thousand products.
- No browser means no headless-Chrome fingerprinting surface, so you rarely need residential proxies for the catalog endpoint. Datacenter IPs work fine for most stores.
The trade-off: you only get what /products.json exposes. It won’t render dynamic “you may also like” widgets or app-injected content. For catalog and pricing intelligence, that’s exactly what you want anyway.
Schema design for downstream use
Flatten the nested variant structure into rows you can diff:
{
"store_domain": "examplebrand.com",
"product_id": 7345123456789,
"title": "Merino Crew Sock",
"handle": "merino-crew-sock",
"vendor": "ExampleBrand",
"product_type": "Socks",
"variant_id": 41234567890123,
"variant_title": "Large / Charcoal",
"sku": "MCS-L-CHR",
"price": "18.00",
"compare_at_price": "24.00",
"currency": "USD",
"available": true,
"image_url": "https://cdn.shopify.com/s/files/1/.../merino-crew.jpg",
"created_at": "2026-01-12T08:00:00Z",
"updated_at": "2026-05-21T14:30:00Z",
"scraped_at": "2026-05-24T12:00:00Z"
}
Choices worth making early:
- Explode to one row per variant. Price and availability live at the variant level, not the product level. Keeping it nested makes price-diffing painful.
- Always store
compare_at_price. The gap betweenpriceandcompare_at_priceis the discount depth — a core competitive signal. - Keep
availableandupdated_at. Together they let you detect both stockouts and price changes between runs. - Stamp
scraped_aton every row. Price tracking is meaningless without knowing when a price was observed.
Typical use cases
- Competitive intelligence — monitor a competitor set’s full catalogs, catch new-product launches the day they go live, watch their discount cadence.
- Price tracking — diff
priceandcompare_at_priceacross daily runs to map promotions and price-elasticity. - Dropshipping research — bulk-scan hundreds of stores in a niche to find winning products, vendors, and price points.
- Market and niche analysis — map an entire vertical’s assortment and pricing to spot gaps.
- Price-comparison engines — feed structured Shopify catalog data into a comparison dashboard.
- AI / RAG pipelines — build a product knowledge base for retrieval-augmented shopping assistants.
The common thread is breadth times freshness: one store scraped once is a curiosity; 200 stores diffed daily is a competitive-intelligence system.
Cost math
Because there’s no browser and no residential proxy needed for most stores, the per-product cost is dominated by the cheap HTTP fetch. This actor prices per result (a “Business Lead” event at well under a cent each). A realistic competitive-intel setup — 50 competitor stores, ~500 products each, daily incremental refresh — is roughly 25,000 product rows on the first full pull, then far fewer per day once you switch to updated_at-incremental mode. That lands in the low tens of dollars per month at full breadth, or inside the free monthly credit for a smaller competitor set.
Building it yourself is doable (it’s a public JSON endpoint), but you’d still own: pagination loop handling, incremental updated_at logic, the fallback path for stores that block /products.json, variant flattening, and a scheduler. None of it is rocket science; all of it is upkeep.
Common pitfalls
- Forgetting the 250 cap.
?limit=1000is silently clamped to 250. If you don’t paginate, you’ll think a 4,000-product store only has 250 items. - Stores that disable the endpoint. A
404or HTML response on/products.jsonmeans the merchant blocked it. Have a sitemap/collection fallback. - Treating
availableas exact inventory. It’s a boolean, not a count. Shopify doesn’t expose stock quantity on the public endpoint. - Price as a string. Shopify returns
priceas a string ("18.00"), not a number. Cast it before you do math. - Currency assumptions. Don’t assume USD. Read the store’s currency; international stores return their own.
- Re-scraping everything. Without
updated_at-incremental logic you’ll re-pull stable catalogs daily and pay for noise.
Wrapping up
The Shopify /products.json endpoint is the rare scraping target that’s both trivially accessible and genuinely valuable. The hard part isn’t access — it’s doing it at breadth, incrementally, across stores that occasionally block you, and keeping the diff clean. If you need a one-off catalog dump, write the fetch loop yourself. If you need a daily competitive-pricing feed across a market, a managed no-browser actor is the cheaper, lower-maintenance route.
▶ Open the Shopify Competitor Spy on Apify — bulk catalog and price extraction via direct JSON, incremental refresh, flat per-variant schema. Pay per product. Start with Apify’s free monthly credit.
Related guides
How to Scrape Avito: Russia's Largest Classifieds (avito.ru)
Scrape Avito.ru listings at scale — title, current and old price, location, category, images and URL. Search by keyword or browse by category and location.
How to Scrape Blocket.se Swedish Classifieds in 2026
Extract used cars, electronics and marketplace items from Blocket.se — Sweden's largest classifieds. Pull prices, images, location, coordinates and seller type via its internal APIs.
How to Scrape Craigslist Listings and Prices in 2026
Learn how to scrape Craigslist listings, prices, images and GPS coordinates across any city and category — no login, no API key — and build market-wide datasets at scale.