Shopify Store Scraper & Price/Stock Change Monitor
Pricing
Pay per event
Shopify Store Scraper & Price/Stock Change Monitor
Export any Shopify store's full catalog from its domain, then get only what changed: new or removed products, price and stock changes. No login needed.
Pricing
Pay per event
Rating
0.0
(0)
Developer
Randor Saar
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Shopify Store Scraper & Price/Stock Change Monitor exports the full public catalog of any Shopify store from just its domain: products, variants, prices, compare-at (sale) prices, stock flags, SKUs, images and tags. Schedule it in changes mode and each run returns only what changed: new and removed products, price moves, sale changes and stock flips.
Try it in one click: the form is pre-filled with one store (colourpop.com) and 100 products. A real run of it on Apify finished in 6 seconds with 100 product rows and one free status row, for $0.085.
- ✅ Just type a domain (
gymshark.com): no login, no API key, no store access needed - ✅ Full catalogs, including stores above 25,000 products (Kith: 35,206 of 35,206, matching its sitemap)
- ✅ Change monitor built in: you pay a small scan fee plus a fee per change, not for re-exporting the catalog
- ✅ Headless stores (custom front ends) are read from their verified
myshopify.comshop - ✅ Pay only for stores that finish: rows are held back until a store's crawl ends
ok; blocked, failed or unfinished stores cost nothing - ✅ One free status row per store that says what worked and why
- ✅ Collects public data only: the same product data any logged-out shopper sees, no customer data
What can you use it for?
| You are | You use it to |
|---|---|
| Dropshipper or reseller | Watch supplier catalogs for price and stock changes |
| DTC brand or repricing team | Track competitor prices, discounts and new launches |
| Market or assortment analyst | Build price-band and launch datasets across many stores |
| AI agent (Apify MCP) | Answer "what does this store sell, and what changed this week?" |
What data does it extract?
Product row (type: "product"), one per product (or one per variant with One row per variant):
| Field | What it is |
|---|---|
store, myshopifyDomain, currency | Store domain, its Shopify shop domain, and the store's default currency |
productId, handle, title, url | Shopify product ID, handle, title and product link |
vendor, productType, tags | Brand, product type and tags |
featuredImage, imageUrls | Main image and all image URLs |
priceMin, priceMax, compareAtMax, onSale | Price range across variants, highest compare-at (crossed-out) price, and whether anything is discounted |
available, variantsInStock, variantCount | Stock flag for the product and how many variants are in stock |
variants[] | Per variant: id, title, sku, price, compareAtPrice, available, grams, options |
createdAt, publishedAt | When the product was created and published (UTC) |
likelyTestProduct | true for products that look like store test or placeholder items |
inventoryQuantity | Inventory add-on only: total for the product and per variant, where the store makes it public (null otherwise) |
descriptionHtml | Only with Include description HTML |
source, scrapedAt | Where the row came from (products.json or the Storefront API) and when |
Change row (type: "change"): store, productId, variantId, handle, title, variantTitle, changeType, oldValue, newValue, changePercent, previousSeenAt, url, scrapedAt. changeType is one of added, removed, priceUp, priceDown, compareAtChanged, backInStock, outOfStock, and optionally titleChanged, tagsChanged, imagesChanged.
Store status row (type: "storeStatus", always free): status, productsFound, expectedCount and where it came from, complete, route, httpStatus, proxyUsed, error and notes.
| status | Meaning | Charged? |
|---|---|---|
ok | Catalog read completely (or up to your maxProductsPerStore) | Yes, its rows |
notProcessed | The run stopped first, your max charge was too low for this store, or the store's time budget ran out | No |
invalidInput | Not a domain or URL | No |
passwordProtected | The store is behind its storefront password | No |
blocked | A bot challenge or HTTP 429 that stayed after retries and fresh proxy sessions | No |
notShopify | Not a Shopify store, or its product feed is switched off | No |
error | Anything else, including a catalog well short of the store's own product count | No |
How to use it
- Click Try for free and keep the pre-filled store, or enter your own domains (
gymshark.com,https://kith.com, or a collection URL such ashttps://kith.com/collections/mens). - Pick a mode:
snapshot(all products),changes(only what changed since the last run) orsnapshotWithChanges(all products, each tagged with its change). - For monitoring, set a Watchlist name and schedule the Actor (for example daily). Each watchlist keeps its own baseline.
- Click Start, then download the results as JSON, CSV, Excel or HTML, or read them through the Apify API.
Input example
{"stores": ["gymshark.com", "colourpop.com", "allbirds.com"],"mode": "changes","watchlistName": "competitors","minPriceChangePercent": 2}
Other options: collections, maxProductsPerStore, rowPerVariant, trackFields (add title, tags, images), includeInventory, includeDescriptionHtml, originFallback, resetState, maxConcurrencyPerStore, storeTimeBudgetSecs (default 1,200 s, 60 to 3,600) and proxyConfiguration (Apify datacenter proxy by default). Every field is explained in the input form.
Output examples
A product row from a real run on 24 October 2026 (tags, images and variants shortened):
{"type": "product","store": "allbirds.com","myshopifyDomain": "weareallbirds.myshopify.com","currency": "USD","productId": "7340901859408","handle": "womens-allbirds-flip-flop-dusty-pink","title": "Women's Allbirds Flip Flop - Dusty Pink","vendor": "Allbirds","productType": "Shoes","tags": ["allbirds::edition => limited", "allbirds::gender => womens", "allbirds::material => sugar", "…"],"url": "https://allbirds.com/products/womens-allbirds-flip-flop-dusty-pink","featuredImage": "https://cdn.shopify.com/s/files/1/1104/4168/files/A12513_26Q2_Allbirds-Flip-Flop-Dusty-Pink_PDP_LEFT.png?v=1774646345","priceMin": 25,"priceMax": 25,"compareAtMax": 50,"onSale": true,"available": true,"variantsInStock": 1,"variantCount": 7,"variants": [{ "id": "42146889039952", "title": "5", "sku": "A12513W050", "price": 25, "compareAtPrice": 50, "available": false, "grams": 455, "options": ["5"] }],"createdAt": "2026-03-27T21:03:50Z","publishedAt": "2026-09-25T23:58:13Z","likelyTestProduct": false,"source": "products.json","scrapedAt": "2026-10-24T12:50:04Z"}
A change row from a real scheduled run (a size sold out between two runs):
{"type": "change","store": "gymshark.com","currency": "USD","productId": "6806899851466","handle": "gymshark-gslc-stringer-sleeveless-tops-purple-aw26","title": "Gymshark GSLC Stringer - Cherry Purple/Soft White","variantId": "39799451844810","variantTitle": "Medium","changeType": "outOfStock","oldValue": true,"newValue": false,"changePercent": null,"previousSeenAt": "2026-10-24T13:15:30Z","url": "https://gymshark.com/products/gymshark-gslc-stringer-sleeveless-tops-purple-aw26?variant=39799451844810","scrapedAt": "2026-10-24T13:39:02Z"}
A store status row (free):
{ "type": "storeStatus", "store": "allbirds.com", "status": "ok", "route": "products.json", "productsFound": 397, "expectedCount": 397, "expectedCountSource": "meta.json", "complete": true, "proxyUsed": "apify-datacenter", "rowsOutput": 397, "error": null }
The dataset has three views: Products, Changes and Store status. The run's OUTPUT record holds a run summary (events, stores by status, timing, request statistics) and STATUS a compact list of each store's result.
How much does it cost to scrape a Shopify store?
You pay per result. Platform usage (compute, proxy, storage) is included in the price.
| Event | Price |
|---|---|
| Product row (or variant row) | $0.85 per 1,000 ($0.00085 each) |
| Change row | $2.00 per 1,000 ($0.002 each) |
100 products scanned in changes mode | $0.0003 per 100 ($0.003 per 1,000) |
| Inventory add-on (only where the quantity is public) | $0.50 per 1,000 |
| Actor start | $0.00005 per run (Apify's standard start event; the default 512 MB counts once) |
Status rows, stores that don't end ok, duplicates, price moves below your threshold | free |
Snapshot mode charges one product row per product. Changes mode charges a scan fee in batches of 100 products plus one change row per change; unchanged products are not output.
The scan fee is rounded up once per store per run: a 75-product store is 1 batch ($0.0003), a 153-product store 2 batches ($0.0006), a 10,359-product store 104 batches ($0.0312). The remainder never carries over to another store.
Worked examples (prices from the table above, counts from real runs):
- The pre-filled run (
colourpop.com, 100 products, snapshot): 100 × $0.00085 + $0.00005 = $0.08505. - One store's full catalog: Allbirds, 397 products = 397 × $0.00085 = $0.34.
- First monitoring run (baseline) on gymshark.com, colourpop.com and allbirds.com (10,359 + 1,064 + 397 products): 104 + 11 + 4 = 119 batches × $0.0003 = $0.036, no change rows.
- Daily monitoring of the same 3 stores: $0.036 scan fee plus $0.002 per change. A real run on Gymshark found 26 changes: 26 × $0.002 = $0.052.
- 100 stores, 119,977 products checked in one changes-mode run: 1,244 batches × $0.0003 = $0.37.
Apify's Free plan includes $5 of monthly usage.
You never pay for status rows, for stores that end blocked, notShopify, error, notProcessed or any status other than ok (even if part of their catalog was read), for duplicate products, or for price moves below minPriceChangePercent. The run also respects the maximum charge you set: a store that wouldn't fit is skipped as notProcessed and costs nothing.
Change monitoring (changes mode)
- The first
changesrun for a store saves a baseline and outputs no change rows: you pay only the scan fee. - The baseline lives in the key-value store
shopify-monitor-<watchlistName>in your Apify account, one record per store. - A baseline is replaced only after a complete crawl that ended
ok. A stopped, blocked or timed-out crawl never overwrites it, so you don't get falseremovedrows. - A product is reported
removedonly after it was missing on two complete runs in a row. A variant that disappears from a product that is still listed is reported straight away. - A product deleted and re-created with the same handle is reported once (
addedwithrecreatedFromProductId). updated_atis not used: Shopify bumps it on nearly every product daily. Changes are detected from price, compare-at price and stock per variant.- With
maxProductsPerStoreset, the baseline isn't saved (a capped crawl isn't a full catalog).
In real tests, every detected change was checked against the live store: 9 of 9, 1 of 1 and 16 of 16 matched.
How reliable is it?
- Accuracy: 30 of 30 products from 13 stores matched the store's own product pages on every field.
- Blocking: every request goes through Apify's datacenter proxy with one session per store, rotated (up to 3 times) on a bot challenge or HTTP 429. In our test runs on Apify with the proxy, the only store that kept challenging was bombas.com (Vercel). A 100-store run at 512 MB saw 0 challenges and 0 HTTP 429 responses. Challenges are never solved; a store that keeps challenging ends
blockedand costs nothing. - Large stores: Shopify's product feed stops at 25,000 products. Past that, the Actor continues through Shopify's public Storefront API and uses the store's sitemap as the target count (Kith: 35,206 of 35,206 on Apify in 669 s).
- Scale: one 100-store run at 512 MB read 191,064 products in 1,296 s (97 stores finished; the 3 largest needed a bigger time budget).
- Restarts: charged products are recorded before each charge, so if Apify migrates or restarts a run, nothing is charged twice (tested with forced reboots on Apify: charged batches equalled the expected count exactly).
FAQ
Is it legal to scrape Shopify stores? This Actor reads only public product data that any logged-out shopper can see, through the same JSON feeds Shopify serves to every visitor. It doesn't log in and reads no customer data. Check your own use against each store's terms and the law where you work; if you're unsure, ask a lawyer.
Why did a store end blocked?
The store put a bot challenge on its own domain (for example bombas.com sits behind Vercel's checkpoint). The Actor retries with fresh proxy sessions but never solves challenges. You aren't charged for that store.
Why did a big store end notProcessed?
Its time budget ran out. The largest stores (for example Burga, about 160,000 products, or Fashion Nova) may need more than the default 1,200 s. Raise Time budget per store (up to 3,600 s). Nothing is charged for an unfinished store.
Why is the price in a different currency than on my screen?
Prices are in the store's default currency (currency), as its public feed serves them, not your local currency.
Can I monitor only one collection?
Yes: enter a collection URL (https://kith.com/collections/mens) or list collection handles in collections.
Can I get exact stock quantities? Turn on the inventory add-on. Many stores hide quantities; you're charged only for products where a quantity was public.
Can I use it through the API or with integrations? Yes. Run it with the Apify API, the JavaScript or Python client, schedules, webhooks, or integrations such as Make, Zapier and Google Sheets.
Limits
- Shopify stores only. Stores with their product feed switched off end
notShopify. - Very large stores (e.g. Burga, about 160,000 products, or Fashion Nova) may need a larger
storeTimeBudgetSecs; in our tests Fashion Nova wasn't finished within a 600 s budget (34,095 products read on Apify at 512 MB). - Stores behind their own bot protection (e.g. bombas.com, Vercel) end
blocked. - Prices are the storefront's default-currency prices; market-specific prices aren't read.
- A store whose public feed lists well under its own product count ends
error(not charged), because the catalog can't be confirmed complete.
Feedback
Found a bug or need a field? Open an issue on the Issues tab and include the run ID.