Shopify Products Scraper with Price and Stock Change Tracking
Pricing
$1.00 / 1,000 scraped products
Shopify Products Scraper with Price and Stock Change Tracking
Shopify products scraper for any storefront. Export the full catalog with variants, prices and stock, and see what changed since the last run. Pay per product.
Pricing
$1.00 / 1,000 scraped products
Rating
0.0
(0)
Developer
Gerald Dobin
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Shopify Products Scraper
Give this Actor a list of Shopify stores and it hands back the whole public catalog as one clean row per product: title, URL, vendor, product type, tags, the full price range, whether anything is in stock, and every size and colour variant with its own price, compare at price, SKU and stock flag, plus images and option axes. Run it again tomorrow and it tells you what moved, marking each product new, priceChanged, availabilityChanged, updated, unchanged or removed, with the old prices sitting next to the new ones. No browser, no login, no API key, no setup: paste a store address and press start.
Who it is for
Merchants watching competitors. Put your rivals in the list, schedule it daily, and switch on "Only return what changed". You get a short dataset every morning holding exactly the price cuts, the restocks, the sell outs and the new arrivals, and nothing else.
Agencies and dropshippers researching catalogs. Pull an entire store, or just the collections you care about, into a spreadsheet in one run. Every variant is a row you can sort by price, filter by vendor, or join to your own SKU list on the stable Shopify product id.
Analysts looking across a market. Point it at fifty stores in one go and get a single comparable table: pricing distributions, discount depth from the compare at price, assortment size by vendor and product type, and how fast each store turns its catalog over.
Sample output
{"store": "www.allbirds.com","storeName": "Allbirds","currency": "USD","productId": 7205177819216,"handle": "anytime-crew-sock-blizzard-verdant-green","url": "https://www.allbirds.com/products/anytime-crew-sock-blizzard-verdant-green","title": "Anytime Crew Sock - Blizzard, Verdant Green","vendor": "Allbirds","productType": "Socks","tags": ["allbirds::material => cotton", "YCRF_socks"],"available": true,"priceMin": 15,"priceMax": 18,"compareAtPriceMin": 18,"compareAtPriceMax": 18,"variantCount": 4,"variants": [{"id": 41271102799952,"title": "S (W5-7)","sku": "A12705U001","price": 15,"compareAtPrice": 18,"available": true,"options": ["S (W5-7)"],"grams": 59,"requiresShipping": true}],"images": ["https://cdn.shopify.com/s/files/1/.../sock.jpg"],"featuredImage": "https://cdn.shopify.com/s/files/1/.../sock.jpg","options": [{ "name": "Size", "values": ["S (W5-7)", "M (W8-10 / M8)", "L (W11 / M9-12)", "XL (M13-14)"] }],"bodyHtml": null,"description": null,"createdAt": "2025-08-06T23:11:35.000Z","updatedAt": "2026-09-08T01:10:51.000Z","publishedAt": "2026-06-11T23:48:52.000Z","changeType": "priceChanged","previous": { "priceMin": 18, "priceMax": 18, "available": true },"scrapedAt": "2026-09-08T02:14:07.881Z","error": null}
How change tracking works
The first run of a store labels everything new. At the end of every run the Actor saves a small snapshot of the store in a key-value store called shopify-products-scraper-state in your own account: for each product its price range, stock flag, variant count and a short fingerprint of the fields a shopper can see, and for each variant its price, compare at price and stock flag. No descriptions, no image addresses, no tag lists, so even a catalog of tens of thousands of products stays small.
The next run compares against that snapshot and sets changeType on every row:
| Value | What it means |
|---|---|
new | The product was not in the previous run. |
priceChanged | A price or a compare at price moved, on the product or on any single variant. |
availabilityChanged | The product or one of its variants went in or out of stock. |
updated | The store changed the title, vendor, product type, tags, options or images, or added or dropped a variant, without moving a price or the stock. |
unchanged | Nothing at all moved. |
removed | The product was in the previous run and is gone from the catalog now. |
A price move is reported ahead of a stock move, and a stock move ahead of any other edit, so a price drop is never hidden behind a title tweak that happened in the same hour. The previous field on every row carries the price range and the stock flag the last run saw, so you can compute the size of a move without keeping your own history.
Description edits on their own do not count as a change. This is a price and stock monitor, and comparison is done on prices, stock, the variant lineup, and the title, vendor, product type, tags, options and images. A merchant rewriting the marketing copy under an otherwise identical product leaves the row as unchanged, so a monitoring schedule is not billed for copywriting. Turn on "Include the product description" and read description yourself if copy changes are what you are after.
Shopify's own updated_at timestamp is deliberately not used to decide this. Many large stores rewrite it on every product on every request as their inventory syncs, so a scraper that trusted it would report the entire catalog as changed on every single run and bill you for all of it. Comparison is done on the things a shopper would actually notice instead. The raw updatedAt is still on every row, so you can use it if you want it.
To run it as a monitor: switch on "Only return what changed", then schedule the Actor daily or hourly. Each run gives you a dataset holding only the products that actually moved, and you are billed only for those rows. Point a webhook or an integration at the run and you have a price and stock alert.
What removed means. It means the product was absent from a full read of the catalog, and the Actor is careful about claiming it. A store is only allowed to report removals when every page of it came back without error and the last page came back empty, nothing was cut short by "Maximum products per store", a collection filter or the run's cost limit, and the previous snapshot loaded whole. Anything less and a product it did not see is treated as unseen rather than gone, and the run says so in the log. A limited run also merges what it saw into the saved snapshot rather than replacing it, so the next full run still knows about the rest.
One run at a time per store and settings. Two runs of the same task overlapping is not a supported way to use this Actor: they would each write a baseline over the other. Schedule them far enough apart to finish.
Each set of settings keeps its own baseline. The snapshot is keyed by the store plus the settings that decide which products a run even looks at: the collection filter, the per store limit and the store address. So a daily task reading a whole catalog and a second task watching one collection on the same store do not overwrite each other, which would otherwise make the narrower one report everything outside its collection as removed. The practical consequence is that changing those settings starts a fresh baseline: the next run after such a change labels everything new once, then settles down.
Input reference
| Field | Type | Default | What it does |
|---|---|---|---|
stores | list of text | three example stores | The storefronts to read. A bare domain like gymshark.com, a full address like https://www.allbirds.com, or a myshopify.com address. A link to a product or collection page is reduced to the store root. |
collections | list of text | empty | Limit the run to certain collections by handle, for example mens or new-arrivals. Empty means the whole catalog. |
maxProductsPerStore | number | 50 | How many products to read from each store, so a first run is quick and cheap. Set 0 to read the whole catalog. |
includeDescription | true or false | false | Add the product description as cleaned HTML (bodyHtml) and as plain text (description). |
trackChanges | true or false | true | Compare against the previous run and set changeType and previous. |
onlyChanges | true or false | false | Return only the rows whose changeType is not unchanged. |
maxConcurrency | number | 5 | How many requests to run at once across all stores. Each store is always read one page at a time. |
Every run with the defaults works as it stands, so you can press start and see real output before changing anything.
Pricing
Pay per event, one event: Scraped product, charged once for every product row you receive. Error rows are never charged, and in "Only return what changed" mode the products that did not move are neither returned nor charged, which is what makes a daily monitor cheap to run. Set a maximum cost on the run and the Actor stops cleanly at that limit rather than handing you rows it cannot bill for, and a run stopped that way leaves the changes it did not deliver in place, so the next run still reports them.
Limits
The public catalog is paged by number over a catalog the merchant may be editing while the run reads it, so a product that moves between pages mid run can be missed by that run and picked up by the next one. This is why a removal is only ever reported after a clean full read, described above. Some stores turn the public product endpoint off, or put a bot check in front of it. Those produce an error row saying so, and they are never billed. The endpoint carries the catalog only, so there is no collection level metadata such as a collection title or description, and no inventory counts beyond the in stock flag each variant publishes. Reviews, ratings, question and answer content and anything behind a customer login are not included, because none of that is in the public catalog JSON. Prices are exactly what the storefront quotes to an anonymous visitor in the store's own currency, so a store that shows different prices by country returns the ones its default market publishes.
Product descriptions are returned as cleaned HTML. Scripts, styles, embeds, frames, forms, images and every event handler are stripped out, and only a small allowlist of formatting tags and safe links survives, so a description is safe to put straight into a page of your own.
This Actor reads only the public storefront JSON that every Shopify store serves to anonymous visitors. No cookies, no login, no accounts, no personal data.