Shopify Product Scraper — Catalog, Variants, Prices & Discounts
Pricing
from $10.00 / 1,000 products
Shopify Product Scraper — Catalog, Variants, Prices & Discounts
Export the full product catalog of any Shopify store as a clean, spreadsheet-ready table. Variants, prices, compare-at prices, calculated discount %, stock status, SKUs and images.
Pricing
from $10.00 / 1,000 products
Rating
0.0
(0)
Developer
tidyfeed
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Paste a store address. Get its entire catalog as a spreadsheet-ready table.
Every product, every variant, with prices as real numbers, a calculated discount %, stock status, SKUs and images. Add several stores to compare competitors side by side in one run.
No API key. No login. No Shopify partner account. No proxies.
The difference, on a real product
Shopify publishes its product feed in a shape that is awkward to use. Here is what a live Allbirds variant looks like in the raw feed:
{"options": [{ "name": "Size", "position": 1 }], ← name lives up here"variants": [{"option1": "10.5", ← value lives down here"price": "91.00", ← a string"compare_at_price": "130.00" ← another string}]}
Three problems: the option name and its value are in different objects, prices are text rather than numbers, and there is no discount figure anywhere.
Here is the same variant as this actor returns it:
| option1Name | option1Value | price | compareAtPrice | discountPercent | onSale | available |
|---|---|---|---|---|---|---|
| Size | 10.5 | 91 | 130 | 30 | true | true |
Paste that into a spreadsheet and it sorts, filters and sums immediately. No formulas, no lookup table, no cleanup pass.
What you get
One row per variant, so every size and colour carries its own price and stock flag.
| Column | Example |
|---|---|
storeDomain | allbirds.com |
productTitle | Women's Strider - Rugged Beige |
option1Name / option1Value | Size / 10.5 |
option2Name / option2Value | Colour / Navy — blank when a product has one option |
sku | A11848W105 |
price | 91 |
compareAtPrice | 130 |
discountPercent / onSale | 30 / true |
available | true |
vendor, productType | Allbirds, Shoes |
tags | the store's own tags, comma-joined |
productUrl, imageUrl, imageCount | direct links |
publishedAt, createdAt, updatedAt | ISO timestamps |
Prefer one row per product? Switch Row format and you get a price range, variant count and combined SKU list instead.
What it costs
One charge per product returned. Every variant of that product is included at no extra cost.
That is the same billing unit the rest of this category uses, so the price comparison is direct — the difference is what arrives for the money.
| Your run | You pay |
|---|---|
| A 200-product store | $2.01 |
| A 1,000-product catalog | $10.01 |
| Three competitors at 500 products each | $15.01 |
Products your filters exclude are not billed. Set Minimum discount % to 50, point it at a 250-product catalog, and if 87 products qualify you are charged for 87 — not 250.
It follows headless stores to their real shop
A growing number of brands run a custom front end — Next.js, Hydrogen, a bespoke storefront — on their own domain. Ask brand.com/products.json and you get a web page instead of a feed, which is where most scrapers stop and report "not a Shopify store".
These stores still name their Shopify shop in their own markup. This actor reads that address and pulls the catalog from there.
kotn.com → custom front end → reads kotn-ss15.myshopify.com → 250 productsmejuri.com → custom front end → reads mejuri-us.myshopify.com → 250 products
Both of those return nothing on the brand domain. Both come back with a full catalog here.
Typical uses
- Competitor price monitoring — schedule a daily run across several stores and watch prices move.
- Sale tracking — set Minimum discount % to 20 and see only what a competitor has actually marked down.
- Catalog migration or audit — pull an entire catalog into a spreadsheet before a replatform.
- Assortment research — compare how two brands price the same product type.
- Dropshipping and sourcing — export a supplier's catalog with SKUs and stock.
- Feeding an AI agent — callable over the API and through MCP, so Claude, Cursor and other assistants can pull live catalog data mid-task.
Input
| Field | What it does |
|---|---|
| Shopify store URLs | One or more addresses. A bare domain, a homepage, a product page or a .myshopify.com address all work. |
| Max products per store | Stops after N products per store. Default 1000. |
| Row format | One row per variant (default), or one row per product with a price range. |
| Include product description | Adds the description as plain text with the HTML stripped out. Off by default. |
| Skip sold-out items | Keeps only what is currently in stock. |
| Minimum discount % | Keeps only items discounted by at least this much. |
{"storeUrls": ["https://gymshark.com", "allbirds.com"],"maxProductsPerStore": 1000,"outputMode": "variant","onlyAvailable": true,"minDiscountPercent": 20}
That run returns every in-stock item discounted 20% or more, across both stores.
How it works
Shopify serves a public product feed at /products.json on every storefront. This actor reads that feed, walks it 250 products at a time, and reshapes the result into a flat table.
Because it uses the store's own public feed:
- it is fast — a 1,000-product catalog finishes in well under a minute,
- it needs no proxies — nothing to configure, nothing extra to pay for,
- it does not break when a theme changes — there is no HTML parsing involved.
Runs are resilient across stores: if one address fails, the others carry on and the run still succeeds, with a per-store line saying exactly what happened and why.
Honest limits
Worth knowing before you run it:
- Password-protected and pre-launch stores return nothing. There is no public feed to read.
- A handful of stores disable the feed. Rare, but it happens; the run reports which stores came back empty and why.
- A few brand domains sit behind bot protection that challenges every request. The run reports those instead of failing, and the store's
.myshopify.comaddress usually works in their place. - Currency is not published in the feed. Prices are in the store's own default currency.
- Inventory counts are not published either — Shopify exposes an in-stock/out-of-stock flag, not a quantity.
- Non-Shopify sites are detected and skipped with a clear message rather than a failed run.
Output example
{"storeDomain": "allbirds.com","productTitle": "Women's Strider - Rugged Beige (Stony Cream Sole)","handle": "womens-strider-rugged-beige","productUrl": "https://allbirds.com/products/womens-strider-rugged-beige","vendor": "Allbirds","productType": "Shoes","sku": "A11848W105","option1Name": "Size","option1Value": "10.5","price": 91,"compareAtPrice": 130,"discountPercent": 30,"onSale": true,"available": true,"imageUrl": "https://cdn.shopify.com/s/files/1/1104/4168/files/A11847…jpg","imageCount": 5,"updatedAt": "2026-08-21T04:54:55-07:00"}
Export as CSV, Excel, JSON or XML, or pull it straight from the API.
Scheduling
Prices change. Set a schedule to run this daily or weekly, and each run stores a dated snapshot you can compare — that is all a price-monitoring pipeline really needs.
Legal
This actor reads only data that a Shopify store publishes publicly, at an address the store itself serves to anyone. It collects no personal data, requires no login, and bypasses no access control. You remain responsible for how you use the exported data.
Questions, or a store that behaves oddly? Open an issue on the actor — issues are read and answered.