AU Grocery Price Comparison - Cheapest retailer + Price History avatar

AU Grocery Price Comparison - Cheapest retailer + Price History

Pricing

from $3.00 / 1,000 product prices

Go to Apify Store
AU Grocery Price Comparison - Cheapest retailer + Price History

AU Grocery Price Comparison - Cheapest retailer + Price History

Prices a shopping list across every Australian retailer holding each item, names the cheapest and dearest shop with the saving worked out, judges today's price against that product's own history, and totals the whole basket per retailer against buying each item wherever it is cheapest.

Pricing

from $3.00 / 1,000 product prices

Rating

5.0

(1)

Developer

GatherWorks

GatherWorks

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

12 days ago

Last modified

Categories

Share

๐Ÿ›’ AU Grocery Price Comparison โ€” Cheapest Retailer + Price History

Name the products. Get back where each one is cheapest, how much you save by not buying it at the dearest shop, and whether today's price is actually a good one.

Swept daily, kept since March 2024. Coles, Woolworths and ALDI are re-priced every day and every price is retained โ€” 30 million observations and counting โ€” so you get today's shelf price and the two and a half years behind it. Every figure carries the date it was seen, and every product can be judged against what it has actually cost.


๐Ÿ” What is it?

Give it a shopping list. For each item it finds the product, prices it at every retailer holding it, then does the part you would otherwise do by hand:

  • ๐Ÿฅ‡ names the cheapest shop and the dearest, and works out the gap
  • ๐Ÿ•ฐ๏ธ places today's cheapest price in that product's own price range over 7 days to 2 years
  • ๐Ÿงบ totals the whole list per retailer, and tells you what one trip costs against cherry-picking

โšก What can it do?

  • ๐Ÿช Compare across retailers in one call. Coles, Woolworths, ALDI and marketplace sellers sit in the same database, so a single item comes back priced at all of them together.
  • ๐Ÿ’ธ Quantify the saving. spreadCents and savingPct say what the difference is actually worth, per item.
  • ๐Ÿ“‰ Say whether it is a good price. verdict is good-price, typical or poor-price โ€” judged against the low, median and high that product has really held, not against a guess.
  • ๐Ÿงบ Price the whole basket. Which single shop is cheapest for everything, and how much more that is than buying each item wherever it is cheapest.
  • ๐Ÿ”„ Swept daily. The major chains are re-priced every day, so a row is typically hours old, not weeks โ€” and observed and staleDays say exactly how old rather than leaving you to assume.
  • ๐Ÿ“… Date every price. A price with no timestamp is a claim, not a fact.
  • โš–๏ธ Refuse a comparison it cannot make honestly. See below โ€” this is the part most price tools get wrong.

๐ŸŽฏ It refuses rather than guesses

Three refusals are built in, and each protects you from a number that looks authoritative and is not:

RefusalWhy
๐Ÿšซ A price you cannot act on never winsA tracker's own "lowest across retailers" figure is a real observation and not a shop. Naming it "cheapest" would send you to a checkout that does not exist.
โฑ๏ธ Prices seen days apart are flagged, not mergedcomparable: false and observationGapDays ride on the row. Two prices seen a week apart are two facts, not a comparison.
๐Ÿคท A thin history gets no verdictIf the database holds no price for most of the window, verdict is unknown and verdictBasis says exactly how much was missing. A confident call off one data point is not one we have earned.

โŒจ๏ธ Inputs

InputTypeDefaultWhat it does
๐Ÿ›’ queriesstring[]โ€”Required. One product name per line, matched against product names in the database
๐Ÿ”ข matchesPerQueryinteger3Distinct products to price per name. "milk" matches many; "Weet-Bix 375g" matches one. Each is charged
๐ŸŒ marketstring"AU"ISO 3166-1 alpha-2. AU is the only market with coverage; another code returns no matches rather than guessing
๐Ÿšง maxItemsinteger(none)Hard cap on products priced across the run
๐Ÿ“‰ priceHistoryoff/30d/90d30dVerdict + history bar. Add-on
โš–๏ธ unitPricebooleantruePrice per 100g/100ml. Add-on
๐Ÿ”— listingHistorybooleanfalseEvery listing ever seen. Add-on
๐Ÿท๏ธ stockCodesbooleanfalseRetailer SKUs. Add-on
๐Ÿฅฃ nutritionbooleanfalseNutrition panel. Add-on

๐Ÿ“Š What data does it return?

One row per product, with every retailer's offer nested inside it.

