Shopify Product Tracker: New Products, Price Changes & Stock avatar

Shopify Product Tracker: New Products, Price Changes & Stock

Pricing

$50.00 / 1,000 store catalog reads

Go to Apify Store
Shopify Product Tracker: New Products, Price Changes & Stock

Shopify Product Tracker: New Products, Price Changes & Stock

Track any Shopify store's catalog: new products, price changes and what went out of stock. Paste a store URL and get one row per product with prices, variants and stock from the store's public product feed. Run it again to see what changed since your last run.

Pricing

$50.00 / 1,000 store catalog reads

Rating

0.0

(0)

Developer

FrameProbe

FrameProbe

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Share

A Shopify product tracker for any store: one row per product with prices, variants and stock, read from the store's public product feed. No login, no app to install, no API key. Run it again and each row says what changed since your last run: new products, price changes, what went out of stock and what came back.

What you'd do without this

  • Page through the store's feed, and stop before a 40,000-product store runs up your compute.
  • Match every variant to last week's, including renamed ones and ones recreated under the same SKU.
  • Never report a deletion from a read that stopped early.

Quickstart

{
"storeUrls": ["shop.example.com"],
"maxProductsPerStore": 1000
}

Schedule it daily or weekly with the same input and the same history store, and from the second run on every product row carries its changes.

What the first run returns

One row per product: productId, handle, title, productType, vendor; createdAt, updatedAt and publishedAt, each with its daysSince...; isNew and newFrom; variantCount, variantsAvailable, variantsOutOfStock, variantsAvailabilityUnknown, anyVariantOutOfStock, variantsOnSale; priceMin, priceMax; catalogComplete.

isNew is judged from the store's own dates, and stores do not all use them the same way, so it is marked confidence: "low". The first run needs no history to answer.

What runs two onward add

  • changeSinceLastRun: added, removed, changed or unchanged.
  • variantsAdded, variantsRemoved, variantsRenamed, variantsPriceUp, variantsPriceDown, variantsWentOutOfStock, variantsBackInStock, variantsUnmatched, and priceMinBefore / priceMaxBefore beside today's prices.
  • A product reads unchanged only when every variant paired with last run's and none moved.
  • A removed product gets its own row, and only when this run read the whole catalog.

Store rows

Each store ends with one row where rowType is store. It says whether the feed was read (status: ok, failed or skipped), how many products (productsRead), whether the read reached the end of the catalog (catalogComplete), and if not read, why (error). A store with an empty catalog still gets its store row, so no store you asked for is ever missing from the output.

Every row carries every key. A value that does not apply is null, never a missing key.

Example product row, second run

{
"rowType": "product",
"storeUrl": "https://shop.example.com",
"status": "ok",
"error": null,
"productsRead": null,
"productId": "7391234567890",
"handle": "classic-crew-sock",
"title": "Classic Crew Sock",
"productType": "Socks",
"vendor": "Example Co",
"checkedAt": "2026-09-10T16:00:00Z",
"createdAt": "2025-03-02T17:04:11Z",
"updatedAt": "2026-09-10T15:28:55Z",
"publishedAt": "2026-08-20T16:00:00Z",
"daysSinceCreated": 556,
"daysSinceUpdated": 0,
"daysSincePublished": 21,
"isNew": true,
"newFrom": "published_at",
"variantCount": 6,
"variantsAvailable": 5,
"variantsOutOfStock": 1,
"variantsAvailabilityUnknown": 0,
"anyVariantOutOfStock": true,
"variantsOnSale": 2,
"priceMin": "18.00",
"priceMax": "22.00",
"changeSinceLastRun": "changed",
"productRenamed": false,
"variantsAdded": 0,
"variantsRemoved": 0,
"variantsRenamed": 0,
"variantsPriceUp": 0,
"variantsPriceDown": 2,
"variantsWentOutOfStock": 1,
"variantsBackInStock": 0,
"variantsUnmatched": 0,
"priceMinBefore": "20.00",
"priceMaxBefore": "22.00",
"catalogComplete": true,
"basis": "snapshot",
"confidence": "high",
"caveats": [
"public products only: anything the store has hidden, unpublished or put behind a password is not listed here",
"isNew is judged from the store's own published_at timestamp, whose meaning has not been verified against a live store; see basis",
"a product the store hid since your last run is indistinguishable here from one it deleted, so this leans toward reporting REMOVED"
]
}

What it can't do, and which way it leans

  • A hidden product reads exactly like a deleted one, so removals are over-reported.
  • If the store removes or hides a product while a run is reading its catalog, one other product that is still for sale can be missed, and it shows as removed. This leans the same way as the line above: toward removals that did not happen. If a product shows as removed and is back on your next run, check it before you act on the removal. Every removed row says this in its caveats.
  • Some stores do not serve their public product feed. For those, the run reports the store as failed, never as an empty catalog, so a store that refuses is never read as one that deleted everything. A failed store is not charged.
  • Password-protected stores and unpublished products are invisible to it.
  • The feed does not say which currency its prices are in, so there is no currency column. Prices are exactly as the store wrote them.
  • Stock is yes or no per variant. The feed carries no quantities.

Two separate limits, neither inferred from the other

maxProductsPerStore caps how much of each catalog is read. A store bigger than that is read up to the cap and marked incomplete, and no removals are reported for it on that run. newWithinDays only decides what counts as new. Changing one never changes the other.

Reading close to 10,000 products per store needs more than the default 512 MB of memory: set the run to 1024 MB first. Our test read of 10,000 products from one store peaked at 431 MB, 84% of the default (measured on a local machine, not on Apify).

Where your history lives

In a named key-value store in your own Apify account, shopify-catalog unless you set historyStoreName. It holds the last catalog read from each store, as the product objects the store served. It is yours: read it, export it, or delete it to start over. Use a different name to keep separate histories side by side.

A store that fails on a run leaves its saved catalog untouched, so the next run still compares against the last catalog that was really read.

Pricing

One charge per store whose feed was read, whatever the catalog size. A store that refuses its feed, cannot be reached, or is skipped because your run's maximum charge had no room for it is not charged. There is no start fee. The amount is on the Pricing tab.

Input

FieldWhat it does
storeUrlsOne or more store addresses. Also accepted as storeUrl, stores, store, urls, url, domains, domain or startUrls, as a string, a list, or a list of {"url": ...} objects. Commas and new lines split a string. Up to 100 stores a run
newWithinDaysDays within which a product counts as new. Default 30
maxProductsPerStoreHard cap on products read per store. Default 1,000
historyStoreNameYour key-value store for the history. Default shopify-catalog