# Coles, Woolworths & ALDI Scraper — AUS Grocery Prices (`griffie/coles-woolworths-aldi-scraper`) Actor

Scrape Coles, Woolworths and ALDI Australia: price, was-price, unit price, specials and multi-buys, availability, brand, size, category, barcode and image for any search, category, specials list or product. Price-change monitor mode.

- **URL**: https://apify.com/griffie/coles-woolworths-aldi-scraper.md
- **Developed by:** [Dustin Griffie](https://apify.com/griffie) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 products

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Coles, Woolworths & ALDI Scraper — AU Grocery Prices

Get grocery prices from **Coles, Woolworths and ALDI Australia** in one run. For every product you get the shelf price, was-price, unit price, special or multi-buy offer, availability, brand, pack size, category, image and link. Search all three supermarkets for the same terms to compare prices, pull a whole category or the weekly specials, or watch a list of products and get only the prices that changed.

### What you can do

- **Compare prices** for "milk", "coffee beans" or any search term at Coles, Woolworths and ALDI side by side.
- **Download a category** such as Coles *Pantry*, Woolworths *Dairy, Eggs & Fridge* or ALDI *Freezer*: paste the category URL.
- **Get this week's specials:** half-price, price drops and multi-buys, with the saving and promo text.
- **Look up specific products** by URL or ID (`coles:7265535`, `woolworths:88436`, `aldi:000000000000399309`).
- **Monitor prices:** schedule the same input daily or weekly. Monitor mode returns only products whose price, was-price, special or stock changed, and you pay only for those.

### How to scrape Coles, Woolworths and ALDI prices

1. Pick the supermarkets.
2. Enter search terms and/or paste Coles, Woolworths or ALDI URLs (search, category, specials or product pages), or product IDs.
3. Optional: tick *Specials only*, turn on *All current specials*, or turn on the *Price-change monitor*.
4. Click **Start**, then download the results as JSON, CSV or Excel, or read them through the API.

### Input

| Field | What it does |
|---|---|
| `retailers` | Any of `coles`, `woolworths`, `aldi`. Search terms run at each selected supermarket. |
| `searchTerms` | Words to search for, e.g. `milk`, `coffee beans`, `nappies`. |
| `startUrls` | Coles, Woolworths or ALDI URLs: search results, category (`/browse/...`, `/shop/browse/...`, `/products/.../k/...`), specials (`/on-special`, `/shop/browse/specials`) or a product page. |
| `productIds` | `coles:<id>`, `woolworths:<stockcode>`, `aldi:<sku>`. A bare number works when only one supermarket is selected. |
| `scrapeSpecials` | Adds each selected supermarket's specials list (Coles *On Special*, every Woolworths department's specials, ALDI *Super Savers* and *Limited Time Only*). |
| `specialsOnly` | Keep only products that are on special (for searches and categories). |
| `maxItemsPerTarget` | Products per search term, category or specials list (default 100). In monitor mode this counts products checked. |
| `maxItems` | Hard limit for the whole run (0 = none). |
| `includeSponsored` | Keep the sponsored placements Woolworths mixes into results (off by default). |
| `monitorMode`, `monitorIncludeNew`, `monitorStoreName` | Price-change monitor (see below). |
| `proxyConfiguration`, `fallbackToResidential` | Apify datacenter proxy by default, with an automatic switch to Australian residential proxies if a supermarket keeps blocking. |

Example:

```json
{
  "retailers": ["coles", "woolworths", "aldi"],
  "searchTerms": ["milk", "coffee beans"],
  "startUrls": [{ "url": "https://www.coles.com.au/browse/pantry" }],
  "productIds": ["woolworths:88436"],
  "maxItemsPerTarget": 50
}
```

### Output

One row per product:

```json
{
  "recordType": "product",
  "retailer": "woolworths",
  "productId": "348593",
  "name": "KitKat Milk Chocolate Mini Bars 154g 11 pack",
  "brand": "KitKat",
  "size": "154g 11 pack",
  "price": 3.75,
  "wasPrice": 7.5,
  "savingsAmount": 3.75,
  "isOnSpecial": true,
  "promoType": "HALF_PRICE",
  "promoText": "Save $3.75",
  "multibuy": null,
  "unitPrice": 2.44,
  "unitPriceText": "$2.44 / 100G",
  "unitMeasure": "100G",
  "isAvailable": true,
  "availabilityText": "Available",
  "category": "Share Packs",
  "categoryPath": "Snacks & Confectionery > Buckets & Treats > Share Packs",
  "barcode": "9300605152397",
  "imageUrl": "https://cdn1.woolworths.media/content/wowproductimages/large/348593.jpg",
  "url": "https://www.woolworths.com.au/shop/productdetails/348593/kitkat-milk-chocolate-mini-bars",
  "searchQuery": "chocolate",
  "sourceType": "search",
  "position": 5,
  "scrapedAt": "2026-10-24T20:48:12.155Z"
}
```

