Woolworths & Aldi Price Scraper and Comparison avatar

Woolworths & Aldi Price Scraper and Comparison

Pricing

from $1.50 / 1,000 product scrapeds

Go to Apify Store
Woolworths & Aldi Price Scraper and Comparison

Woolworths & Aldi Price Scraper and Comparison

Woolworths and Aldi Australia prices in one table: price, was-price, unit price, specials, multibuys, stock, barcode, nutrition and Special Buy dates. Search terms, category or product links. Optional: match the same product at both stores, with a confidence score. No login.

Pricing

from $1.50 / 1,000 product scrapeds

Rating

0.0

(0)

Developer

CHEN-SHU-CHEN

CHEN-SHU-CHEN

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

What is Woolworths & Aldi Price Scraper and Comparison?

You want to know what a basket costs at Woolworths and at Aldi this week, which items are on special, or how a brand's products sit on the shelf. Checking two websites by hand means copying prices, sizes and unit prices product by product, and the two stores write sizes and unit prices differently.

Type search terms, paste category or product links, or both, and get one row per product from Woolworths and Aldi Australia in the same columns: price, was-price and savings, unit price (also converted to per kg, per litre or per item, so the stores compare directly), special type (half price, multibuy, price drop, member and Rewards offers), in stock, barcode, category, all images, and for Woolworths the ingredients, allergens, Health Star Rating and nutrition that come with every search result. No login is needed.

Turn on compare stores and the Actor also pairs the same product at both stores (same brand, same pack size, matching name) and writes one comparison row per pair: which store is cheaper, by how much, and by unit price, with a match confidence score so you can see why two products were paired.

Because it runs on Apify, you can schedule a weekly price check, call it through the API, connect it to Make, Zapier or Google Sheets, and export as CSV, Excel or JSON.

Coles is not supported. Its site blocks automated reads, so this Actor covers Woolworths and Aldi only, and says so rather than returning half-empty Coles rows.

