Shopify Product Monitor: Price Drops, Stock and New Products avatar

Shopify Product Monitor: Price Drops, Stock and New Products

Pricing

from $0.50 / 1,000 product variant returneds

Go to Apify Store
Shopify Product Monitor: Price Drops, Stock and New Products

Shopify Product Monitor: Price Drops, Stock and New Products

Shopify products scraper and price monitor. Competitor price tracking for any store: one row per variant with price, compare-at price and stock, then only the price drops, back in stock alerts, new and removed products since the last run. Alerts to Discord, Slack or Telegram; rows to Google Sheets.

Pricing

from $0.50 / 1,000 product variant returneds

Rating

0.0

(0)

Developer

Adrian Voss

Adrian Voss

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Watch any Shopify store, get only what changed. One row per product variant with price, compare-at price and stock, then, on every later run, only the variants that got cheaper, dearer, came back in stock, sold out, appeared or vanished. A quiet check costs only the start fee. Schedule it and it posts each change to Discord, Slack or Telegram, or feeds Google Sheets and n8n.

This is a Shopify products scraper and a Shopify price monitor in one actor. Give it store domains (or links to a collection); it reads each store's public catalog, flattens every product into one row per variant (size, colour), and remembers each variant's price and stock between runs. No login, no API key, no store access: it reads the same public catalog page a browser can open at /products.json.

Who it's for

  • Ecommerce teams doing competitor price tracking. Watch the stores you compete with, get a message the day a rival cuts a price or runs out of your product's closest alternative.
  • Deal hunters and resellers who want a back in stock alert on a sold-out size or a drop on a watched item, without refreshing a product page.
  • Dropshippers and marketplace sellers monitoring a supplier's catalog for price rises, new products and delistings.
  • Analysts and agencies who need a clean catalog export (one row per variant, SKU, vendor, type, tags, compare-at price, discount) for a list of stores, again and again.

Why this one

  • One row per variant, not per product. A hoodie in five sizes is five rows, each with its own price, SKU and stock flag, because that is where prices and stock actually change.
  • Changes only, and you are billed only for them. Turn on monitoring and unchanged variants are removed before billing. The first run remembers everything; every later run returns the variants that are new, cheaper, dearer, back in stock, out of stock or removed, whichever of those you pick.
  • Alerts in your channel. Paste a Discord or Slack webhook or a Telegram bot link and each change arrives as its own message with photo, size, price, was-price and link. The messages are free.
  • Honest failures. A domain that is not on Shopify comes back as NOT_SHOPIFY, a Shopify store that switched its catalog off as PRODUCTS_HIDDEN, a store that rate-limits you as BLOCKED. None of them is ever billed.
  • Store currency included. Every row carries the store's currency, read from the store's own /meta.json (falling back to /cart.js), with currencySource saying which one answered.
  • Scoped to what you care about. Read a whole store, a list of collection handles, or paste a collection link.

What you get

One dataset row per variant (One row per variant is on by default), for example:

FieldMeaning
storeThe store domain you gave
productId, variantIdShopify's numeric ids
title, variantTitleProduct name and the variant (size, colour); variantTitle is empty for single-variant products
vendor, productType, tags, handleCatalog data as the store publishes it
urlLink to the product with ?variant=<id> so it opens on that variant
skuThe variant's SKU, empty if the store does not publish it
price, compareAtPrice, discountPct, currencyCurrent price (a number), the crossed-out price, the percentage off, the store currency
availableIn stock or not, as the storefront shows it
imageUrl, publishedAt, updatedAtThe variant's image (or the product's first image) and the product's dates
changeType, changesWith monitoring: new, price-drop, price-rise, back-in-stock, out-of-stock or removed, and every change found on the variant
previousPrice, priceDeltaPct, previousAvailable, firstSeenAtWhat the last run saw, the percentage move (negative for a drop) and when the variant was first seen

Each row also repeats a few store-level fields: productCount, totalVariants, variantCount, truncated and monitorStatus. Turn off "One row per variant" and you get one row per store with all its variants in a variants list instead.

Rows are variants. A store's 250 products are not 250 rows: in testing, the first 250 products of kyliecosmetics.com came to 709 variants, gymshark.com to 1,685 and allbirds.com to 2,720. Use maxProducts (or the general "Stop after this many results") to set the size of a run, and monitoring to pay only for what changed.

Monitoring: price drops, back in stock, new and removed

Tick Only return variants that changed since the last run (deltaMode) and give the run a stable deltaName if you like (otherwise one is derived from your alert settings). Each store keeps its own memory in a named key-value store, one record per store and per collection scope.