- Prices are in **AUD**. `wasPrice` and `savingsAmount` are set only when the supermarket shows a saving. `multibuy` holds offers like *Buy 2 for $6* as `{ "quantity": 2, "unitPrice": 3, "text": "Buy 2 for $6" }` (`unitPrice` = price each when you buy the quantity).
- `unitPrice` is the supermarket's comparison price for `unitMeasure` (for example per 1L, 100g or 1EA).
- `barcode` is only published by Woolworths.
- In monitor mode each row also has `changeType` (`new`, `price`, `wasPrice`, `special_started`, `special_ended`, `promo`, `back_in_stock`, `unavailable`), `previousPrice`, `priceChange` and `priceChangePct`.

**Status rows** (`recordType: "status"`) explain every input that gave no products: `invalid`, `not_found`, `no_results`, `partial` or `failed`, with a message. They are free. Run totals, request counts and the proxy used per supermarket are in the `RUN_STATS` key-value record.

The dataset has ready-made views: **Products**, **Specials**, **Price changes (monitor)** and **Statuses**.

### Price-change monitor

Turn on `monitorMode` and schedule the same input (for example weekly). The Actor remembers the last price of every product in a named key-value store (`monitorStoreName`). Each run returns only:

- products whose price, was-price, special/promo or availability changed, with the previous price and the change, and
- products seen for the first time (turn off `monitorIncludeNew` to skip them).

Unchanged products are not saved and not charged. Use a different `monitorStoreName` for each watch list.

### How much does it cost to scrape Coles, Woolworths and ALDI?

Pay per event: you pay only for **products saved** to the dataset.

| Event | Free | Starter | Scale | Business and up |
|---|---|---|---|---|
| `product`: one product row | $0.001 | $0.0009 | $0.0008 | $0.0007 |
| Actor start | $0.00005 | $0.00005 | $0.00005 | $0.00005 |

Example: 1,000 products cost $1.00 on the Free plan and $0.70 on the Business plan. Status rows, duplicates, skipped sponsored items and unchanged products in monitor mode are free. The Actor respects your **Max cost per run** and stops cleanly at the limit without saving anything it can't charge for.

### Tips & limits

- **Prices are the supermarkets' national online prices** with no store or postcode selected. In-store prices and some regional prices (for example in WA, NT or Tasmania) can differ. Store- or postcode-specific pricing is not supported.
- **ALDI** prices are the ALDI Australia website's walk-in (in-store) prices. ALDI rarely shows was-prices. ALDI *Special Buys* (weekly non-food deals) pages aren't supported; *Super Savers* and *Limited Time Only* are.
- **Woolworths** mixes sponsored products into results. They are skipped by default so they don't repeat across searches; turn on `includeSponsored` to keep them (marked `isSponsored: true`).
- **Coles** category pages list specials first, so a capped category run is weighted toward specials. Raise `maxItemsPerTarget` to get the whole category.
- A product found by several inputs is saved (and charged) once per run.
- Speed: about 1,000 products per 30–50 seconds with the default settings.

### Legal & disclaimer

This Actor reads publicly available product and price information from coles.com.au, woolworths.com.au and aldi.com.au, the same data any visitor sees without signing in. It is **not affiliated with, endorsed by or sponsored by Coles Group, Woolworths Group or ALDI**. "Coles", "Woolworths" and "ALDI" are trademarks of their owners and are used only to describe the data source.

You are responsible for using the data lawfully and in line with each website's terms of use and the laws that apply to you. Keep request volumes reasonable, don't republish product images or descriptions as your own, and don't use the data to mislead consumers. Prices change often; always check the supermarket's website before relying on a price. If in doubt, ask a lawyer.

### FAQ

**Do I need a proxy?** No setup is needed. The Actor uses Apify's datacenter proxy and switches to Australian residential proxies automatically if a supermarket starts blocking (keep *Fall back to residential proxies* on).

**Can I get every product a supermarket sells?** Yes: run its top-level categories with a high `maxItemsPerTarget`. For example, the whole ALDI range is about 3,300 products.

**Why is a product missing?** It may be out of the national online range, sponsored (Woolworths) or already saved by another input in the same run. Check the status rows and `RUN_STATS`.

