Shopify Price & Stock Change Monitor avatar

Shopify Price & Stock Change Monitor

Pricing

from $3.00 / 1,000 change-detecteds

Go to Apify Store
Shopify Price & Stock Change Monitor

Shopify Price & Stock Change Monitor

Watches Shopify stores and returns only what changed since the last run: price drops, price rises, out-of-stock, back-in-stock, new and removed products.

Pricing

from $3.00 / 1,000 change-detecteds

Rating

0.0

(0)

Developer

Duffy Radmilović

Duffy Radmilović

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

12 hours ago

Last modified

Categories

Share

Watches Shopify stores and returns only what changed since your last run — not another full catalog dump you have to diff yourself.

Point it at one or more Shopify storefronts, run it on a schedule, and each run tells you what dropped in price, what went out of stock, what came back, what is new and what is gone.

What makes this different

Other Shopify scrapers hand you a snapshot of a catalog. To spot a price drop you have to store yesterday's export, store today's, and compare them yourself.

This Actor keeps the previous catalog for you and does the comparison. A typical run on a store with 2,000 products returns a handful of rows, not 2,000 — and you pay for those few rows instead of the whole catalog, every single day.

How it works

Only public, documented Shopify endpoints are used:

endpointused for
/meta.jsonstore name, currency, and confirming the site really is Shopify
/products.json?limit=250&page=Nthe public product catalog, page by page

No login, no cookies, no captcha solving, no proxies, no AI. Plain HTTP and JSON.

The first run has nothing to compare against, so it saves a baseline and returns a one-row summary of the store: products, in stock, sold out, on sale, price range and the newest products. From the second run on you get the actual changes.

Get the changes in a Google Sheet every morning

Pair this Actor with Dataset to Google Sheets — No OAuth and every change lands in a spreadsheet you already use. No Google login, no token that expires.

  1. Create a task of this Actor with your competitors' stores and give it a daily Schedule.

  2. Share your Google Sheet (Editor) with the e-mail shown in the Sheets Actor's README.

  3. In this task → Integrations → connect an Actor → Dataset to Google Sheets — No OAuth, with input:

    {
    "spreadsheetUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit",
    "sheetName": "Price changes",
    "mode": "append",
    "datasetId": "{{resource.defaultDatasetId}}",
    "columns": ["detectedAt", "shopName", "changeType", "title", "variantTitle",
    "priceBefore", "priceAfter", "priceChangePct", "availableAfter", "productUrl", "message"]
    }

That's it: each morning the tab gets one row per change (price drop, restock, new product...), or a single NO_CHANGES row, so you can see the check ran. Tested end to end on 25 Sep 2026: this Actor's run started the Sheets Actor on its own, and 200 real change rows landed in the sheet in the column order above.

Cost for one store checked daily: about $0.01 for the check + $0.003 per change here, plus $0.025 for the sheet update, so roughly $1–1.50 a month.

Input

{
"shopUrls": [
"https://www.deathwishcoffee.com",
"https://allbirds.com"
],
"mode": "changes",
"watch": ["price", "availability", "new", "removed"],
"minPriceChangePct": 5,
"direction": "down",
"stateStoreName": "shopify-watch-state",
"requestDelayMs": 300
}
fielddefaultmeaning
shopUrls(required)Store URLs or bare domains.
modechangeschanges returns differences; snapshot returns the full catalog, one row per variant.
watchallWhich change types to report. Reporting fewer types costs less.
minPriceChangePct0Ignore price moves smaller than this, to cut noise.
directionanydown for price drops only, up for rises only.
maxProductsPerShop0Safety brake for huge catalogs. 0 means no limit.
maxChangesPerShop0Caps how many change rows one store can produce in a single run, so a site-wide sale cannot produce a surprise bill. 0 means no limit.
stateStoreNameshopify-watch-stateNamed key-value store holding the previous catalog. Runs that should be compared must use the same name.
resetStatefalseForget the baseline and start over.
requestDelayMs300Pause between requests to the same store.

Output

One row per change. The row below uses real product data from deathwishcoffee.com as captured by the Actor; priceBefore is the value the previous run had stored, which is what makes it a change:

{
"shopDomain": "www.deathwishcoffee.com",
"shopName": "Death Wish Coffee",
"currency": "USD",
"detectedAt": "2026-09-22T11:46:07.316Z",
"changeType": "PRICE_DROP",
"productId": "171104582",
"variantId": "392715452",
"handle": "valhalla-java-single-serve-pods",
"productUrl": "https://www.deathwishcoffee.com/products/valhalla-java-single-serve-pods",
"title": "Valhalla Java Single-Serve Pods",
"variantTitle": "10 count",
"sku": "5094SSC",
"vendor": "Death Wish Coffee Company",
"productType": "Coffee",
"tags": ["Intro Offer", "Single Serve", "Subscription", "Valhalla Java"],
"priceBefore": "16.99",
"priceAfter": "14.99",
"priceChange": -2,
"priceChangePct": -11.77,
"compareAtPrice": null,
"availableBefore": true,
"availableAfter": true,
"imageUrl": "https://cdn.shopify.com/s/files/1/0271/7209/files/Valhalla_Java_10ct_Angle_Vertical_Pods_A1_2.jpg?v=1733925456",
"publishedAt": "2021-02-12T12:07:04-05:00",
"productUpdatedAt": "2026-09-22T04:55:13-04:00",
"isFirstRun": false
}

