Shopify Price History & Fake Discount Tracker avatar

Shopify Price History & Fake Discount Tracker

Pricing

from $3.00 / 1,000 product trackeds

Go to Apify Store
Shopify Price History & Fake Discount Tracker

Shopify Price History & Fake Discount Tracker

Track Shopify product prices over time, get the 30-day lowest price, and flag inflated "was" prices. History starts with your first scheduled run.

Pricing

from $3.00 / 1,000 product trackeds

Rating

0.0

(0)

Developer

Viktor Kondas

Viktor Kondas

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

27 minutes ago

Last modified

Features

Limited permissions

Share

Track Shopify product prices over time, get the 30-day lowest price, and flag inflated "was" prices. Schedule it daily on the stores you watch: every run saves the price of every variant in your own Apify account, then tells you the 30-day low, whether the shop's compare-at ("was") price is consistent with it, and what changed since yesterday. Dataset, CSV, a one-click price history chart and optional webhook or Telegram alerts. $0.003 per product check, $0.02 per store snapshot, no subscription.

Independent tool. Not affiliated with Shopify or any store. Reads each store's public product feed only — no login, no cart, no personal data. Information tool, not legal advice.

Start your log before Black Friday

Past prices cannot be recovered for most shops, so your history starts with your first scheduled run. Run 1 is a baseline: it saves today's prices and returns no warning, just a clear message ("Baseline saved for N products. Schedule this task daily. 30-day lows become reliable after 30 days of runs."). From run 2 you get changes; after about 30 days of daily checks the 30-day low and the discount verdict are fully backed by data.

Black Friday is 27 November 2026 — a schedule started now has roughly two weeks of history by then. The status of every number says how complete it is (lowest30dStatus: full, partial or none), so a short history never looks like a full one.

Quick start

  1. Open the task 30-day lowest-price log, replace the example shops with the Shopify store URLs you want to watch (a domain, a homepage, a product URL, or a collection like /collections/sale).
  2. Click Start. Run 1 saves your baseline. Open the dataset, the Price history chart and the CSV export from the run's output tab.
  3. Click Schedule → daily (for example 06:00). Keep the same shop URLs and the same History store name, so the history keeps growing.

Every run writes to a named key-value store in your account (default shopify-price-history). Named stores do not expire.

Get alerts, not spreadsheets

Use the task Competitor price-drop alerts (outputMode: changesOnly, minDropPct: 5). It returns only variants that really changed: price drop or rise, new, back in stock, out of stock, removed, or a newly inflated discount. Small moves under minDropPct are still recorded in history but are not reported.

  • Webhook or Telegram (only when something changed): fill in webhookUrl, or telegramBotToken + telegramChatId. You get one summary message per run that had changes and nothing on quiet days.
  • Apify integrations: connect the built-in email or Slack integration to the task (Integrations → add → run succeeded). Because the dataset only holds real changes, an attached dataset is empty on quiet days. The webhook/Telegram inputs above are the way to be notified only when something changed.
  • Every run also writes a CHANGES record (counts per change type plus the changed items) to the run's key-value store.

What you get

One dataset item per variant per run (rowType: product), plus one summary item per store (rowType: store). Variants are tracked by their Shopify variant ID, so a renamed product handle keeps its history.

FieldMeaning
store, title, handle, variantId, variantTitle, sku, productUrlWhich variant (handle and titles are refreshed each run; variantId is the history key)
price, compareAtPrice, currency, availableCurrent price, the shop's "was" price, ISO 4217 currency, in stock
lowest30d, lowest30dStatus, checkedDays30d, historyDaysCoveredLowest price of the last 30 days and how complete that window is
discountVerdict, saleStartedAt, referenceLowest30d, claimedDiscountPct (discountPct), actualDiscountPctIs the "was" price consistent with the lowest price of the 30 days before the sale?
changeType, previousPrice, priceChangePct, baselineWhat changed since the previous check
removed, removedAtThe variant is no longer returned by a completed check (history kept)
chartUrlLink to the price history chart (see below)

Legacy fields from earlier versions keep working: promoStatus, onSaleSince, daysOnSale, lowestPriceSeen30d (same value as lowest30d), regularPriceObserved, referenceInflationPct, inflatedReference (now set from the verdict: true, false, or null when there is not enough history).

lowest30dStatus — full: 27+ checked days in the last 30 and no gap longer than 2 days · partial: some history, or gaps (missed runs hide anything that happened between checks) · none: first sighting.

discountVerdict — consistent: the compare-at price is within tolerance (default 1%) of the lowest price in the 30 days before the sale started · inflated_reference: it is higher · insufficient_history: fewer than 27 checked days (or a gap longer than 2 days) before the sale — the partial numbers are still returned · no_discount: no compare-at price above the price.

changeType — new (variant first seen after the baseline) · price_drop · price_rise · new_inflated_discount (verdict became inflated_reference) · back_in_stock · out_of_stock · removed · none.

