# Australian Grocery Prices: Coles & ALDI (`fourteenerdevs/australian-grocery-prices`) Actor

Coles and ALDI Australia prices in one clean table: price, was-price, specials, unit price normalised to $/kg, $/L or each, category, image and link. Search, categories, specials or product URLs, with optional day-to-day price-change tracking. Woolworths in beta.

- **URL**: https://apify.com/fourteenerdevs/australian-grocery-prices.md
- **Developed by:** [Fourteener Devs](https://apify.com/fourteenerdevs) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 product saveds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### What does Australian Grocery Prices do?

**Australian Grocery Prices** collects product prices from **Coles** and **ALDI Australia** and returns them in **one clean table with the same columns for both stores**: price, was-price, specials, the shelf unit price, and a **unit price converted to $/kg, $/L or per item** so you can compare stores directly. Point it at search terms, categories, the specials pages or individual products, and schedule it to **track price changes day to day**.

No coding, no browser extensions, no logins. Results download as Excel, CSV or JSON, or flow straight into Google Sheets, Make, Zapier or your own app through the API.

**Woolworths** is available as a **beta** option (see below).

### Why use it?

- 🛒 **Compare a shopping list across stores.** Search "milk 2l", "olive oil" or "nappies" at Coles and ALDI in one run and sort by `standardUnitPrice` to find the cheapest per kilo or litre.
- 🏷️ **Get every special.** The full Coles specials list (half price, multi-buy, price drops) and **every announced ALDI Special Buys drop, including upcoming dates**.
- 📈 **Monitor prices automatically.** Turn on *Only save new products and price changes*, schedule a daily run, and you only receive (and only pay for) products whose price or special changed.
- 🧱 **Feed apps and research.** Price-comparison apps, budgeting tools, deal newsletters, cost-of-living and inflation research, and brand and category teams watching their shelf.

### What data does it collect?

| Field | Example | Notes |
|---|---|---|
| `retailer` | `Coles` | Coles, ALDI or Woolworths |
| `productId` | `8150288` | The store's own product number |
| `displayName` | `Coles Full Cream Milk 3L` | Brand + name + size |
| `name`, `brand`, `size` | `Full Cream Milk`, `Coles`, `3L` | As the store lists them |
| `price` | `4.95` | Current price in AUD |
| `wasPrice`, `savings` | `6.70`, `0.70` | Filled when the product is reduced |
| `isOnSpecial`, `promotion` | `true`, `1/2 Price` | Half price, multi-buy, ALDI Special Buy and similar |
| `unitPrice`, `unitPriceText` | `1.65`, `$1.65/1L` | The unit price shown on the shelf |
| `standardUnitPrice`, `standardUnit` | `1.65`, `L` | Normalised to $/kg, $/L, each, $/m or per 100 sheets |
| `inStock` | `true` | Coles and Woolworths online availability (ALDI does not sell groceries online) |
| `availableFrom` | `2026-10-21` | ALDI Special Buys on-sale date |
| `category`, `categoryPath` | `Dairy, Eggs & Fridge` | The store's own category tree |
| `gtin` | `9300601186945` | Barcode, on Coles product-page results |
| `details` | | Product-page results only: description, plus ingredients, allergens and country of origin for Coles |
| `imageUrl`, `url` | | Product image and page |
| `sourceType`, `source` | `search`, `milk` | What found it: `search`, `url` or `specials`, and the term or URL |
| `scrapedAt` | `2026-10-17T18:51:33Z` | When the price was read |

With price tracking on, every row also gets `previousPrice`, `previousWasPrice`, `priceChange`, `priceChangePercent`, `priceChanged`, `isNewProduct` and `lastSeenAt`.

#### Sample output

```json
[
  {
    "retailer": "Coles",
    "productId": "1338352",
    "name": "Protein Snack Dutch Chocolate",
    "brand": "Rokeby",
    "size": "160g",
    "displayName": "Rokeby Protein Snack Dutch Chocolate 160g",
    "price": 1.55,
    "wasPrice": 3.15,
    "savings": 1.6,
    "isOnSpecial": true,
    "promotion": "1/2 Price | save $1.60",
    "unitPrice": 0.97,
    "unitPriceText": "$0.97/100g",
    "standardUnitPrice": 9.7,
    "standardUnit": "kg",
    "currency": "AUD",
    "inStock": true,
    "availableFrom": null,
    "category": "Dairy, Eggs & Fridge",
    "categoryPath": [
      "Dairy, Eggs & Fridge",
      "Dairy Desserts",
      "Chilled Dairy Desserts"
    ],
    "gtin": null,
    "imageUrl": "https://productimages.coles.com.au/productimages/1/1338352.jpg",
    "url": "https://www.coles.com.au/product/rokeby-protein-snack-dutch-chocolate-160g-1338352",
    "sourceType": "url",
    "source": "https://www.coles.com.au/browse/dairy-eggs-fridge",
    "scrapedAt": "2026-10-17T18:51:33Z"
  },
  {
    "retailer": "ALDI",
    "productId": "000000000000398691",
    "name": "Light Milk 2L",
    "brand": "FARMDALE",
    "size": "2 l",
    "displayName": "FARMDALE Light Milk 2L",
    "price": 3.39,
    "wasPrice": null,
    "savings": null,
    "isOnSpecial": false,
    "promotion": null,
    "unitPrice": 1.7,
    "unitPriceText": "$1.70 per 1 L",
    "standardUnitPrice": 1.7,
    "standardUnit": "L",
    "currency": "AUD",
    "inStock": null,
    "availableFrom": null,
    "category": "Dairy, Eggs & Fridge",
    "categoryPath": [
      "Dairy, Eggs & Fridge",
      "Milk"
    ],
    "gtin": null,
    "imageUrl": "https://dm.apac.cms.aldi.cx/is/image/aldiprodapac/product/jpg/scaleWidth/600/93645b60-eb11-4046-b28e-2b441f8585a4/farmdale-light-milk-2l",
    "url": "https://www.aldi.com.au/product/farmdale-light-milk-2l-000000000000398691",
    "sourceType": "search",
    "source": "milk",
    "scrapedAt": "2026-10-17T18:51:33Z"
  }
]
```

### How to use it

1. Click **Try for free**.
2. Add **search terms** (one per line), or paste **start URLs** from coles.com.au or aldi.com.au, or tick **Scrape all current specials**.
3. Pick the supermarkets and click **Start**. Results appear in the **Prices** tab as they arrive.

By default each search term, URL or specials list stops at 100 products per supermarket, which keeps first runs cheap. Set **Max products per source** to 0 to collect everything, for example the full specials lists.

#### Example inputs

**Compare a shopping list across Coles and ALDI**

```json
{ "searchTerms": ["full cream milk 2l", "free range eggs", "olive oil"], "retailers": ["coles", "aldi"], "maxItemsPerSource": 30 }
```

**Coles dairy specials plus every announced ALDI Special Buy**

```json
{ "startUrls": [{ "url": "https://www.coles.com.au/on-special/dairy-eggs-fridge" }, { "url": "https://www.aldi.com.au/special-buys" }], "maxItemsPerSource": 0 }
```

**Daily price watch on specific products** (schedule it every morning)

```json
{
  "startUrls": [
    { "url": "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288" },
    { "url": "https://www.aldi.com.au/product/farmdale-light-milk-2l-000000000000398691" }
  ],
  "onlyChanged": true
}
```

#### Which URLs work?

| Store | Supported pages |
|---|---|
| Coles | Categories (`/browse/...`), specials (`/on-special`, `/on-special/<category>`), search (`/search/products?q=...`), products (`/product/...`) |
| ALDI | Categories (`/products/.../k/...`), Special Buys (`/special-buys`, `/special-buys/<date>`), search (`/results?q=...`), products (`/product/...`) |
| Woolworths (beta) | Search (`/shop/search/products?searchTerm=...`) |

Coles only lists the first ~5,000 products of any listing. When a category or the specials list is bigger, the Actor automatically walks its sub-categories instead. In testing, the full Coles specials list (about 7,800 products) took around 5 minutes and returned 98% of the count Coles shows.

### How much does it cost?

You pay per product saved: **$1 per 1,000 products**. Platform usage is included, and Apify's standard run-start fee is a fraction of a cent.

| Run | Products | Cost |
|---|---|---|
| 3 search terms × 2 stores, 30 results each | ~180 | about $0.18 |
| All ALDI Special Buys (this week and upcoming) | ~250 | about $0.25 |
| Full Coles specials list (*Max products per source* set to 0) | ~7,800 | about $8 |
| Daily watch of 200 products with *Only changes* | only the products that changed | cents per day: specials mostly change once a week |

Apify's free plan includes monthly credit, enough for thousands of products. Set a **maximum cost per run** in the run options and the Actor stops cleanly when it reaches it, and you are never charged beyond it. Duplicates found by several search terms are removed before saving, so you don't pay twice for the same product.

### Price tracking

Turn on **Track price changes between runs** and the Actor remembers the last price of every product it sees in a storage on your own Apify account (`au-grocery-price-history` by default). Each row then shows the previous price and the change.

Turn on **Only save new products and price changes** to receive only what moved. The first run saves everything as a baseline; from then on a daily scheduled run returns just the price drops, rises and specials that started or ended. Use different storage names to keep separate watch lists apart.

### Woolworths (beta)

Woolworths blocks requests from cloud servers, so this option sends its requests through Apify's Australian residential proxy. It is slower than Coles and ALDI and currently supports search terms and search URLs only (no full specials list yet). Select **Woolworths (beta)** under *Supermarkets* to try it.

### Integrations and API

Use the results anywhere: export to Excel, CSV, JSON or HTML; send them to **Google Sheets**, **Slack**, **Make**, **Zapier** or **Airbyte** with Apify integrations; or call the Actor from your own code with the [Apify API](https://docs.apify.com/api/v2) and the Python or JavaScript client.

### FAQ

**Is it legal to collect these prices?**
The Actor reads only public product and price information that any visitor sees without logging in, and it collects no personal data. It identifies itself as an automated tool rather than pretending to be a browser, keeps its request rate low, and backs off when a site asks it to slow down. You are responsible for how you use the data; if you republish it, check the retailers' terms first. This Actor is not affiliated with, endorsed by or sponsored by Coles, ALDI or Woolworths.

**Are these in-store prices?**
They are the prices on each store's website at the moment of the run. Coles online prices can differ slightly by region and from some in-store prices. ALDI prices are the same nationwide for most products.

**Why is `inStock` empty for ALDI?**
ALDI Australia does not sell groceries online, so its site has no stock level. Special Buys have an `availableFrom` date instead.

**Something isn't working.**
Open an issue on the Actor's Issues tab with your run link and we'll look at it quickly. Store websites change; fixes ship fast.

### Changelog

- **1.0** First release: Coles and ALDI search, categories, specials, Special Buys and product pages; normalised unit prices; price-change tracking; Woolworths beta.

# Actor input Schema

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

Products to look up at every selected supermarket, one per line (e.g. 'milk 2l', 'weet-bix', 'olive oil').

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

Which supermarkets to search and pull specials from. Start URLs always run on the supermarket they belong to. Woolworths is in beta: it blocks cloud servers, so it runs through an Australian residential proxy and is slower.

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

Paste category, specials, search or product pages, e.g. https://www.coles.com.au/browse/dairy-eggs-fridge/milk, https://www.aldi.com.au/products/dairy-eggs-fridge/k/960000000, https://www.aldi.com.au/special-buys, or a single product page to track its price. You can also link a text file of URLs.

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

Collect the full specials lists: Coles specials and every announced ALDI Special Buys date (not yet available in the Woolworths beta). Set 'Max products per source' to 0 to get the complete lists.

## `onlySpecials` (type: `boolean`):

Drop products that are at their regular price. ALDI Special Buys count as specials.

## `maxItemsPerSource` (type: `integer`):

Upper limit for each search term, URL or specials list, per supermarket. 0 means no limit (a full Coles category can be thousands of products).

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

Stop the run after saving this many products. 0 means no limit. You can also cap the cost with the run's maximum charge.

## `deduplicate` (type: `boolean`):

Save each product once per supermarket even if several search terms or URLs find it. You only pay for saved products.

## `trackPriceChanges` (type: `boolean`):

Remember each product's price in a storage on your account and add previousPrice, priceChange, priceChangePercent and isNewProduct to every result. Schedule the Actor daily to build a price history.

## `onlyChanged` (type: `boolean`):

Turns on tracking and saves only products whose price or special changed since the last run, plus products seen for the first time. The first run saves everything as a baseline; later runs are much cheaper.

## `historyStoreName` (type: `string`):

Named key-value store that holds the remembered prices. Use different names to keep separate watch lists apart. Lowercase letters, numbers and dashes only.

## Actor input object example

```json
{
  "searchTerms": [
    "milk",
    "eggs"
  ],
  "retailers": [
    "coles",
    "aldi"
  ],
  "scrapeSpecials": false,
  "onlySpecials": false,
  "maxItemsPerSource": 100,
  "maxItems": 0,
  "deduplicate": true,
  "trackPriceChanges": false,
  "onlyChanged": false,
  "historyStoreName": "au-grocery-price-history"
}
```

# Actor output Schema

## `prices` (type: `string`):

Every product saved in this run: price, was-price, specials, unit prices, category, image and link.

## `priceChanges` (type: `string`):

The same products with their previous price and change, filled when price tracking is on.

## `summary` (type: `string`):

Products saved per store and per source, any sources that failed, and request statistics.

# 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 = {
    "searchTerms": [
        "milk",
        "eggs"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fourteenerdevs/australian-grocery-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 = { "searchTerms": [
        "milk",
        "eggs",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fourteenerdevs/australian-grocery-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 '{
  "searchTerms": [
    "milk",
    "eggs"
  ]
}' |
apify call fourteenerdevs/australian-grocery-prices --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fourteenerdevs/australian-grocery-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/SbOEupyxtRswIcoNM/builds/CxG9lenzhC0pNuW1l/openapi.json