changeType is one of:

valuemeaning
PRICE_DROP / PRICE_RISEa variant's price moved
OUT_OF_STOCK / BACK_IN_STOCKa variant's availability flipped
NEW_PRODUCT / REMOVED_PRODUCTa product appeared or disappeared
TITLE_CHANGEDa product was renamed
BASELINE_SAVEDfirst run for this store; nothing to compare yet
NO_CHANGESthe store was checked and nothing changed (free row, so an empty day is never mistaken for a failed run)
SNAPSHOTa row from snapshot mode

Errors are rows, not just log lines

A store that cannot be read does not fail the whole run and does not hide in the log. It produces a row you can filter on:

{ "shopDomain": "shop.tesla.com", "error": "BLOCKED",
"message": "Store blocked the request (HTTP 403) at https://shop.tesla.com/meta.json",
"detectedAt": "2026-09-22T11:45:29.318Z" }

Error codes: BAD_INPUT, NOT_SHOPIFY, BLOCKED, RATE_LIMITED, TIMEOUT, HTTP_ERROR, NETWORK_ERROR, TOO_LARGE, UNEXPECTED_ERROR, CHARGE_LIMIT_REACHED.

Pricing

Pay per event:

eventprice
Actor start$0.00005
Store checked$0.01
Change detected$0.003
Snapshot item$0.0003

Scanning a catalog costs the same whether anything changed or not, which is why a checked store is billed separately from the changes found. A quiet day is cheap; it is not free.

Example: 20 stores, checked daily, roughly 60 changes a day → 20 × $0.01 + 60 × $0.003 = $0.38 per day, about $11.40 per month.

Doing the same job with a catalog-dump scraper means exporting 20 × ~1,500 products at around $0.001 per product — roughly $30 for a single run.

If a store runs a site-wide sale, one run can legitimately produce thousands of changes. Use maxChangesPerShop, or Apify's own maxTotalChargeUsd, to put a ceiling on that.

Limitations — please read before buying

  • Your maximum cost per run is respected. When the next store would push the run over the limit you set, the Actor stops, bills nothing more, and adds a CHARGE_LIMIT_REACHED row listing the stores it did not check. If the limit is hit in the middle of one store's changes, the rest of that store's changes are held back and its baseline is not advanced, so they are reported on the next run instead of being lost.

These are real and measured, not boilerplate:

  • Roughly 10–20% of Shopify stores block automated requests. Tested on 10 random stores: 7 worked, 1 rate-limited, 1 returned HTTP 403, 1 was not Shopify. Blocked stores return a BLOCKED row. No proxies are used, so there is no way around this.
  • Exact stock levels are not available. Shopify's public products.json returns inventory_quantity: null. You get available: true/false only. Anyone promising public stock counts from this endpoint is guessing.
  • The first run reports no changes. It saves the baseline and returns a store summary. Changes start with run two.
  • Only Shopify stores. Other platforms return NOT_SHOPIFY.
  • About 100,000 variants per store is the ceiling, set by the 9 MB key-value record limit at roughly 90 bytes of stored state per variant. The Actor runs at 512 MB and processes the catalog page by page, so catalogs in the tens of thousands of variants are fine — a 22,777-variant store peaks at well under half the limit.
  • If maxProductsPerShop is set, products beyond the limit are invisible and are deliberately not reported as removed.
  • A partly downloaded catalog never overwrites the baseline, so a network hiccup cannot turn into a fake "everything was removed" report.
  • No personal data. Products, prices, and company information only.

FAQ

How much does it cost to monitor one store? One check is $0.01 plus $0.003 per change found. A store checked once a day with a few changes costs roughly $0.30–$0.50 a month. See the pricing table above.

How often should I run it? Once a day suits most competitor price tracking. Every few hours makes sense for restock alerts on fast-selling items. Running more often than hourly rarely finds more and costs more. Use an Apify schedule and keep the same stateStoreName so every run compares against the previous one.

Can I get a price drop or restock alert by email or Slack? Yes. Set watch to ["price"] with direction: "down", or ["availability"] for back-in-stock, then attach Apify's email, Slack or webhook integration to the Actor. It only fires when there is a row, and rows only exist when something changed.

What happens if a store blocks the Actor? You get a BLOCKED or RATE_LIMITED row for that store, the other stores still run, and the baseline for the blocked store is left untouched. You pay for the store check, not for changes that were never fetched.

How do I make sure a big sale doesn't produce a big bill? Set maxChangesPerShop, or set a maximum cost per run in the run options. The Actor stops cleanly at the limit and reports the rest on the next run.

Can it track a competitor's whole catalog, not just changes? Yes, mode: "snapshot" returns one row per variant. For ongoing competitor price tracking, changes mode is much cheaper.

Does it work on non-Shopify stores? No. Other platforms return a NOT_SHOPIFY row.

Uses public endpoints that Shopify serves to anyone. /products.json is not disallowed by the default Shopify robots.txt (verified). Respect the terms of the stores you monitor, and keep requestDelayMs at a polite value.