Structured Product Price & Stock Monitor — JSON-LD / Shopify
Track product price and stock from a store's own JSON-LD or Shopify data. Restock, price-drop and sale alerts into Slack or Discord. No API key.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
products,priceDropThresholdPct,onlyNewSinceLastRun(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.0025 per product checked = $2.5 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Product checked | A product was checked | $0.0025 |
| Report generated | A report was generated | $0.05 |
| Restock detected | A restock was detected | $0.02 |
| Change detected | A price change was detected | $0.015 |
| Sale started | A sale got detected | $0.015 |
| No structured data | No structured data detected | $0.001 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-06-09, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
products | The product URLs to track. Each item is an object: { "url": "https://store.com/products/x", "label": "optional human name" }. `url` is required; `label` is optional and is used in the output and in alerts. | array |
priceDropThresholdPct | Only treat a price DROP as a change when it is at least this percentage. 0 (default) records every price change. Price increases are always recorded regardless. Use e.g. 5 to ignore tiny fluctuations and only act on meaningful drops. | integer |
onlyNewSinceLastRun | When ON (recommended for scheduled monitoring), only products that are new or have changed are emitted to the dataset, deltas, not a full re-dump. When OFF, every product's current state is emitted every run. | boolean |
trackPrice | Detect price_change events (old -> new, with % change). | boolean |
trackStock | Detect back_in_stock / out_of_stock events. | boolean |
trackSalePrice | Detect sale_started / sale_ended events (based on compare-at / list price where the source exposes it, best on Shopify & WooCommerce). | boolean |
trackTitle | Detect title_change events (useful for catching relisted / swapped products). | boolean |
notifyOnRestock | Send a webhook notification when a product comes back in stock. | boolean |
notifyOnPriceDrop | Send a webhook notification when a price drops (respecting the price-drop threshold above). | boolean |
webhookUrl | Optional. Slack, Discord, or generic webhook to receive a compact change summary. Slack (hooks.slack.com) and Discord (discord.com/api/webhooks) formats are auto-detected; any other URL receives the full structured JSON payload (great for Zapier / Make / n8n / custom endpoints). | string |
What you get
A structured dataset — each result includes fields like:
change_countchangeschecked_atcurrentextraction_methodextraction_statusis_changedis_newlabelsync_statustargeturlExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
4 ready-to-run use cases
Competitor Price Monitoring from Storefront JSON-LD
Competitor price monitoring that reads each store's own JSON-LD: price, currency, sale flag, stock, SKU. Pages without it say so rather than guessing a number.
Shopify Price Tracker: Catch Sale Start and End
A shopify price tracker reading the store's published list and sale price, so you know the day a discount starts and the day it ends. Changes are logged.
Discord Restock Bot for Limited Product Drops
Point this discord restock bot at a product URL and it posts to your webhook when stock flips back in. Reads the store's JSON-LD, no HTML guesswork.
Product Price API from Any Store's JSON-LD Data
A product price api for a list of URLs: price, currency, sale flag, stock and SKU per product, read from each store's own markup. Built for shopping agents.
Related tools in E-commerce & Price Tools
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
eBay Sold Listings Scraper
Get sold and completed eBay listings: sale price, shipping, sold date, condition, bids, on 9 marketplaces. Bring your own eBay login. $0.70 per 1,000.
1688 Wholesale Scraper
Scrape 1688.com wholesale listings. Get unit price, quantity price tiers, MOQ, supplier, sales count and rating. $0.35 per 1,000 products.
Alibaba 1688 Supplier Ratings Scraper
1688.com supplier ratings: score, five sub-scores, repeat-buyer rate, years on platform, factory or trader, audits. No account. $0.40 per 1,000.
Alibaba.com Scraper
Get Alibaba.com products with no account: price ranges, MOQ, supplier name, country, verified status and images. $0.85 per 1,000.
AliExpress Products Scraper
Scrape AliExpress products by search term: product ID, title, price, discount, rating, order count and image. All prices in one currency. $0.12 per 1,000.
Taobao Category Products Scraper
Scrape Taobao products by category. Get the title, price in CNY, image, product URL, seller and shop ids. No account, no cookies. $1.95 per 1,000 products.
Where this tool sits
- Categories
- E-commerce & Price Tools Monitors & Alerts
- Platforms
- Shopify
Product Price & Stock Monitor: restock and price-drop alerts from a store's own data
Give it a list of product page URLs and it checks each one on a schedule, remembers what it saw last time, and tells you what moved. Price up or down, back in stock, out of stock, a sale starting or ending, or the title changing under the same link.
It reads the structured data a store publishes about its own products: JSON-LD, Shopify's product JSON, WooCommerce data, or microdata. No HTML selectors to break. The flip side is the honest limit: a store that publishes none of that returns nothing useful, and you get a row saying exactly that.
| Input | Product page URLs, with optional labels |
| Output | One row per product that is new or changed |
| Ceiling | No fixed cap on the product list, so keep it to what a run can finish |
| Account needed | None, no API key |
| Price | $0.0025 per product checked, flat on every plan |
🛒 What Product Price & Stock Monitor does
Each run fetches every product URL, pulls the structured record out of the page, and compares it against the baseline it saved last time. The baseline lives in a named key-value store on your own account, so it survives between scheduled runs.
Six kinds of change are detected, and you can switch each family off: price_change, back_in_stock, out_of_stock, sale_started, sale_ended and title_change. A title change is the one people forget to watch, and it is how you catch a listing that has been quietly swapped for a different product under the same URL.
priceDropThresholdPct is worth understanding before you set it. At the default 0 every price move is recorded. Set it to 5 and a drop smaller than 5% is not reported, and the baseline still moves to the new price. So a product sliding 4% a run will never trip a 5% threshold, however far it falls in total. Price rises are always recorded whatever you set. If you want to catch slow slides, leave the threshold at 0 and filter on priceChangePct yourself.
Alerts go out through webhookUrl. Slack and Discord formats are detected from the URL, and anything else gets the full JSON payload, which is what Zapier, Make and n8n want.
📥 What you give it
{
"products": [
{ "url": "https://www.adafruit.com/product/3055", "label": "Raspberry Pi 3" },
{ "url": "https://www.allbirds.com/products/mens-wool-runners", "label": "Wool Runners" }
],
"priceDropThresholdPct": 0,
"onlyNewSinceLastRun": true,
"webhookUrl": ""
}
| Field | What the run uses if you leave it | What it is |
|---|---|---|
products | box starts with two examples | One object per product: url is required, label is optional and is what appears in your alerts. |
priceDropThresholdPct | 0 | Ignore price drops smaller than this percentage. Read the note above before raising it. |
onlyNewSinceLastRun | true | Emit only new or changed products. Turn it off to get every product's current state every run. |
trackPrice | true | Detect price moves, with the old value and the percentage. |
trackStock | true | Detect back in stock and out of stock. |
trackSalePrice | true | Detect a sale starting or ending, from the compare-at price where the store publishes one. |
trackTitle | true | Detect a title change under the same URL. |
notifyOnRestock | true | Send the webhook when something comes back in stock. |
notifyOnPriceDrop | true | Send the webhook on a price drop, respecting the threshold above. |
webhookUrl | empty | Slack, Discord, or any endpoint that wants the JSON. |
proxyConfiguration | on, using Apify's own network | Most stores answer without it. Change it only if a storefront gates you by region. |
📤 What you get back
A real row from a recent run:
{
"target": "snap-www.adafruit.com-fda349aa961c",
"label": null,
"url": "https://www.adafruit.com/product/3055",
"checked_at": "2026-08-22T07:52:20.183033+00:00",
"extraction_status": "ok",
"extraction_method": "json-ld",
"sync_status": "ok",
"current": {
"title": "Raspberry Pi 3 - Model B - ARMv8 with 1G RAM",
"price": 35,
"currency": "USD",
"list_price": null,
"on_sale": false,
"availability_raw": "http://schema.org/InStock",
"in_stock": true,
"sku": "3055"
},
"changes": [],
"change_count": 0,
"is_new": false,
"is_changed": false,
"error": null
}
| Field | What it is |
|---|---|
current | The product as it is right now. list_price and on_sale are filled in only where the store publishes a compare-at price. |
changes | One entry per detected move, each with a change_type and the before and after values. Empty when nothing moved. |
extraction_method | json-ld, shopify, woocommerce or microdata, so you can see which source the numbers came from. |
extraction_status | ok, no_structured_data when the page publishes none, or error when the store answered with an HTTP error. |
availability_raw | The store's own wording, kept beside the tidy in_stock boolean so you can check it. |
target | A stable key built from the URL. Use it to join runs together. |
is_new, is_changed | First time seen, or seen before with something different. |
🧾 Reading the output
Two kinds of row can land in your dataset.
| Row | How to spot it | Charged |
|---|---|---|
| A product | no _diagnostic key, and an extraction_status | yes, when extraction_status is ok |
| The run notice | _diagnostic: true and a status | no |
On a quiet run with onlyNewSinceLastRun on, the only row you get is the notice, which reads status: "no_changes" and counts what was checked. That row is never billed.
Two things to know about status. A URL that answers with an HTTP error comes back with extraction_status: "error" and is not charged. And a page that answers normally but carries no structured data comes back as no_structured_data, which also covers a consent or interstitial page that answered in place of the product, so check the URL in a browser if a store you expect to work reports it.
▶️ How to run it
1. Open Product Price & Stock Monitor and click Try for free. 2. Put your product URLs into Products to monitor, one object each, with a label you will recognise in an alert. 3. Turn Only new / changed since last run off for the first run so you can see the full shape. 4. Run it once, check the rows, then turn it back on. 5. Paste a Slack or Discord hook into Webhook URL and schedule it.
💰 How much does it cost?
$0.0025 per product checked. Flat on every Apify plan, no volume tiers. When something moves:
| Event | Price |
|---|---|
| Product checked | $0.0025 |
| Restock detected | $0.02 |
| Price, stock, sale-end or title change | $0.015 |
| Sale started | $0.015 |
| Page had no structured data | $0.001 |
| Run that found a change or delivered your webhook | $0.05 |
A product gets at most one change event per run, whatever moved. A URL that answers with an HTTP error is not charged at all, and the quiet-run notice row is free.
💡 What people use it for
- Watching a sold-out item and getting a Slack ping the minute it is back, which is what
back_in_stock plus notifyOnRestock is for.
- Tracking a competitor's list prices across a few dozen product pages, with the threshold at
0so
nothing is missed.
- Catching a supplier quietly relisting a different item under the same URL, using
title_change. - Watching when seasonal sales start and end across a set of stores, with
sale_startedand
sale_ended.
- Feeding a repricing sheet through the webhook, keyed on
target.
🚧 What it does not do
- It needs the store to publish structured product data. No JSON-LD, Shopify, WooCommerce or
microdata means no usable row.
- No HTML fallback. That is the design: selectors break silently and give you wrong prices.
- A price-drop threshold moves the baseline anyway, so a slow slide under the threshold is never
reported. Leave it at 0 if that matters.
- No product search or discovery. You supply the URLs.
- No variant-level tracking. It reads the product record the page publishes, not every size and
colour.
- No stock counts, only in stock or not, because most stores publish only that.
- No screenshots and no price history chart. The history is whatever you keep from the rows.
- The product list has no cap in the schema, so a very long list can run out of time. Split it
across several scheduled runs.
🧭 Which monitor do you need?
| If you want | Use |
|---|---|
| Price and stock on product pages you name | This one |
| Every product in a Shopify store | Shopify Products Scraper |
| Amazon prices and product detail | Amazon Scraper |
| New reviews on your own listings, triaged | App Review Triage Monitor |
❓ Questions people ask
Will it work on any store? Only on stores that publish structured product data, which is most Shopify and WooCommerce shops and a lot of others. Test one URL before you build a list on it.
How does it remember the last price? A named key-value store on your own account holds the baseline between runs. Nothing is kept on our side.
What happens the first time? Every product is new, so you get a full snapshot and no change events. Changes start from the second run.
Can I get Slack alerts? Yes, paste your Slack hook into webhookUrl and the format is picked up automatically. Discord too.
Why did a price drop not alert me? Check priceDropThresholdPct. A drop under the threshold is suppressed, and the baseline still moves.
Is monitoring public product pages legal? They are public pages and the data is what the store publishes about itself. Apify's write-up on scraping and the law is a sensible starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Send the run ID and the product URL. The row's extraction_status and extraction_method usually narrow it down on their own.