ChangeMeaning
newA variant the watchlist has not seen before (every variant, on the very first run)
price-dropThe price fell since it was last seen; priceDeltaPct is negative
price-riseThe price went up; priceDeltaPct is positive
back-in-stockavailable went from false to true
out-of-stockavailable went from true to false
removedThe variant used to be in the catalog and is not any more (the product was deleted, unpublished, or left the collections you watch)
  • Pick which of these count in Alert me on (alertOn); all six are on by default. Only those are returned and billed.
  • Smallest price change to count ignores rounding noise (a 1% floor, say).
  • A variant that changed in two ways, cheaper and back in stock, is one row: changeType is the first match you asked for and changes lists both.
  • Removed is reported only when the run read the store to its last page. A run stopped by maxProducts, the time budget or a failed page declares nothing removed, so a capped run never invents deletions. A removed variant is reported once and forgotten 30 days after it was last seen.
  • The first run returns every variant as new. Turn on Remember silently on the first run (skipFirstRun) to bank the baseline and return nothing, so alerts start with the second run.
  • Monitoring remembers every variant it saw, up to whatever the store has (a store with tens of thousands of variants makes a large memory record: watch its collections instead).
  • A quiet run returns one summary row per store (monitorStatus: NO_CHANGES, variantCount: 0) and is charged only the start fee. Set quietRunOutput to none and a quiet run's dataset is empty.

Send Shopify alerts to Discord, Slack or Telegram

Paste a link in Send alerts to (notifyUrl) and every changed variant is posted as one message: photo, title, size or colour, price with the was-price, stock, store and link, with a badge such as PRICE DROP -20% or BACK IN STOCK.

  • Discord or Slack: the channel's webhook URL.
  • Telegram: https://api.telegram.org/bot<token>/sendMessage?chat_id=<chat id>.
  • Anything else (n8n, Make, Zapier, your own bot) receives the alert as JSON.

Up to maxNotificationsPerRun messages go out per run (20 by default); above that one "+N more" message says how many more variants are in the run's dataset, so a busy first run never floods a channel. Messages are free. A message that fails never fails the run: the row's notifyErrors says why. The link is stored encrypted and never logged or written to the results. Messages go out only when monitoring is on.

Collections

Leave Only these collections empty to read each store's whole catalog. Or list collection handles (sale, new-arrivals) or collection links, and only those collections are read for every store. A store line that is itself a collection link, such as https://kyliecosmetics.com/collections/award-winners, reads just that collection. Each collection scope keeps its own watchlist memory, so a product that leaves the collection is reported as removed even though it is still in the store.

Price

Pay-per-event. A flat per-run fee covers session/proxy warmup; you're billed per item only when data is actually found and returned — see .actor/pay_per_event.json for exact prices. A miss is never charged.

You pay per variant row returned, and only for rows that come back: a store that is not Shopify, has its catalog switched off or blocks the run is free, and in monitoring mode only changed variants are billed. Rows are variants, not products (see "What you get"), so set maxProducts to the size you want.

How to use

  1. In the Apify Console. Open the actor page and click Start — the stores field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
  2. Via the API. Call it directly with a POST request — no Console needed once you have an API token:
    curl "https://api.apify.com/v2/acts/accountable_eel~shopify-product-monitor/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"stores":["https://kyliecosmetics.com/collections/award-winners"]}'
  3. On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.

Input

{
"stores": [
"https://kyliecosmetics.com/collections/award-winners"
]
}