FieldNotes
๐Ÿท๏ธ name, brand, gtin, productRefproductRef is stable โ€” keep it to re-price the same product later without searching again
๐Ÿ“ฆ size, sizeBase, sizeKnownThe pack size as the shop printed it (375g, 2 x 1L), plus that quantity normalised. sizeKnown is false when no shop published one โ€” see below
๐Ÿฅ‡ bestRetailer, bestPriceCents, bestListingWhere it is cheapest, and the page it was seen on
๐Ÿ’ฐ dearestRetailer, dearestPriceCentsThe other end of the range
๐Ÿ’ธ spreadCents, savingPctWhat shopping around is worth on this item
๐Ÿช retailerCountHow many shops the figure is drawn from
๐Ÿ“… bestObserved, bestStaleDaysWhen that price was seen, and how long ago
โš–๏ธ comparable, observationGapDaysWhether the compared prices were seen close enough together to mean anything
๐Ÿšฉ bannerPresentTrue when a banner (e.g. IGA) is involved, whose stores price independently
๐Ÿ“‰ verdict, verdictBasisgood-price / typical / poor-price / unknown, and the reasoning
๐Ÿ“ˆ windowLowCents, windowMedianCents, windowHighCentsThe range this product has actually held
๐Ÿ”€ vsMedianPct, vsLowCents, priceDirection, priceChangesHow today sits against that range, and which way it is moving
๐Ÿ”ฌ windowCoveragePctHow much of the window the database can actually account for
๐Ÿงฎ sourcesConfirmingHow many independent sources stand behind the price โ€” a count, so you can weigh the evidence
โš ๏ธ disputedListings, widestDisputeCentsListings where sources disagreed on the price. Where they do, at least one is wrong, and you should know
๐Ÿ“Š historyBar[](history add-on) The price series as intervals, ready to chart. carried marks an interval the price was assumed rather than seen
๐ŸŽฏ windowDearerPct(history add-on) Share of the window, by time, the price sat above where it stands now. 89 means it was dearer than this 89% of the time
โณ daysAtCurrentPrice, longestHeldCents, longestHeldDays(history add-on) How long today's price has held, and the price that held longest
๐Ÿ”€ lastChangeCents, lastChangePct(history add-on) The most recent move, and how big it was
โš–๏ธ per100Cents, measure, cheapestPackIsCheapestUnit, estimated(unit price add-on)
๐Ÿ”— listingHistory[](listing add-on) Every listing: link, firstSeen, lastSeen, observations, stillListed
๐Ÿท๏ธ stockCodes[](stock code add-on) Each retailer's SKU
๐Ÿฅฃ nutrition(nutrition add-on) available: false with a reason where none is held
๐Ÿงพ offers[]Every retailer: price, listing, observed, staleDays, corroboration
โš ๏ธ disclaimerCarried onto every row, not left in an envelope

Plus one basket row per run, also saved to the key-value store as BASKET-SUMMARY:

FieldNotes
๐Ÿงบ byRetailer[]Every retailer: how many of your items they carry, the total for those, and missing โ€” the items they do not stock, because a cheap-looking basket is usually a short one
๐Ÿฅ‡ cheapestFullBasketThe cheapest single shop that carries everything โ€” null if none does
๐Ÿ—บ๏ธ bestCoverageWho came closest, when no single shop carries the lot
โœ‚๏ธ cherryPickTotalCentsThe total if you buy each item wherever it is cheapest
๐Ÿš— singleStorePremiumCentsWhat one trip costs you over cherry-picking. This is the number that decides whether a second stop is worth it

๐Ÿšซ What it does not return

  • Live prices. Every row is an recorded observation. The retailer may have changed it since โ€” hence the disclaimer on every row.
  • Stock levels you can trust. inStock is often null. It is passed through, never inferred.
  • A verdict it cannot support. Sparse history returns unknown, on purpose.
  • Which price tracker the observation came from. Sources are not disclosed; the retailer you would actually buy from is.

๐Ÿ“„ Real output

From {"queries": ["weet-bix breakfast cereal"], "priceHistory": "90d", "unitPrice": true} โ€” a real run against live data, not an illustration:

