Unadhi Guides

Competitor discount sheet: which products a Shopify or WooCommerce store has on sale, and by how much

Updated 19 Oct 2026 · Disclosure: the product tracker linked below is an Unadhi product on the Apify Store. This guide is free, and the sheet works with a CSV from any tool or one you build by hand. Current Apify pricing is only on the Store page.

What you get: one Google Sheet (or Excel workbook) called a discount sheet with three tabs you actually read: on_sale (every discounted product in your competitors' stores, biggest discount first, with price, compare-at price, discount % and stock), stores (per store: products, products on sale, share of the catalogue on sale, median and largest discount) and history (one row per store per week, so you see the day a sale starts). You paste one product CSV into a raw tab; formulas do the rest. Setup is about 30 minutes; each later week takes about five.

The finished discount sheet

on_sale tab

StoreProductPriceCompare-atDiscountIn stock
competitor-a.exampleLinen shirt, sand1,4992,49940%TRUE
competitor-b.exampleCanvas tote8991,19925%TRUE
competitor-a.exampleCotton kurta, navy1,7991,99910%FALSE

stores tab

StoreProductsOn saleShare on saleMedian discountLargest discount
competitor-a.example2403615%20%40%
competitor-b.example8545%25%25%

Example rows only, to show the layout. Not real store data.

Why bother before Black Friday

Black Friday 2026 is Friday 27 November and Cyber Monday is 30 November. Many stores mark products down days or weeks earlier, and festive sales in other markets run on their own calendars. A weekly discount sheet answers three practical questions without guessing:

How "on sale" works in store data

Step 1: pick the stores and get one product CSV

Pick 3 to 10 stores your customers really compare you with. Use each store's homepage (the whole catalogue), not just its sale page, or you cannot work out the share on sale.

Free, one or two stores

Open /products.json?limit=250&page=1 on a Shopify store, or /wp-json/wc/store/v1/products?per_page=100 on a WooCommerce store, and copy title, URL, price and compare-at (or regular) price into a sheet with the column names used below. Step-by-step: export a Shopify store's products to CSV and export a WooCommerce store's products to CSV. If a store returns 401, 403 or 404 there, or its robots.txt or terms forbid scraping, leave it out.

No code, several stores at once (Apify)

  1. Create a free Apify account (no card needed for the free plan; see apify.com/pricing for current free monthly usage).
  2. Open Shopify & WooCommerce Product + Price Tracker and click Try for free.
  3. Paste your store list. In JSON view:
{
  "startUrls": [
    { "url": "https://competitor-a.example" },
    { "url": "https://competitor-b.example" }
  ],
  "maxProductsPerShop": 2000,
  "maxListingPages": 20,
  "includeDescription": false
}

Set maxProductsPerShop above each store's real catalogue size, otherwise the share on sale is worked out on part of the range. Turn descriptions off; this sheet does not need them. When the run finishes, open the dataset and choose Export → CSV. The columns used here are shop, title, url, price, compareAtPrice, onSale, currency and inStock. Also open the run's SHOPS_SUMMARY record: it says which stores were read and which were skipped (for example because robots.txt or the store's terms forbid scraping). Skipped stores are simply missing from the sheet.

To run the same store list every week, save the input as an Apify Task and, if you like, add a weekly Schedule for it; then you only download the CSV.

Step 2: import it into a tab called raw

Step 3: add a COL helper (one-time)

CSV column order can change between exports, so pick columns by header name. Same helper as in the call sheet guide:

=IFERROR(XLOOKUP(h, raw!$1:$1, raw!$2:$5000), "")
=LAMBDA(h, IFERROR(XLOOKUP(h, raw!$1:$1, raw!$2:$5000), ""))

Raise 5000 if your stores together list more products than that.

Step 4: work out each discount (the rows tab)

Add a tab called rows, type these headers in row 1 and each formula in row 2. In Excel 365 the formulas spill on their own; leave out ARRAYFORMULA.

ColHeaderFormula in row 2
Astore=COL("shop")
Bproduct=COL("title")
Cprice=COL("price")
Dcompare-at=COL("compareAtPrice")
Ediscountsee below
Fin stock=COL("inStock")
Gcurrency=COL("currency")
Hlink=COL("url")

E: discount (blank when there is no real markdown)

=ARRAYFORMULA(IF(A2:A="", "", IF((C2:C>0)*(D2:D>C2:C), 1-C2:C/D2:D, 0)))

Format column E as a percentage. A product only counts as discounted when it has a price and a compare-at price higher than that price; everything else gets 0. The tracker's own onSale column should agree; if a row has onSale TRUE but no compare-at price, open the product page and check.

Step 5: the on_sale and stores tabs

on_sale: every discounted product, biggest first

Copy the headers from rows into row 1 of a new tab on_sale, then in A2:

=SORT(FILTER(rows!A2:H, rows!A2:A<>"", rows!E2:E>0), 5, FALSE)

Want only discounts of 20% or more? Change rows!E2:E>0 to rows!E2:E>=0.2. Want only products still in stock? Add , rows!F2:F=TRUE inside the FILTER.

stores: one row per store

New tab stores, headers Store, Products, On sale, Share on sale, Median discount, Largest discount. Then:

CellFormula (fill B2:F2 down as far as the store list goes)
A2=SORT(UNIQUE(FILTER(rows!A2:A, rows!A2:A<>"")))
B2=IF(A2="", "", COUNTIF(rows!A:A, A2))
C2=IF(A2="", "", COUNTIFS(rows!A:A, A2, rows!E:E, ">0"))
D2=IF(A2="", "", C2/B2)
E2=IF(OR(A2="", C2=0), "", MEDIAN(FILTER(rows!E2:E, rows!A2:A=A2, rows!E2:E>0)))
F2=IF(OR(A2="", C2=0), "", MAX(FILTER(rows!E2:E, rows!A2:A=A2)))

Format D, E and F as percentages. Mixed currencies do not matter here: every figure is a ratio inside one store.

history: a weekly snapshot (two minutes)

Add a tab history with headers Date, Store, Products, On sale, Share on sale, Median discount, Largest discount. Each week after the import, select stores!A2:F, copy, and in the first empty row of history use Paste special → Values only starting in column B, then type the date in column A for those rows. Over four or five weeks this shows exactly when each store started its sale and whether it is getting deeper. A line chart of Share on sale per store makes it obvious at a glance.

Step 6: optional, products you both sell

If you stock the same branded products, add a tab mine with your own SKU or GTIN in column A and your price in column B. The tracker exports gtin and sku when the store publishes them. In rows add column I =COL("gtin") and column J:

=ARRAYFORMULA(IF(I2:I="", "", IFERROR(VLOOKUP(I2:I, mine!A:B, 2, FALSE), "")))

Column J then shows your price next to every competitor product with the same barcode, so you can filter for "they are cheaper than us and on sale". If GTINs are blank, match by eye on title; never assume two products are identical from a similar name.

Step 7: read it carefully before you react

What not to do

This guide is general information, not legal advice. You are responsible for how you use the data and for following each site's terms and your local law. The Apify Actor mentioned reads only public product pages, uses an honest bot User-Agent, follows robots.txt, checks each store's terms, never logs in and never gets around blocks.

Partner programme opening soon

Partner programme opening soon: join the free waitlist. Planned terms are 50% of each referred sale (75% once you have 5+ paying customers), single level, paid through Gumroad only from revenue received.

Related

← All guides

Unadhi Guides are free, independent explainers. We correct errors as soon as we find them: write to mininglife7@gmail.com.