Shopify Product Scraper avatar

Shopify Product Scraper

Pricing

from $0.79 / 1,000 products

Go to Apify Store
Shopify Product Scraper

Shopify Product Scraper

Export any Shopify store's full catalogue to CSV, Excel or JSON: variants, SKUs, prices, sale prices, stock and images. Opens stores that answer 403, 404 or 429 to other scrapers. From $0.79 per 1,000 products. No account, no API key.

Pricing

from $0.79 / 1,000 products

Rating

0.0

(0)

Developer

Stable

Stable

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Share

Unofficial. This Actor is not affiliated with, endorsed by or sponsored by Shopify. It reads only publicly available pages, does not log in and does not bypass any access control. All product names and trademarks belong to their respective owners.

Every product from any Shopify store — including the ones that refuse

Paste store domains. Get their full catalogues as CSV, Excel or JSON: variants, SKUs, prices, sale prices, stock, images and the exact time each product last changed. No account, no API key, no browser.

About four Shopify stores in ten answer a scraper with 403, 404 or 429. This one opens them anyway, and it does it without a proxy setting or anything for you to configure.

Measured on 27 August 2026 over sixteen well-known stores: fifteen opened. Four of those only through the second route — 94% against the 69% the ordinary route gives on its own.

One row, from a real run

Taken from mejuri.com on 27 August. That store refused the ordinary route and came back through the second one — resolvedVia says which. Trimmed only in the variant list, from 26 down to one.

{
"recordType": "product",
"storeDomain": "mejuri.com",
"storeHandle": "mejuri-us",
"resolvedVia": "origin-host",
"productId": 10385306419384,
"title": "Interconnected Initial Pavé Diamond Charm",
"handle": "interconnected-diamond-letter-charm",
"productUrl": "https://mejuri.com/products/interconnected-diamond-letter-charm",
"vendor": "Mejuri",
"productType": "Charm",
"tags": ["Interconnected: 14k Pave", "promo eligible"],
"publishedAt": "2026-08-24T00:19:19-04:00",
"createdAt": "2026-04-28T10:19:59-04:00",
"updatedAt": "2026-08-27T04:07:51-04:00",
"priceMin": 248,
"priceMax": 248,
"onSale": false,
"available": true,
"variantsTotal": 26,
"variantsAvailable": 23,
"variants": [
{
"variantId": 53415571783864,
"title": "14k Yellow Gold / Lab Grown Diamond / D",
"sku": "p538750114",
"price": 248,
"compareAtPrice": null,
"onSale": false,
"available": true,
"grams": 1,
"options": ["14k Yellow Gold", "Lab Grown Diamond", "D"]
}
],
"options": [
{ "name": "Material", "values": ["14k Yellow Gold"] },
{ "name": "Stone", "values": ["Lab Grown Diamond"] },
{ "name": "Letter", "values": ["A", "B", "C", "D", "E", "F", "G"] }
],
"imageCount": 4,
"featuredImage": "https://cdn.shopify.com/s/files/1/0631/8568/2616/files/0_Interconnected_Diamond.jpg",
"scrapedAt": "2026-08-27T12:07:44Z"
}

Fields

27 per product. 9 more on every variant. Counted, not estimated — the list below is the whole of it.

where it came fromrecordType, storeDomain, storeHandle, resolvedVia
the productproductId, title, handle, productUrl, vendor, productType, tags, description
datespublishedAt, createdAt, updatedAt
moneypriceMin, priceMax, onSale
stockavailable, variantsTotal, variantsAvailable
every variantvariantsvariantId, title, sku, price, compareAtPrice, onSale, available, grams, options
optionsoptions — each option name with all of its values
picturesimageCount, featuredImage, images
when it was readscrapedAt

Every row names its own store, so a run over fifty domains needs no join.

And one status row per store

{ "recordType": "store", "storeDomain": "bombas.com", "storeHandle": null,
"resolvedVia": null, "status": "refused",
"detail": "bombas.com refused the catalogue and its own home page",
"currency": null, "productsReturned": 0, "pagesFetched": 0 }

A store that could not be read is named, with the reason. It is never silently missing from the output, and it is never charged for.

Why some stores refuse, and what happens then

Shopify publishes a store's catalogue at a documented address on the store's own domain. Plenty of shops close that address — the answer is 403, 404 or 429 — and for most tools that is the end of the story.

Every Shopify shop also has a second, internal address, and it is usually still open. The catch is that it is not the brand name: gymshark.com lives at gymsharkusa, hiutdenim.co.uk at hiut, mejuri.com at mejuri-us. Four of six are not guessable at all.

This actor reads the store's own front page, finds the internal name there, and fetches the catalogue from it. That costs one extra request, and only for the stores that needed it — resolvedVia tells you which ones those were.

The order is cheapest-first, so a store that answers normally costs one request:

  1. the catalogue on the store's own domain
  2. a second catalogue path on the same domain
  3. the front page, to read the internal name
  4. the catalogue on the internal address

Filters

Applied before a row is stored, so a product removed by a filter is never charged for.

onlyAvailablein stock only
onlyOnSaleonly products marked down
minPrice, maxPricea price band
productTypes, vendorsby type or brand
titleContainsa word in the title
updatedSinceonly what changed since a date
includeVariants, includeImages, includeDescriptionleave out what you do not need

updatedSince is the one that pays for itself. Give it the date of your last run and a daily check of a shop that changes twenty products costs twenty rows, not the whole catalogue.

What it costs

Pay per event, and there is one paid event: a stored product.

GOLD per 1,000
Product$0.79

The status rows are free. Filtered-out products are free. A store that could not be read is free.

  • A 250-product catalogue: $0.20.
  • A 2,400-product catalogue: $1.90.
  • Apify's $5 of monthly free credit: about 5,000 products.

A single store's catalogue takes one or two requests and finishes in under twenty seconds. Five stores at once, one of them needing the second route, took 23 seconds in testing.

Limits

Stated plainly, because these are properties of what Shopify shows the public and no scraper talks them away.

  • Some stores stay shut. The second route opens most refusals, not all. One of sixteen stayed closed in testing, and it is named in the output.
  • Refusals move. A shop that answers today may refuse next week, and the reverse — several stores that were closed nine days earlier were open again on the day of the last measurement.
  • Public catalogue only. No customers, no orders, no traffic, no revenue.
  • A site that is not on Shopify returns nothing and says so, rather than pretending the catalogue is empty.
  • On the free plan everything works at the FREE rate until Apify's monthly platform credit runs out; the run then stops cleanly and keeps what it has.