One store per line: a domain such as allbirds.com, or a store link (a link ending in /collections/

The other fields are optional: maxProducts (default 250, up to 10,000), collections, deltaMode, deltaName, alertOn, minPriceChangePct, skipFirstRun, quietRunOutput, notifyUrl, notifyFormat, maxNotificationsPerRun, plus the usual result filters and the proxy setting.

Shopify stores answer ordinary requests, so the proxy is off by default and most runs need none. If a store comes back as BLOCKED, switch on Apify Proxy (datacenter). Avoid Residential proxies: every catalog page is about 1.8 MB.

Output

One row per variant, for example:

queryfoundstatusstorecurrencycurrencySourceproductCounttotalVariantsvariantCounttruncatedtruncatedBymonitorStatusnewCountpriceDropCountpriceRiseCountbackInStockCountoutOfStockCountremovedCountvariantsproductIdvariantIdtitlevariantTitlevendorproductTypetagshandleurlskupricecompareAtPricediscountPctavailableimageUrlpublishedAtupdatedAtscrapedAt
https://kyliecosmetics.com/collections/award-winnerstrueOK<variants returned (billed)><all variants (grouped mode)><variant (size, colour)><discount %>1970-01-01T00:00:00.000Z

A store that could not be read comes back as one row with "found": false and a status: NOT_SHOPIFY, PRODUCTS_HIDDEN, BLOCKED, BAD_FORMAT (not a domain) or REQUEST_FAILED. It is never charged.

Example runs

Three inputs that need no key and return rows as they stand. Paste one into the Input tab and press Start.

1. A price and stock snapshot of one collection

{
"stores": ["https://kyliecosmetics.com/collections/award-winners"]
}

2. Competitor price tracking on two stores, first 50 products each

{
"stores": ["allbirds.com", "gymshark.com"],
"maxProducts": 50,
"deltaMode": true,
"deltaName": "competitors",
"alertOn": ["price-drop", "back-in-stock"],
"minPriceChangePct": 2
}

The first run stores the baseline and returns one summary row per store (monitorStatus: FIRST_RUN, nothing billed beyond the start fee). Schedule it daily, and from the second run you get only the price drops and back in stock variants, and pay only for those.

3. Only the sale collection of a store, as one row per variant

{
"stores": ["gymshark.com"],
"collections": ["2-in-1-shorts"],
"maxProducts": 40
}

Use it from Google Sheets, Clay, n8n, Make, or an AI agent

Append each run's rows to a Google Sheet with Apify's Google Sheets integration (or Make, n8n or Zapier) for a running price log, or export the dataset to CSV or Excel. Use the changes dataset view for a price and stock alert list and the products view for the catalog.

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

curl "https://api.apify.com/v2/acts/accountable_eel~shopify-product-monitor/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
-X POST \
-H "Content-Type: application/json" \
-d '{"stores":["https://kyliecosmetics.com/collections/award-winners"]}'

n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~shopify-product-monitor/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"stores":["https://kyliecosmetics.com/collections/award-winners"]} (swap in an expression from an earlier node for a real value).

Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~shopify-product-monitor/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"stores":["{{store}}"]}, mapping the row's store into the stores array.

MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Shopify Price Monitor: Price Drops and Stock Alerts" — the agent will find and run this actor.

vs. alternatives

What it costsWhat you getTrade-off
This actorOne event per variant row, changed rows only in monitoring mode; quiet runs cost the start feeOne row per variant, price and stock changes, back in stock alerts, removed variants, alerts to Discord, Slack or TelegramPublic catalog data only: no exact inventory counts
Shopify Products Scraper (trovevault)$0.001 per product on the free plan, $0.00085 on GoldCatalog export per product, 87 users last monthNo memory between runs: you diff snapshots yourself
Shopify Product Price and Stock Change Monitor (redfoxxie)$0.005 per delivered change, flatA change monitor2 users last month; five times this actor's per-row price on the free plan
Paid price-tracking servicesUsually a monthly subscriptionAlerts in their dashboardYou do not own the data or the filters, and cannot feed your own sheet or bot

Store figures as of September 2026.

Data & privacy

This actor reads the public product catalog that every Shopify store publishes at /products.json and /meta.json, the same data your browser can open without logging in. It does not log in, solve CAPTCHAs or read anything behind a password, and it returns no customer data. Some stores switch the catalog off or protect it; those are reported, not bypassed. Check that your use fits the store's terms and your local law. Not affiliated with Shopify.

FAQ

Is it really one row per variant? Yes. Each size or colour is its own row with its own variantId, sku, price and available flag. That is also what you are billed for, so use maxProducts to size a run.

Why did my monitoring run return nothing? Nothing changed since the last run. You get one row per store with monitorStatus: NO_CHANGES (or no row at all with quietRunOutput: "none") and are charged only the start fee. On the first run with "Remember silently" on, the status is SEEDED.

What does PRODUCTS_HIDDEN mean? The domain is a Shopify store, but it has switched off its public /products.json (headless and Plus stores often do), it is empty, or it is behind a storefront password. There is no public catalog to read.

What does NOT_SHOPIFY mean? /products.json did not exist and the page shows no sign of Shopify. It is worth checking the domain: some Shopify stores run their catalog on another domain (a shop. or checkout host).

A store is BLOCKED. What now? The store rate-limited the run (HTTP 429) or a bot filter refused it (403). Try again shortly, lower "Max concurrency", or switch on Apify Proxy (datacenter).

Are prices in the store's currency? They are the prices /products.json publishes, in the currency Shopify reports for the shop. That currency is in the currency column, and currencySource says whether it came from /meta.json or /cart.js. A store that converts prices for shoppers by location may show a different amount on its website.

Why is truncated true? The run stopped before the end of the catalog: it hit maxProducts, the time budget or a failed page. truncatedBy says which. The rows it did read are delivered and billed; nothing is declared removed on a truncated run.

Does it give exact stock counts? No. Shopify's public catalog says only whether a variant is available, not how many are left.

Can an AI agent call this? Yes, through the Apify MCP server or the API call shown above. Ask for "Shopify Product Monitor: Price Drops, Stock and New Products".