CSV and chart (not charged). Every run writes price-history.csv (long format, one row per price change: shop, product_handle, product_title, variant_id, variant_title, sku, currency, timestamp, price, compare_at_price, available) and price-history.html (one small step-line chart per product: price, the shop's "was" price as a dashed line, the 30-day low as a marked level; up to 50 charts sorted by the largest recent price movement, the rest are in the CSV). The chart is a single self-contained page: no scripts, fonts or external requests; light and dark mode; readable on a phone. Both files appear in the run's output tab and in your history store (chart-<shop>, csv-<shop>) for a stable location. The links are for the account owner when logged in — the storage is private and there are no public or shareable chart links.

The EU 30-day rule

Under the EU price-indication rules (Directive 98/6/EC as amended by the Omnibus Directive 2019/2161), an announced price reduction must reference the lowest price the seller applied in the 30 days before the reduction. This tracker compares each shop's "was" price with the lowest price it recorded itself in the 30 days before the sale started (referenceLowest30d) and tells you how much history backs that comparison. It is an information tool, not legal advice; member states allow some exceptions (for example for perishable goods, products on the market for less than 30 days, or progressive reductions).

Who uses it

  • Sellers watching competitors — see price drops, new products and sales the day they happen.
  • Brands checking resellers — find out whether a reseller's "was" price was ever charged.
  • Journalists and consumer groups checking Black Friday claims — evidence with a verdict, a history window and a CSV.

Pricing

Pay per event, no subscription: $0.003 per product check (per product — a product with 12 variants is one charge) and $0.02 per store snapshot (one summary item per store per run). Reading the catalog, retries, the CSV, the chart, the changes record, removed-variant items and alerts are free; shops that cannot be read are free.

Examples with every product delivered each day (mode: all): 300 products in one store checked daily ≈ $27.60 per month; 1,000 products ≈ $90.60 per month. outputMode: changesOnly charges only the products that changed (plus the store snapshot of a store that had changes — a quiet run pushes and charges nothing), mode: summary only the store snapshot. Use Max products per run (maxProducts) as a hard cost cap and Max products read per shop (scanLimitPerStore) to limit large shops. Set Max cost per run in the Run options as a hard limit.

Input

FieldDescription
storeUrlsShopify stores: domain, homepage, product URL (whole store), collection URL (that collection only) or market sub-folder like /en-de. Can import a list from a text file / Google Sheet CSV. Max 500 per run.
historyEnabledKeep price history (default on). Legacy alias trackHistory; history is off if either is off
historyStoreNameNamed key-value store in your account (default shopify-price-history). Tasks that share a name share (and merge) their history
outputModeall (default) or changesOnly — only variants whose changeType is not none
minDropPctPrice moves smaller than this are recorded but reported as none (default 5)
maxProductsCap on products delivered across all stores — your cost cap (default 200)
scanLimitPerStoreProducts read per shop, 250 per request, free (default 5,000). A capped or failed scan is not counted as a completed check
webhookUrl, telegramBotToken, telegramChatIdOptional summary alert, only when something changed
modeon-sale (default) · all · changes (legacy: sale started / deepened / ended …) · summary (store rows only)
maxProductsPerStore, minDiscountPct, includeStoreSummaryPer-store cap, minimum discount, store summary item ($0.02) on/off
referenceTolerancePctHow far the "was" price may exceed the pre-sale 30-day low before it is flagged (default 1)
proxyConfigurationResidential proxy is recommended for big catalogs; direct egress often gets HTTP 429

FAQ

Why is my first run empty of history? Run 1 is a baseline: there is nothing to compare with yet, so the 30-day fields are empty and baseline is true. This is not an error. From run 2 on you get changes; the 30-day low is reliable after about 30 days of daily checks.

Can I get prices from before I started? No. The tracker only knows the prices it saw itself. Your history starts with your first scheduled run.

What happens if a scheduled run fails? That day is not counted as a completed check, nothing is marked as removed, and lowest30dStatus shows partial until the window is covered again. A scan that hits scanLimitPerStore or a page that keeps failing (HTTP 429/5xx after up to 5 retries) is treated the same way.

Can two tasks track the same shop? Yes. Before saving, the tracker re-reads the record and merges it (union of price points and check dates), so concurrent tasks on the same shop and store name do not overwrite each other.

Does it work on every Shopify store? No. It needs the public /products.json feed. Password-protected shops, some headless stores and shops that disallow it in robots.txt are returned as a free item with the reason.

Where is my history stored and what if I delete it? In a named key-value store in your Apify account (default shopify-price-history), one record per shop (large shops are split into numbered records). Delete the store or a record and that shop starts a new baseline. Let the Actor create the store on its first run — an Actor with limited permissions cannot open a store you created by hand.

What if a shop changes currency, or shows different prices by country? Shopify Markets can localise prices (and currency) by the visitor's country. The tracker records the currency the shop actually presents and, with an Apify proxy, pins the proxy's exit country to the shop's own country (override it in the proxy settings). If the presented currency still changes, the old series is closed and a new baseline starts; currencies are never mixed in one series.

Does it cover Amazon? No — Shopify stores only.

Why is onSalePct 0 on a shop that runs Black Friday? Many shops apply Black Friday discounts at checkout (codes, automatic discounts) instead of marking products down. Those never appear in the public product feed.

Can you add a field or fix a store? Yes — open an issue with the store URL.

Limitations

  • Shopify stores only, through the public product feed. Discounts applied at checkout (codes, bundles, "buy 2 get 1") are not visible there.
  • Prices are in the store's primary currency and market. Market sub-folders such as /en-de work only where the shop serves its feed there.
  • The 30-day verdict needs 27+ checked days before the sale; before that you get insufficient_history and the partial numbers.

Built by Viktor Kondas · Vibe Coder's Life · Custom work: hello@vibecoderslife.com