{
"name": "Weet-bix Breakfast Cereal",
"size": "575g",
"sizeBase": 575,
"sizeKnown": true,
"gtin": "9300652805048",
"productRef": "prod_HpNtNhDVHVvxx2YGfXF_SA",
"retailerCount": 2,
"bestRetailer": "coles",
"bestPriceCents": 350,
"bestListing": "https://coles.com.au/product/2001784",
"sourcesConfirming": 3,
"dearestRetailer": "woolworths",
"dearestPriceCents": 500,
"spreadCents": 150,
"savingPct": 30,
"comparable": true,
"observationGapDays": 0,
"disputedListings": 2,
"widestDisputeCents": 90,
"verdict": "typical",
"verdictBasis": "Judged against a 250c-500c range over 90d, 98.6% covered.",
"windowLowCents": 250,
"windowMedianCents": 500,
"windowHighCents": 500,
"windowDearerPct": 86,
"daysAtCurrentPrice": 0,
"lastChangeCents": -150,
"priceDirection": "volatile",
"priceChanges": 15,
"cheapestByUnitRetailer": "coles",
"per100Cents": 61,
"measure": "mass",
"cheapestPackIsCheapestUnit": true,
"estimated": false,
"disclaimer": "Not a live observation, confirm with retailer"
}

Read that row out loud and it says something no single shop can tell you:

  • ๐Ÿฅ‡ The same 575g box is $3.50 at Coles and $5.00 at Woolworths on the same day โ€” 30% apart, and comparable: true with observationGapDays: 0 means both prices were seen in the same sweep, so the gap is real rather than an artefact of looking on different days.
  • ๐Ÿ“ฆ size: "575g" is what makes that a comparison at all. Same pack, both shops.
  • โš–๏ธ 61c per 100g, and the cheapest box is also the cheapest per gram โ€” which is not always true.
  • ๐Ÿ“‰ $3.50 is typical, not a bargain. It beats the $5.00 median, but this product has been as low as $2.50 in 90 days across 15 price changes, so the verdict declines to call it a good price.
  • ๐Ÿงฎ Three sources confirm the winning price, and โš ๏ธ two listings have sources that disagree, by as much as 90c. At least one of those is wrong, and you get told rather than handed one confident number.

๐Ÿงฉ Add-ons

Everything below is opt-in and separately priced. Leave them off and you pay for prices only. An add-on is charged only when the lookup actually answered โ€” a product with no nutrition on file is never billed for nutrition.

Add-onWhat it addsPrice
๐Ÿ“‰ Price history โ€” 1 monthVerdict (good / typical / poor) against the range the product actually held, plus a chartable history bar๐Ÿ’ต $0.006 per product
๐Ÿ“Š Price history โ€” 3 monthsThe same, through a full promotion cycle โ€” a price that looks good against a month often reads as typical against a quarter๐Ÿ’ต $0.012 per product
โš–๏ธ Unit pricePrice per 100g / 100ml at each retailer, and whether the cheapest pack is also the cheapest per unit๐Ÿ’ต $0.004 per product
๐Ÿ”— Listing historyEvery listing ever seen: the link, first and last sighting, how many observations stand behind it, whether it is still listed๐Ÿ’ต $0.005 per product
๐Ÿท๏ธ Retailer stock codesEach retailer's own SKU, for matching to your catalogue or a supplier feed๐Ÿ’ต $0.004 per product
๐Ÿฅฃ NutritionThe nutrition panel where one is held. Batched, so one charge covers up to ten products๐Ÿ’ต $0.01 per batch

๐Ÿ“ฆ Why pack size is on every row

A price gap is not a comparison until you know the two packs are the same size. $3.50 against $5.00 means nothing if one box is 375g and the other is 575g โ€” and until recently that field was not published at all, which made every cross-retailer figure weaker than it looked.

size is what the shop printed. It is never computed: a size is derivable by dividing a shelf price by a per-100g price, and that returns 266.67g for a box printed 266g โ€” a number no shop wrote, in a field you would reasonably read as the shop's own words. Where nobody published one, sizeKnown is false and size is absent rather than guessed.

๐ŸŽ Included at no extra charge

These ride along with calls you have already paid for, so they cost nothing on top:

  • ๐Ÿงฎ How many sources confirm each price. Three independent sightings is a different quality of evidence from one, and now you can see which you have.
  • โš ๏ธ Where sources disagree. disputedListings and widestDisputeCents flag listings whose sources report different prices. At least one of them is wrong โ€” worth knowing before you act on a thin margin. In live testing this fired on a real product with a 90c spread between claims.
  • ๐ŸŽฏ windowDearerPct with any history add-on: the share of the window the price sat above today's. One number, no interpretation needed.
  • โณ How long the current price has held, the price that held longest, and the size of the last move โ€” all free with history.
  • ๐Ÿงบ What each retailer does not stock, in the basket row. A retailer looking cheap because they carry four of your ten items is the trap this closes.
  • ๐Ÿ“ฆ Pack size, so a price comparison is a comparison. Free on every row, add-on or not.

โš–๏ธ Why the unit price add-on earns its keep