How to scrape Woolworths and Aldi prices

  1. Open the Input tab and add Search terms, one per line: cadbury dairy milk, coca cola 2l, nappies. Each term is searched at both stores unless you pick one.
  2. Optionally paste Category links (https://www.woolworths.com.au/shop/browse/specials/half-price, https://www.aldi.com.au/products/dairy-eggs-fridge/milk/k/1111111160) or Product links or codes (https://www.woolworths.com.au/shop/productdetails/44528/..., a stockcode such as 44528, or an 18-digit Aldi SKU).
  3. Set Max products per search term or category. 50 is the default.
  4. Turn on what you need: Specials only, Add Aldi Special Buys, Include product page details, Compare the same product at both stores.
  5. Click Start. A search term with 50 products per store finishes in a few seconds.
  6. Open the Output tab. The Products view lists every product, Woolworths vs Aldi the comparison rows, and Inputs and errors anything that returned nothing.

What data does it return?

Every product row has the same columns for both stores. A column a store does not publish is null, never 0.

FieldNotes
store, productId, stockcode / sku, urlWoolworths stockcode or Aldi SKU
barcode, gtinFormatWoolworths only. Aldi publishes no barcodes
name, displayName, brand, variety, size
sizeAmount, sizeUnit, packCountThe size normalised: 6 x 375mL is 2250, ml, 6
price, wasPrice, savings, isOnSpecial, isHalfPricewasPrice only when it is above the price
specialTypeshalf_price, multibuy, member_price, rewards_offer, prices_dropped, lower_price_always, special; for Aldi special_buy, lower_prices, super_savers, limited_time_only
promotionTextsThe store's own tag text: "Save $18.00", "2 for $10.00", "Was $3.30 - 25/08/2026"
multibuyQuantity, multibuyPrice, multibuyUnitPrice"2 for $10" is 2, 10.0
wasPriceHistoryWoolworths "Prices Dropped" tags parsed: {price: 3.3, date: "2026-08-25", isRange: false}
unitPrice, unitPriceMeasure, unitPriceTextAs the store shows it: 2.7, 100G, $2.70 / 100G
unitPriceStandard, unitPriceStandardUnitPer kg, L or each, the same basis for both stores
instorePrice, instoreWasPrice, instoreIsOnSpecialWoolworths' in-store price where it differs
inStock, isAvailable, isPurchasable, supplyLimit, stockMessageWoolworths. Aldi publishes no stock, so inStock is null there
isForDelivery, isForCollection, isForExpress, nextAvailabilityDateWoolworths delivery options
isSponsored, adStatus, searchRank, organicRank, inputTotalResultsPosition in the store's results for your term, with and without sponsored tiles: share of shelf for a brand
isMarketplace, vendorWoolworths Everyday Market (third-party sellers)
categoryPath, departments, categories, subcategories, categoryIds, sap*
ingredients, allergensContains, allergensMayContain, allergyStatement, dietaryClaims, healthStarRating, nutrition, description, storageInstructionsWoolworths, from the search result itself
imageUrl, images, imageUrlMedium, imageUrlSmall, imageDetailsAll product images; Aldi at 1500 px
isSpecialBuy, specialBuyOnSaleDate, specialBuyOnSaleText, isUpcomingSpecialBuy, specialBuyWeekAldi Special Buys
averageRating, ratingCount, reviewCount, ratingBreakdownnull when the store shows no ratings
fulfilmentStoreIdThe Woolworths store the price comes from (see below)
input, inputType, inputIndex, status, scrapedAtWhich input found the product

With Include product page details (one extra request per product):

FieldStore
nutritionPanel (per serve and per 100 g/mL), servingSize, servingsPerPackWoolworths
countryOfOrigin, australianIngredientsPercent, countryOfOriginLabelWoolworths: "Australian", 100
aisle, aisleDepartment, detailImages, videoUrl, directions, warningsWoolworths
description, ingredients, allergensContains, allergensMayContain, storageInstructions, directionsAldi. Aldi fills ingredients and storage on about a third of its products

detailsStatus says whether that worked for each row.

Comparison rows (rowType: "comparison"): cheapestStore (woolworths, aldi or same), priceDifference, priceDifferencePercent, cheapestByUnitPrice, unitPriceDifference, unitPriceUnit, matchMethod, matchConfidence, nameSimilarity, and each side's id, name, brand, size, price, was-price, unit price, link and image.

Input rows (rowType: "input"): one for each input that produced no product rows, with status (no_results, not_found, invalid_input, blocked, parse_error, partial, not_processed) and error. The outcome of every input, including the successful ones, is also in the key-value store under INPUTS.

Unreadable products: if a store sends a product without an id, name, link or price, or in a shape the parser cannot read, it becomes a free row with status: "parse_error" and the reason in error, and the rest of the input carries on.

How does the Woolworths vs Aldi comparison work?

Aldi publishes no barcodes, so products are matched on what both stores do publish:

  1. Brand must be the same after tidying case and punctuation: Cadbury = CADBURY.
  2. Pack size must be the same total amount within 2%: 2L = 2 l, 1kg = 1000 g. A six-pack never matches a single bottle, even at the same volume.
  3. The rest of the name is compared once brand and size are removed, by shared words and character similarity.

Brand and size are gates, not points. A pair that fails either is never matched. Passing both gives 0.6, and the name adds up to 0.4, so matchConfidence runs from 0.6 to 1. Only pairs at or above Minimum match confidence (0.85 by default) are written, and each product is used at most once, best match first.

In practice this pairs the branded products both stores stock (Cadbury, Coca-Cola, Norco), which is where a like-for-like price comparison is honest. Aldi's own brands have no Woolworths twin, so they are not paired with a Woolworths product that is only similar. If you want looser pairs, lower the threshold and check nameSimilarity.

Only products read in the same run are compared, so search the same terms at both stores. A product found by two terms is written once.

How much does it cost to scrape Woolworths and Aldi?

You pay per row, not per minute.

EventCharged forPricePer 1,000
product-scrapedOne product row, from either store$0.0015$1.50
product-detailsThe product page added to that row (Include product page details)$0.0005$0.50
comparison-rowOne product matched at both stores$0.005$5.00

Free, never charged: input rows (no_results, not_found, invalid_input, blocked, parse_error, not_processed), unreadable products (parse_error), a product found again by a second term, and product page details when the input was itself a product link (that page is the request).

Examples: 50 products from each store for 10 terms is 1,000 rows, $1.50. With details, $2.00. Comparison rows only appear for confident matches, typically a handful per branded term.

Apify's free plan includes $5 of usage a month, about 3,300 products.

How do I keep a run from costing more than I expect?

Set a maximum charge for the run when you start it. Before each product, the Actor checks that the budget still covers it and its details together (if details are on), and stops before fetching anything it could not charge; inputs it did not reach are listed as not_processed. Each row is written and charged in one step by Apify's SDK, which writes only what the budget covers, so a row is never charged without being in your dataset. Details are charged only after their row is written, once per product. If Apify cannot record a charge, the run stops its paid work. A run also stops when it is plainly costing more than it earns, for example through a proxy that stalls every request, and shortly before the run's timeout: every request's timeout is cut to the time left, and what was not reached is not_processed.

What happens if Apify restarts a run?

Progress is saved after every input, every 25 products, and whenever Apify announces a migration. A restarted run reads its own dataset, skips every product and comparison row already written, finishes the input it was on without going over its product limit, and carries on, so rows are not written or charged twice. If the dataset cannot be read back, the run stops and fails rather than guess.

Two narrow windows remain. If the run stops between writing a product and charging its details, those details are never charged. And because a write can take a moment to show when the dataset is read back, the row written just before a restart can occasionally be missed, then written and charged a second time. That affects at most one row per restart.

Input example

{
"searchTerms": ["cadbury dairy milk", "coca cola 2l"],
"stores": "both",
"maxProductsPerInput": 20,
"categoryUrls": ["https://www.woolworths.com.au/shop/browse/specials/half-price"],
"specialsOnly": false,
"compareStores": true
}

Output example

From a real run on 2026-10-18. A comparison row, trimmed:

{
"rowType": "comparison",
"cheapestStore": "aldi",
"priceDifference": 1.01,
"priceDifferencePercent": 33.7,
"cheapestByUnitPrice": "aldi",
"unitPriceDifference": 22.5,
"unitPriceUnit": "kg",
"matchMethod": "brand_size_name",
"matchConfidence": 1.0,
"woolworthsName": "Cadbury Dairy Milk Chocolate Bar 45g",
"woolworthsPrice": 3.0,
"woolworthsUnitPriceStandard": 66.7,
"aldiName": "Dairy Milk Chocolate Bar 45g",
"aldiPrice": 1.99,
"aldiUnitPriceStandard": 44.2
}

A Woolworths product row, trimmed:

{
"store": "woolworths",
"productId": "814479",
"name": "Cadbury Dairy Milk Chocolate Block",
"brand": "Cadbury",
"size": "180g",
"price": 5.5,
"wasPrice": 8.0,
"savings": 2.5,
"isOnSpecial": true,
"specialTypes": ["special"],
"promotionTexts": ["30% Off", "Save $2.50"],
"unitPriceText": "$3.06 / 100G",
"unitPriceStandard": 30.6,
"unitPriceStandardUnit": "kg",
"inStock": true,
"barcode": "9300617064879",
"isSponsored": false,
"searchRank": 2,
"categoryPath": ["Halloween", "Confectionery", "Chocolate Blocks"],
"url": "https://www.woolworths.com.au/shop/productdetails/814479/cadbury-dairy-milk-chocolate-block"
}

FAQ

Which store's prices are these?

Woolworths: the prices of Woolworths' default online store (fulfilmentStoreId 1101). Most prices are national, but some fresh and regional items differ by store. Choosing another store needs a logged-in Woolworths account, so there is no postcode setting.

Aldi: Aldi's national in-store (walk-in) prices. Aldi does not sell groceries online, and its prices do not change by store.

So a comparison row puts Woolworths' online price next to Aldi's shelf price.

What does "Specials only" mean at Aldi?

Woolworths filters its own specials. Aldi shows no was-prices at all, so "specials" at Aldi means the products in its own Lower Prices, Super Savers and Limited Time Only groups, and specialTypes says which. Aldi's weekly Special Buys are a separate option, because they are mostly non-food (tools, homewares, clothing) on sale from a given date while stocks last.

What can it not return?

  • Coles, whose site blocks automated reads.
  • Aldi barcodes and stock levels, which Aldi does not publish. barcode and inStock are null on Aldi rows.
  • Ratings for most products: Woolworths sends zeros in search results, which are reported as null, not as a rating of 0.
  • Prices for a specific Woolworths store or postcode (see above).

The Actor reads the same public product data any visitor sees on woolworths.com.au and aldi.com.au, without an account. Check the rules that apply to you and to how you use the data; this is not legal advice.

Why did an input come back blocked?

Woolworths and Aldi both read through Apify's datacenter proxy in every test. If a store refuses a request, the Actor retries on a different IP up to three times, then marks the input blocked. After three blocked inputs in a row it stops, and the rest come back not_processed at no charge. Run again later. Residential and Google SERP proxy groups are not used, because the price per product is set for datacenter traffic.

Other limits worth knowing

  • Results come in each store's own relevance order. Woolworths mixes sponsored products into search results; they are kept and flagged isSponsored, because their position is part of what the shelf looks like.
  • Both stores' APIs are undocumented and can change without notice. If a store's answer stops making sense, the input is reported parse_error rather than filled with guesses.
  • Up to 1,000 products per input, and 1,000 Special Buys.

Something broke or a number looks wrong

Open an issue on the Issues tab with the input and the run link.