Shopify Store Scraper avatar

Shopify Store Scraper

Pricing

from $0.60 / 1,000 results

Go to Apify Store
Shopify Store Scraper

Shopify Store Scraper

Export every product and variant from any Shopify-powered store by domain, read straight from the store's own JSON API rather than scraped HTML.

Pricing

from $0.60 / 1,000 results

Rating

0.0

(0)

Developer

The Netaji

The Netaji

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

13 days ago

Last modified

Share

The Actor exports every product and variant from any Shopify-powered store by domain. It reads the store's own /collections.json and /collections/<handle>/products.json endpoints directly, so no HTML is parsed and no product page is rendered.

This scrapes product catalogs from stores built on Shopify. It does not read the Shopify App Store (apps.shopify.com); an app listing and a store's product catalog are different documents, and this Actor only reads the latter.

Accepted input

FieldTypeDefaultDescription
storeUrlstringRequired. A domain or URL of a Shopify-powered store.
maxItemsinteger0Maximum product variants saved. 0 removes the limit.
proxyConfigobjectResidential Apify ProxyProxy used for every request. Residential by default — most storefronts block or rate-limit datacenter IPs outright.
includeRawDatabooleanfalseAdds handle, every product image, option definitions, and per-variant grams/taxable/requiresShipping/publishedAt. Already present in the same response, so this costs nothing extra to turn on.
{
"storeUrl": "allbirds.com",
"maxItems": 500
}

Response fields

One record per product variant.

FieldContents
nameProduct title, with the variant title appended when it isn't the default one
priceVariant price, exactly as the store's JSON returns it
categoryCollection the product was found in, title-cased
brandProduct vendor
identifierVariant id
skuVariant SKU, when the store sets one
stock0 when the variant is out of stock; null when it's available
image_urlFirst product image
urlThe product's page inside the collection it was found in
descriptionProduct description with HTML tags stripped
old_pricePre-sale price, when the store sets a real compare-at price
barcodeVariant barcode, when the store's product JSON exposes it
product_typeThe store's product type for this product
tagsThe store's tags for this product
handleThe product's URL slug. Only present when includeRawData is on
imagesEvery product image, not just the first. Only present when includeRawData is on
optionsThe product's option definitions (e.g. Size, Color) and their values. Only present when includeRawData is on
gramsVariant weight in grams. Only present when includeRawData is on
taxableWhether the variant is taxable. Only present when includeRawData is on
requires_shippingWhether the variant requires shipping. Only present when includeRawData is on
published_atWhen the product was published to the store. Only present when includeRawData is on
{
"name": "Wool Runner - Natural Black / Dark Grey",
"price": "98.00",
"category": "Mens Shoes",
"brand": "Allbirds",
"sku": "",
"stock": null,
"url": "https://www.allbirds.com/collections/mens-shoes/products/mens-wool-runner-natural-black"
}

How collection is scoped

The store's collections are paged first, then each collection that reports at least one product is paged for its products. A product's variants are yielded once each; a variant that appears in more than one collection is written only the first time it's seen, not once per collection.

A collection's advertised product count can be higher than what actually comes back — the endpoint only exposes products published to the store's online-store sales channel, and a nonzero count is read as "this collection has something to fetch," not as a promise of that many results.

Behaviour on partial results and limits

maxItems stops the run once at least that many variants have been saved, not the instant the limit is reached — a request already in flight when the limit is hit is still allowed to finish, so the final count can land a little past maxItems rather than cutting off mid-request.

Stores behind extra bot protection commonly block datacenter IPs outright and rate-limit everything else, which is why Residential Apify Proxy is on by default. Password-protected storefronts still don't work regardless of proxy: the Actor reads the storefront's public JSON API directly, and a store that requires a login has no public surface for it to read.

Frequently asked questions

Does this scrape the Shopify App Store? No. apps.shopify.com lists apps for merchants to install; this Actor reads a store's product catalog through its storefront JSON API. The two are unrelated documents on unrelated domains.

Why did I get fewer results than the store's collections suggest? A collection's products_count includes products not published to the online store, which the JSON endpoints this Actor reads don't expose. The count is a ceiling, not a guarantee.

Are the same product variants returned more than once if they sit in several collections? No. Each variant is saved once, on the first collection it's found in, even if the store lists it under several.

Does maxItems cut the run off at exactly that number? Not to the item. The run stops once the count reaches or slightly passes maxItems, because a request already in flight when the limit is hit is allowed to complete rather than being discarded mid-request.

Will this work on a password-protected store? No. The Actor reads public JSON endpoints with no browser session and no login; a store that requires one has nothing public for it to read.

Why does this need a proxy, and why residential specifically? Most Shopify storefronts block or rate-limit plain JSON API requests, and many block known datacenter IP ranges outright regardless of request pattern. Residential Apify Proxy is enabled by default for that reason; switching it to datacenter or turning it off is likely to get blocked on stores with any real bot protection.

The store's own products.json has more fields than this Actor returns — where did they go? Nowhere; they're not fetched selectively, they're just not included in the default row shape. The store's JSON response carries the full product object — every image, all option definitions, per-variant shipping/tax flags, timestamps, and more — and this Actor reads that same response but writes out a fixed, commonly-needed set of fields per variant. Turn on includeRawData to get the rest; it's already part of the same response, so nothing extra is fetched or charged for it.