The cheapest box is regularly not the cheapest buy. cheapestPackIsCheapestUnit answers that outright instead of leaving you to divide by pack size in your head โ€” and where a size was estimated rather than published, estimated: true says so, because a unit price built on a guessed divisor is not the same claim as one built on a printed weight.

๐Ÿ’ฐ How much does it cost?

Pay-per-event. You are charged for products actually priced and saved โ€” never for a name that matched nothing, and never for a failed lookup.

Base eventPrice
โ–ถ๏ธ Run start๐Ÿ’ต $0.00005
๐Ÿช Product priced across retailers๐Ÿ’ต $0.005
๐Ÿงบ Basket comparison (once per run)๐Ÿ’ต $0.02

You are never charged for work you cannot read. Every row is billed at the moment it is saved, so a charge cannot exist without a row in your dataset. A name that matched nothing, a lookup that failed, an add-on with no answer to give โ€” none of them bill. And if you stop the run, or it reaches the spending limit you set, whatever was already priced is saved and billed before it exits, rather than being thrown away after the work was already done.

Worked examples:

What you runCost
๐Ÿƒ 20 products, prices only โ€” every add-on off๐Ÿ’ต $0.12
๐Ÿฅ– 20 products + 1-month history๐Ÿ’ต $0.24
๐Ÿ›’ 20 products + 1-month history + unit price๐Ÿ’ต $0.32
๐Ÿ“ฆ 20 products + 3-month history + unit price + listings + codes๐Ÿ’ต $0.62
๐Ÿฑ 20 products, everything on๐Ÿ’ต $0.64

A weekly 20-item shop with history and unit prices runs about $1.28 a month. Prices only is $0.48 a month.

๐Ÿ“ˆ Against the alternatives

Price history is the part nobody else sells. Dedicated price-intelligence platforms put it behind their top tier โ€” Prisync unlocks price history on its $399/month plan โ€” and the per-result scrapers do not have it at all: the closest one tells you to build history yourself by scheduling repeated runs, which means you start accumulating from today.

This ActorPer-result scrapersPrice-intelligence SaaS
๐Ÿ“‰ Price historyโœ… back to March 2024โŒ starts when you doโœ… top tier only
๐Ÿช Across retailers in one callโœ…โŒ one retailer per Actorโœ…
โš–๏ธ Unit price comparisonโœ…โŒโž– sometimes
๐Ÿงบ Basket vs cherry-pickingโœ…โŒโŒ
๐Ÿ’ต Minimum spendnonenone๐Ÿ’ธ $99โ€“$399 / month

Below roughly 800 products a month, this is cheaper than the entry SaaS tier โ€” and you are not buying capacity you will not use.

โ“ FAQ

How fresh is the data? The major chains are swept every day. In practice a Coles, Woolworths or ALDI price is a few hours to a day old, and observed and staleDays tell you precisely which โ€” a price is never presented as current when it is not. Smaller retailers and marketplace sellers are swept less often, and their staleDays says so rather than hiding it.

Why is staleDays not always zero, then? Because the sweep runs once a day, and because it records when it looked. A two-day-old price is disclosed as two days old rather than dressed up as live. That disclosure is the point: a price with no timestamp is a claim, not a fact.

Why did I get verdict: "unknown"? The database holds too little of that window to judge fairly โ€” verdictBasis says how much was missing. Try a longer trendWindow, or a more common product.

Why does one product show only one retailer? Only one retailer in the database holds it. retailerCount is always the honest count, and savingPct is 0 rather than an invented figure.

Why is cheapestFullBasket null? No single retailer carries every item on your list. bestCoverage names who came closest.

Can I re-price the same product later? Yes โ€” keep productRef. It is stable and reveals nothing about where the observation came from.

Do I pay for an add-on that found nothing? No. Add-ons are charged only when the lookup answered. Nutrition for a product that has none, or a history window too sparse to judge, costs you nothing.

Why is size missing on some products? Because no shop published one for that product. It is never computed โ€” a size divided out of a per-100g price returns 266.67g for a box printed 266g, and that is not the shop's own words. sizeKnown: false says so plainly.

savingPct looks huge โ€” is it real? Check size and comparable first. A large gap between different-sized packs is not a saving, and comparable: false means the two prices were seen days apart. Both fields are on every row so you never have to take a percentage on trust.

Is this hitting Coles and Woolworths when I run it? No โ€” and that is why it is fast and why it can answer questions a live scrape cannot. Prices are swept daily into a database that keeps every observation, so one call returns every retailer at once plus years of history behind each. A live scraper can tell you today's price at one shop; it cannot tell you that $3.50 is typical rather than a bargain.