# Coles, Woolworths & Aldi Scraper - Australia Grocery Prices (`magenta_courser/australia-supermarket-prices`) Actor

Give supermarket categories (e.g. pantry, dairy-eggs-fridge) and get every product's price, was price, unit price, special type and stock from Coles, Woolworths and Aldi Australia in one flat table.

- **URL**: https://apify.com/magenta_courser/australia-supermarket-prices.md
- **Developed by:** [SUNGHWAN CHO](https://apify.com/magenta_courser) (community)
- **Stats:** 2 total users, 1 monthly users, 80.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 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

## Australia Supermarket Prices: Coles, Woolworths & Aldi

Give supermarket categories (for example `pantry` or `dairy-eggs-fridge`) and get one flat row per product with its current price, was price, unit price, special type and stock status from **Coles**, **Woolworths** and **Aldi Australia**, all in the same columns.

**Live example:** [this week's Coles vs Woolworths vs Aldi specials](https://experimory-crypto.github.io/k-ranking/au/) is rebuilt every Wednesday from this Actor's output.

Use it to track grocery prices and specials every week, compare the three chains side by side, or feed an Australian price-comparison app, retail analytics model or AI agent.

### What you get

One row per product per store:

- Store, product ID, name, brand, size
- Price, was price, discount %
- Unit price and its unit (`$1.73` per `100g`)
- On special yes/no, special type (`HALF_PRICE`, `PERCENT_OFF`, `MULTI_BUY`, `PRICE_DROP`, …) and the store's own special text (`1/2 Price`, `Buy 2 for $6`)
- In stock (Coles and Woolworths)
- Department and aisle
- Product URL and image URL
- Barcode (GTIN): Woolworths only

Prices are numbers in AUD. A value the store does not provide is `null`, never a missing field.

No login, no API key and no browser, so runs are fast and cheap.

### Input

| Field | Description |
|---|---|
| `categories` | Departments to list, one per line. The same name works for every store (`fruit-vegetables` finds Coles "Fruit & Vegetables", Woolworths "Fruit & Veg" and Aldi "Fruits & Vegetables"). Add a subcategory with a slash (`pantry/breakfast`), paste a store category URL, or write `all` for every department. Default: `dairy-eggs-fridge`, `fruit-vegetables`, `pantry`. |
| `stores` | `coles`, `woolworths`, `aldi`. Default: `coles`. |
| `maxItems` | Maximum products per category for each store. `0` = the whole category. Default 100. |
| `onlyOnSpecial` | Keep only products on special. Products filtered out are not saved and not charged. |
| `proxyConfiguration` | Default Apify Proxy (datacenter). If a store refuses a request, the retry goes through Australian residential proxy automatically. |

Common department names: `fruit-vegetables`, `meat-seafood`, `dairy-eggs-fridge`, `bakery`, `deli`, `pantry`, `frozen`, `chips-chocolates-snacks`, `drinks`, `liquor`, `health-beauty`, `cleaning-laundry`, `baby`, `pet`. If a name does not match, the run summary lists each store's exact department names.

```json
{
  "stores": ["coles", "woolworths", "aldi"],
  "categories": ["dairy-eggs-fridge", "pantry"],
  "maxItems": 0,
  "onlyOnSpecial": true
}
```

**Why no keyword search?** Coles and Woolworths disallow their search pages in robots.txt, so this Actor lists categories only. A whole department (for example all 2,263 Coles dairy products) is usually what price trackers want anyway.

### Output

```json
{
  "store": "coles",
  "productId": "6545966",
  "name": "Special Fried Rice Pouch",
  "brand": "Ben's Original",
  "size": "250g",
  "price": 2,
  "wasPrice": 4,
  "unitPrice": 0.8,
  "unitOfMeasure": "100g",
  "isOnSpecial": true,
  "specialType": "HALF_PRICE",
  "specialText": "1/2 Price",
  "discountPct": 50,
  "inStock": true,
  "category": "Pantry",
  "subcategory": "Pasta, Rice, Legumes & Grains",
  "url": "https://www.coles.com.au/product/ben-s-original-special-fried-rice-pouch-250g-6545966",
  "imageUrl": "https://cdn.productimages.coles.com.au/productimages/6/6545966.jpg",
  "barcode": null,
  "requestedCategory": "pantry",
  "scrapedAt": "2026-10-11T11:47:11.680Z",
  "schemaVersion": 1
}
```

| Field | Notes |
|---|---|
| `price` | Current shelf price in AUD. `null` when the store shows no price (product unavailable). |
| `wasPrice` | Only when the store shows a higher previous price; otherwise `null`. |
| `unitPrice`, `unitOfMeasure` | The store's comparison price, e.g. `0.8` per `100g`, `21.25` per `1kg`, `1.75` per `1l`. |
| `specialType` | `HALF_PRICE`, `PERCENT_OFF`, `MULTI_BUY`, `PRICE_DROP` (was price shown), `SPECIAL` (store flags a special without price details), Aldi `SUPER_SAVER` / `LOWER_PRICE`, or `null`. |
| `inStock` | Coles: availability at Coles' default online store. Woolworths: online stock. Aldi sells in store only, so always `null`. |
| `barcode` | Woolworths GTIN. Coles and Aldi listings do not include barcodes (`null`). |
| `category`, `subcategory` | The department that was listed and the product's aisle in it. |

Each product appears once per store per run, even when it is listed in several requested departments.

#### Run summary

The key-value store record `RUN_SUMMARY` (free) shows, per store and per category: `completed`, `partial`, `failed`, `notFound` or `budgetLimited`, products saved, the store's own product count, coverage, and request statistics (refused requests, retries). A failed category or store does not stop the others.

### Pricing

Pay per product row saved. Failed or blocked categories, filtered-out products and the run summary are free. Set **Maximum cost per run** to cap a run; the Actor stops cleanly at the limit and says so in the status message.

### Tips

- Whole departments: Coles pantry has about 6,000 products, Woolworths pantry about 8,500. Use `maxItems: 0` with a few departments, or `all` for the full catalogue (Coles lists about 30,000 products across its departments).
- With `maxItems` set, products come in the store's own order (on Coles this usually puts specials first). Whole-category Coles runs use a price sort so pages do not shift while the run is going.
- Run on a schedule (for example every Wednesday, when Coles and Woolworths specials change) and compare `price` by `store` + `productId` over time.

### Limitations

- Prices are the stores' online prices for their default location; some products are priced differently in store or by state.
- Coles and Woolworths use bot protection. The Actor sends spaced requests and retries refused ones with a new proxy session, but it does not solve captchas. If a store keeps refusing, that store's remaining categories are reported as `failed` (free) and the other stores continue. If every store refuses, the run still ends normally with zero products and a status message saying so (nothing is charged); only wrong input (unknown store or category) fails the run.
- Matching the same product across stores is not included: only Woolworths provides a barcode.
- Data is collected from public pages. Check the stores' terms before reusing names, descriptions or images commercially.

# Actor input Schema

## `categories` (type: `array`):

Supermarket categories to list, one per line. Use a department name such as "pantry", "dairy-eggs-fridge", "fruit-vegetables", "meat-seafood", "bakery", "frozen", "drinks"; the same name is matched to each store's own department. Add a subcategory with a slash ("pantry/breakfast"), paste a store category URL (e.g. https://www.coles.com.au/browse/pantry), or write "all" for every department. Keyword search is not offered because the stores' robots.txt disallows it.

## `stores` (type: `array`):

Which supermarkets to scrape. All stores use the same output fields (the "store" column tells them apart).

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

Stop each category after this many products for each store. 0 = the whole category (large departments such as Coles pantry have 6,000+ products).

## `onlyOnSpecial` (type: `boolean`):

Keep only products that are on special (half price, % off, multi-buy, price drop). Products not on special are not saved and not charged.

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

Apify Proxy (datacenter) is the default and the cheapest. If a store refuses a request, the retry automatically goes through Australian residential proxy when your account has it. Choose Residential + Australia here to use it for every request.

## Actor input object example

```json
{
  "categories": [
    "dairy-eggs-fridge"
  ],
  "stores": [
    "coles"
  ],
  "maxItems": 20,
  "onlyOnSpecial": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `products` (type: `string`):

One row per product per store.

## `runSummary` (type: `string`):

Per-store and per-category status (completed, partial, failed, notFound, budgetLimited), product counts and request statistics. Not billed.

# 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 = {
    "categories": [
        "dairy-eggs-fridge"
    ],
    "stores": [
        "coles"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("magenta_courser/australia-supermarket-prices").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 = {
    "categories": ["dairy-eggs-fridge"],
    "stores": ["coles"],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("magenta_courser/australia-supermarket-prices").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 '{
  "categories": [
    "dairy-eggs-fridge"
  ],
  "stores": [
    "coles"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call magenta_courser/australia-supermarket-prices --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,magenta_courser/australia-supermarket-prices"
        }
    }
}
```

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/yLZu97UZ2P1SnNUeO/builds/k5DVhy4oswpgBCCdv/openapi.json
