Shopify Data Scraper — Products API, Prices, Stock | $0.90/1k
Pricing
from $0.72 / 1,000 product results
Shopify Data Scraper — Products API, Prices, Stock | $0.90/1k
Scrape any Shopify store by domain: products, variants, prices, compare-at prices, stock, SKUs, images, vendor, type, tags, dates and store currency. Many stores per run, collections, product URLs, filters, product or variant rows. No API key.
Pricing
from $0.72 / 1,000 product results
Rating
0.0
(0)
Developer
Raffy
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Security
Limited permissionsShare
What does Shopify Products Scraper do?
Shopify Products Scraper reads the product catalog of any Shopify store and gives it back as clean JSON, CSV or Excel: titles, every variant with its price, compare-at (was) price, stock status and SKU, images, vendor, product type, tags, created / updated / published dates and the store's currency. Enter store domains such as colourpop.com or allbirds.com (one or thousands), and get their products in seconds. No Shopify account, no API key, no app install and no browser.
It works as a Shopify products API for stores you do not own. Every Shopify store publishes its catalog as public JSON (/products.json), and this Actor reads that feed page by page, handles pagination, redirects, headless storefronts and currency, and turns it into one tidy row per product (or per variant).
Typical use cases:
- Competitor price monitoring: track prices, discounts (compare-at prices) and stock of rival Shopify stores every day with a schedule.
- Product research and dropshipping: pull full catalogs of trending DTC brands, their best sellers and new arrivals, with images and descriptions.
- Catalog and market analysis: compare assortments, vendors, product types and price ranges across hundreds of stores.
- Feeds for AI agents and apps: a structured Shopify product scraper an agent can call with just a domain.
- Store research and lead qualification: one store summary row per store (product and collection counts, price range and median, top vendors and product types, theme, apps, the store's social links, last product update) to size up hundreds of Shopify stores without downloading their catalogs.
It reads only data the stores publish for every visitor. It does not log in and does not collect customer data (Shopify's public feeds contain none).
Why use Shopify Products Scraper?
- The whole catalog, fast. 250 products per request; 1,445 products from 30 stores took 7 seconds on Apify in our test.
- Works where other Shopify scrapers stop. Headless stores (a custom front end on
www) and stores that redirect to regional domains are read through the store's own Shopify address, so they still return data. - Correct currency. The price currency comes from the store's shop record and every request pins it, so prices never switch to a visitor's local currency, and the currency is never guessed.
- Filters that save money. In stock only, price range, product type, vendor, tags, title keywords and "updated since" are applied before rows are written; you pay only for rows you keep.
- Honest results. Every row has a
status. A site that is not a Shopify store, an empty collection or a deleted product gives one freenot_foundrow that says why; you are billed only forokrows. - Cheap. $0.90 per 1,000 products, Apify platform usage included.
What data can Shopify Products Scraper extract?
One row per product (default) with these fields:
| Field | Type | Description |
|---|---|---|
title | string | Product title |
storeDomain | string | Store domain as you entered it, e.g. allbirds.com |
storeName | string | Shop name from the store's public shop record |
productId | integer | Shopify product ID |
handle | string | Product handle (URL slug) |
url | string | Product page on the store |
vendor | string | Vendor / brand |
productType | string | Product type as the store names it |
tags | array | Product tags |
minPrice, maxPrice | number | Lowest and highest variant price |
compareAtMinPrice, compareAtMaxPrice | number | Compare-at ("was") prices, when the store sets them |
currency | string | ISO currency of the prices, e.g. USD, AUD; empty if the store does not publish it |
available | boolean | At least one variant can be bought |
onSale | boolean | A variant's compare-at price is above its price |
variantCount | integer | Number of variants |
variants | array | id, title, sku, price, compareAtPrice, available, option1-option3, grams per variant |
images, imageCount | array, integer | Image URLs (up to 50) and the total count |
bodyText | string | Description as plain text (HTML removed) |
options | array | Option names and values, e.g. Size: S, M, L |
createdAt, updatedAt, publishedAt | string | Dates with the store's time-zone offset |
collection | string | Collection handle, when the row came from a collection |
source | string | products_feed, collection_feed or product_page |
status, error, scrapedAt | string | Row status, reason for non-ok rows, time of extraction |
With One row per = Variant, each size/colour is its own row with variantId, variantTitle, sku, price, compareAtPrice, available, option1-option3, grams and image, plus the product columns. Rows from Product URLs also carry per-variant inventoryQuantity and barcode when the store publishes them.
Store summary (one row per store)
With One row per = Store summary (outputMode: "store") the Actor writes one row per store and no product rows. With Add a store summary row (includeStoreSummary: true) you get the summary rows next to the product rows. Each summary row has source: "store_summary" and:
| Field | Description |
|---|---|
storeDomain, storeName, shopifyDomain, primaryDomain, storeDescription | Who the store is, from its public shop record |
productCount, collectionCount | Published products and collections in the whole store |
topCollections | Up to 25 largest collections: title, handle, productsCount |
priceMin, priceMedian, priceAverage, priceMax, currency, currencies | Price range of the sampled products (each at its cheapest variant) and the currencies seen |
onSaleShare, inStockShare, averageVariantCount | Share of sampled products on sale and in stock, variants per product |
topVendors, topProductTypes, topTags, vendorCount, productTypeCount | Most frequent vendors (brands), product types and tags in the sample |
lastProductUpdateAt, newestProductCreatedAt, lastProductPublishedAt | How active the catalog is |
sampleSize, sampleIsFullCatalog | Products read for the statistics (default 250, newest updates first; up to 1,000 with Products sampled per store summary) |
themeName, themeVersion, themeStoreId, usesThemeStoreTheme, headless, passwordProtected, locale | The storefront theme as the home page names it (Dawn, ...), or headless: true for a custom front end |
apps, appEmbeds | Apps and services whose code the home page loads (Klaviyo, Yotpo, Recharge, Klarna, Judge.me, ...). A signal from public assets, not a complete list |
socialLinks | The store's own social profiles linked from its home page, one per network |
country, province, shipsToCountries, shipsToCountryCount, shopPayInstallments, shopPayCardBrands | Business location (country and state only) and selling settings from the shop record |
collectionsError, productSampleError, homePageError | Set only when that part could not be read; the rest of the row is still filled |
A summary never contains people's data: no emails, phone numbers, staff or customer names. Social links are the store's business profiles, never personal profiles.
Result status (tri-state output)
status | Meaning | Billed? |
|---|---|---|
ok | A product (or variant) row, or a store-summary row. | Yes |
not_found | Not a Shopify store, feed turned off, password-protected store, empty or unknown collection, deleted product, or nothing matched your filters. error says which. | No |
error | The store could not be read after several retries (network error, rate limit). error says why. | No |
How to scrape Shopify stores
- Open the Actor in Apify Console and click Try for free.
- Enter one or more store domains in Store URLs or domains (
colourpop.com,https://www.allbirds.com), collection URLs, or product URLs. - Optionally pick Collection handles, One row per (product or variant) and Filters.
- Set Maximum results: the default 20 is a quick test; raise it to 10,000 or more to read whole catalogs.
- Click Start. The default run finishes in about 5-10 seconds. Download the results as JSON, CSV, Excel or HTML.
To automate it, call the Actor from the API tab (Node.js, Python, curl) or add a Schedule for daily price tracking.
How much does it cost to scrape Shopify?
This Actor uses pay-per-event pricing. Apify platform usage is included in these prices.
| Event | Price (Bronze, the default) | When it is charged |
|---|---|---|
| Actor start | $0.005 per run | Once per run (per GB of memory; the 1 GB default is one event). |
Result (status: ok row) | $0.0009 per product (or per variant row), $0.90 per 1,000 | Per saved Shopify product row, or variant row in variant mode, with status ok. |
Store summary (status: ok summary row) | $0.004 per store, $4 per 1,000 stores | Per saved store-summary row with status ok, only when you ask for summaries (One row per = Store summary, or Add a store summary row). Charged instead of a product result for that row, never on top of it. Stores that are not Shopify or cannot be read give a free not_found or error row. |
Higher Apify plans pay less: Silver -10% and Gold -20% on the start, product and store-summary events (Free is the same as Bronze). For example, a product costs $0.0009 on Free and Bronze, $0.00081 on Silver and $0.00072 on Gold; a store summary costs $0.004, $0.0036 and $0.0032.
Examples: the default run (20 products) costs $0.023. Summaries of 1,000 stores cost $4.005. 1,000 products cost $0.905, 10,000 products $9.005. Rows with status not_found or error are never billed, and products your filters drop are never written or billed. You can cap spending with Maximum results, Maximum results per store and the run's Max total charge option.
Input
| Field | Type | Default | Description |
|---|---|---|---|
startUrls | array of strings | colourpop.com, allbirds.com | Store domains or URLs, collection URLs or product URLs |
productUrls | array of strings | - | Product pages to read individually |
collections | array of strings | - | Collection handles to read in every store |
outputMode | product, variant or store | product | One row per product, per variant, or one summary row per store |
includeStoreSummary | boolean | false | Also write one store-summary row per store next to the product rows |
storeSummarySampleSize | integer | 250 | Products per store read for the summary statistics (up to 1,000) |
maxItems | integer | 20 | Stop after this many rows in total |
maxItemsPerStore | integer | - | Stop reading a store after this many rows |
inStockOnly | boolean | false | Only products (variants) that can be bought |
minPrice, maxPrice | integer | - | Price range, in the store's currency |
productTypes, vendors, tags, keywords | array of strings | - | Keep matching products only |
updatedSince | string | - | YYYY-MM-DD or relative such as 7 days |
proxyConfiguration | object | off | Optional Apify Proxy (datacenter is enough) |
Example: the in-stock hoodies under $80 of two stores, one row per variant:
{"startUrls": ["gymshark.com", "https://www.allbirds.com"],"keywords": ["hoodie"],"inStockOnly": true,"maxPrice": 80,"outputMode": "variant","maxItems": 500}
Example: a summary of three stores, no product rows:
{"startUrls": ["colourpop.com", "www.allbirds.com", "kyliecosmetics.com"],"outputMode": "store"}
Output
Real rows from a run on Apify (arrays shortened):
[{"url": "https://allbirds.com/products/womens-allbirds-flip-flop-dusty-pink","status": "ok","scrapedAt": "2026-09-27T22:24:39.779Z","storeDomain": "allbirds.com","storeName": "Allbirds","productId": 7340901859408,"handle": "womens-allbirds-flip-flop-dusty-pink","title": "Women's Allbirds Flip Flop - Dusty Pink","vendor": "Allbirds","productType": "Shoes","tags": ["allbirds::complete => true", "allbirds::edition => limited", "allbirds::gender => womens"],"createdAt": "2026-03-27T14:03:50-07:00","updatedAt": "2026-09-27T15:24:39-07:00","publishedAt": "2026-09-25T16:58:13-07:00","currency": "USD","minPrice": 25,"maxPrice": 25,"compareAtMinPrice": 50,"compareAtMaxPrice": 50,"available": true,"onSale": true,"variantCount": 7,"variants": [{ "id": 42146889039952, "title": "5", "sku": "A12513W050", "price": 25, "compareAtPrice": 50, "available": false, "option1": "5", "option2": null, "option3": null, "grams": 455 }],"images": ["https://cdn.shopify.com/s/files/1/1104/4168/files/A12513_26Q2_Allbirds-Flip-Flop-Dusty-Pink_PDP_LEFT.png?v=1774646345"],"imageCount": 5,"bodyText": "Sun on your feet. Comfort underneath. Light, easy, and made for warm weather, these flip flops bring everyday comfort to sunny days...","options": [{ "name": "Size", "values": ["5", "6", "7", "8", "9", "10", "11"] }],"collection": null,"source": "products_feed"},{"url": "https://princesspolly.com/","status": "not_found","error": "princesspolly.com is not a Shopify store: us.princesspolly.com/meta.json answered HTTP 404 (every Shopify store answers it). If the shop runs on another domain, enter that domain or its .myshopify.com address.","scrapedAt": "2026-09-27T22:24:38.641Z","storeDomain": "princesspolly.com"}]
A store-summary row (outputMode: "store"), from a run on Apify on 2026-10-19 (arrays shortened):
{"url": "https://www.allbirds.com/","status": "ok","scrapedAt": "2026-10-19T20:26:10.069Z","storeDomain": "allbirds.com","storeName": "Allbirds","shopifyDomain": "weareallbirds.myshopify.com","primaryDomain": "www.allbirds.com","storeDescription": "The world’s most comfortable shoes, made with natural materi...","country": "US","province": "California","currency": "USD","currencies": ["USD"],"productCount": 692,"collectionCount": 1346,"topCollections": [{"title": "All Products", "handle": "all-products-1", "productsCount": 4143}, {"title": "All Shoes - Men's and Women's", "handle": "all-shoes-mens-and-womens", "productsCount": 3056}],"sampleSize": 250,"sampleIsFullCatalog": false,"priceMin": 4,"priceMax": 165,"priceMedian": 75,"priceAverage": 83.86,"onSaleShare": 0.552,"inStockShare": 0.448,"averageVariantCount": 10.9,"vendorCount": 1,"topVendors": [{"name": "Allbirds", "count": 250}],"productTypeCount": 4,"topProductTypes": [{"name": "Shoes", "count": 234}, {"name": "Apparel", "count": 6}],"topTags": [{"name": "allbirds::complete => true", "count": 242}, {"name": "shoprunner", "count": 223}],"lastProductUpdateAt": "2026-10-19T13:26:09-07:00","newestProductCreatedAt": "2026-05-26T11:10:21-07:00","lastProductPublishedAt": "2026-09-25T16:58:13-07:00","shipsToCountryCount": 1,"shipsToCountries": ["US"],"shopPayInstallments": true,"shopPayCardBrands": ["visa", "master", "american_express", "discover", "diners_club"],"themeName": "allbirds-theme","themeVersion": "1.231.12","themeStoreId": null,"usesThemeStoreTheme": false,"headless": false,"passwordProtected": false,"locale": "en-US","apps": ["Attentive", "Redo", "Elevar", "Google Tag Manager", "Microsoft Clarity", "GovX ID", "Shop Pay"],"appEmbeds": [],"socialLinks": {"instagram": "https://www.instagram.com/allbirds", "pinterest": "https://pinterest.com/weareallbirds", "facebook": "https://www.facebook.com/weareallbirds", "x": "https://twitter.com/allbirds", "tiktok": "https://www.tiktok.com/@weareallbirds", "youtube": "https://www.youtube.com/channel/UCnGErLCau5qNJ0Xwe6uEyTw"},"source": "store_summary"}
Tips
- Put many stores in one run: you pay the start fee once, and stores are read in parallel.
- Use Maximum results per store so one huge catalog cannot use up the run.
- For daily price tracking, schedule the run and use Updated since
1 day: the feed is newest-first, so the scan stops early. - If a store answers with rate-limit errors, run it again later or enable Apify Proxy (datacenter).
- To qualify a long list of domains, use One row per = Store summary: one row per store for $0.004, and non-Shopify domains give a free
not_foundrow.
Limitations
- Only public Shopify storefronts. Password-protected stores and stores that turned their public product feed off return a
not_foundrow. - Stock counts (
inventoryQuantity) are published by some stores only, and only on product-URL rows; feed rows carryavailableper variant, not quantities. - Prices are in the store's own currency (its main market). Regional price lists of other markets are not collected.
productType,vendorandtagsare whatever the store enters; they differ between stores.- Store-summary prices, vendors, product types and tags come from a sample (default 250 products, newest updates first);
sampleIsFullCatalogsays when the sample is the whole store. Counts (productCount,collectionCount) always cover the whole store. A collection'sproductsCountis Shopify's own figure and can include products that are not published. appslists services whose code the home page loads; apps that run only in checkout, in the admin or on other pages are not seen.themeNameis empty for headless stores.- For product URLs on stores with a headless front end,
availablecomes from the published stock data and can be empty;availabilityErrorthen says why. Scanning the store or a collection always givesavailable.
FAQ
Do I need a Shopify account, app or API key?
No. The Actor reads the public JSON that every Shopify store serves to every visitor. It works for any store, not only your own.
How do I know if a site is a Shopify store?
Just enter it. A Shopify store returns products; any other site returns one free not_found row explaining that it is not a Shopify store (or that its feed is off). You can use this to check lists of domains.
Can I get the products of one collection only?
Yes. Enter the collection URL (https://colourpop.com/collections/best-sellers) or put the handle best-sellers in Collection handles.
How do I track the price of specific products?
Put their URLs in Product URLs and schedule the run. Use One row per = Variant to get one row per size or colour with its own price and stock.
Can I see which theme and apps a Shopify store uses?
Yes. Set One row per to Store summary. Each store gets one row with its theme (themeName, for example Dawn, or headless: true), the apps and services its home page loads (apps, for example Klaviyo, Yotpo, Recharge, Klarna), its social profiles, product and collection counts, price range and median, top vendors and product types, and the date of the last product update.
Can I use this Actor from an AI agent or MCP client?
Yes. It runs with no input at all (it then reads two example stores), accepts plain domains, and every row explains itself with status and error.
Why did I get fewer rows than maxItems?
The stores have fewer matching products, a per-store limit stopped them, or your run hit its Max total charge. not_found rows say when a filter matched nothing.
Related Actors
- Google Ads Library & Transparency Scraper - use it to see which Google ads a competing store or brand is running.
- Keyword Suggestions API - use it for Google Shopping autocomplete keywords for product titles, ads and SEO.
- Tech Stack & DMARC Checker - use it to check which domains on a prospect list run a hosted commerce platform, plus their mail and DNS setup.
- Pinterest Scraper - use it to see how the same products are being pinned and discovered visually.
- Google Trends Scraper - use it to check demand and seasonality for a product category before you stock or price it.
- Google Maps Leads Extractor - use it to find local retailers as leads alongside online store data.
- App Store Scraper - use it if the merchant also sells or promotes an iOS app.
- Google Play Scraper - use it if the merchant also sells or promotes an Android app.
- AliExpress Products Scraper - use it to check supplier prices, ratings and order counts for the same products on AliExpress.
Legal and data-protection notice
This Actor extracts only product and store information that Shopify stores publish publicly for every visitor; it does not extract customer data, e-mail addresses, phone numbers or other personal data, and it does not log in or get around access controls. Personal data is protected by the GDPR in the European Union and by other regulations around the world; do not use the output to process personal data without a legitimate reason. You are responsible for complying with each store's terms of service and applicable law when using the extracted data.
This Actor is an independent tool and is not affiliated with, endorsed by or sponsored by Shopify Inc. or any store it reads. Shopify is a trademark of Shopify Inc. All trademarks belong to their respective owners.