# Actor input Schema

## `retailers` (type: `array`):

Which supermarkets to search (used for search terms and "All current specials"). URLs and prefixed product IDs always go to their own retailer.

## `searchTerms` (type: `array`):

Products to search for, e.g. "milk", "Vegemite", "nappies". Each term is searched at every selected retailer.

## `startUrls` (type: `array`):

Paste any Coles, Woolworths or ALDI URL: a category (coles.com.au/browse/dairy-eggs-fridge/milk, woolworths.com.au/shop/browse/pantry, aldi.com.au/products/pantry/k/970000000), a search results page, a specials page (coles.com.au/on-special) or a product page.

## `productIds` (type: `array`):

Look up specific products: "coles:7265535", "woolworths:88436", "aldi:000000000538441002". Product URLs work too.

## `scrapeSpecials` (type: `boolean`):

Also scrape the current specials catalogue of every selected retailer (Coles "On Special", Woolworths specials in every department, ALDI Super Savers and Limited Time Only). Limited by Max products per search.

## `specialsOnly` (type: `boolean`):

Only return products that are on special (price drops, multi-buys, half price). Applied to searches and categories.

## `maxItemsPerTarget` (type: `integer`):

Stop each search term, category or specials list after this many products. In monitor mode this counts products checked (changed or not), so every run watches the same products.

## `maxItems` (type: `integer`):

Stop the whole run after this many products (0 = no limit). You are never charged for more than this.

## `includeSponsored` (type: `boolean`):

Keep paid/sponsored placements that the retailer mixes into results (they are marked isSponsored). Off by default because they repeat across searches.

## `monitorMode` (type: `boolean`):

Remember prices between runs and only return products whose price, was-price, special or availability changed (plus products seen for the first time). Unchanged products are not saved and not charged. Schedule the same input daily or weekly.

## `monitorIncludeNew` (type: `boolean`):

In monitor mode, also return products the monitor has never seen (always true on the first run you want a baseline). Turn off to get only real changes.

## `monitorStoreName` (type: `string`):

Named key-value store that holds remembered prices. Use a different name for each separate watch-list.

## `maxConcurrency` (type: `integer`):

How many searches/categories run in parallel.

## `maxRetries` (type: `integer`):

Retries on a fresh IP when a request is blocked or fails.

## `proxyConfiguration` (type: `object`):

Apify datacenter proxy (default) works for all three retailers. Coles blocks most servers without a proxy.

## `fallbackToResidential` (type: `boolean`):

If a retailer keeps blocking datacenter IPs, switch that retailer to Apify residential proxies (Australia) automatically.

## `debugLog` (type: `boolean`):

Verbose logging.

## Actor input object example

```json
{
  "retailers": [
    "coles",
    "woolworths",
    "aldi"
  ],
  "searchTerms": [
    "milk",
    "coffee beans"
  ],
  "scrapeSpecials": false,
  "specialsOnly": false,
  "maxItemsPerTarget": 50,
  "maxItems": 0,
  "includeSponsored": false,
  "monitorMode": false,
  "monitorIncludeNew": true,
  "monitorStoreName": "au-grocery-price-monitor",
  "maxConcurrency": 4,
  "maxRetries": 6,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "fallbackToResidential": true,
  "debugLog": false
}
```

# Actor output Schema

## `results` (type: `string`):

Name, brand, size, price, was-price, unit price, specials, availability, category, image and link.

## `specials` (type: `string`):

Savings, promo text and multi-buy deals.

## `changes` (type: `string`):

Monitor mode: previous vs current price.

## `runStats` (type: `string`):

Counts per status, charged products, requests and proxy tier per retailer.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "retailers": [
        "coles",
        "woolworths",
        "aldi"
    ],
    "searchTerms": [
        "milk",
        "coffee beans"
    ],
    "maxItemsPerTarget": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("griffie/coles-woolworths-aldi-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "retailers": [
        "coles",
        "woolworths",
        "aldi",
    ],
    "searchTerms": [
        "milk",
        "coffee beans",
    ],
    "maxItemsPerTarget": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("griffie/coles-woolworths-aldi-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "retailers": [
    "coles",
    "woolworths",
    "aldi"
  ],
  "searchTerms": [
    "milk",
    "coffee beans"
  ],
  "maxItemsPerTarget": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call griffie/coles-woolworths-aldi-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,griffie/coles-woolworths-aldi-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/wTaMJPXNXABOkGOMH/builds/e7GUdIJRGo6rnh9FS/openapi.json
