# Coles & Woolworths Scraper: Prices, Specials & Unit Prices (`egra_van/au-grocery-prices`) Actor

Get Australian supermarket prices from Coles and Woolworths by keyword, category or product ID: current price, was-price, unit price, specials (half price, multi-buy), promotions and stock in one unified format. For price tracking, price comparison apps and grocery specials alerts.

- **URL**: https://apify.com/egra\_van/au-grocery-prices.md
- **Developed by:** [Argentin Vazdautan](https://apify.com/egra_van) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.45 / 1,000 grocery 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 Scraper: Prices, Specials & Unit Prices

Search **Coles** and **Woolworths** (Australia) by keyword, category or product and get **prices, was-prices, unit prices, specials, promotions and stock** from both supermarkets in **one unified format**. Built for price-comparison apps, retail analysts, deal sites and anyone tracking specials.

The Actor reads the same JSON the two websites use, so every field is typed and complete. It handles the stores' bot protection with a real Chrome browser when needed, retries with new IPs and cookies when blocked, and reports every failed search as a clear error row instead of failing the whole run.

*Keywords: Coles scraper, Woolworths scraper, Australian grocery prices, supermarket price comparison, Woolies specials, Coles specials, half price, unit price, grocery price tracker API.*

### What you can do

- 🔎 **Search both stores at once** by keyword ("milk", "tim tam", "nappies")
- 🗂️ **Scrape whole categories** by pasting category links (sub-categories too)
- 🏷️ **Get all current specials**, or keep only specials from your searches (`onlySpecials`)
- 📦 **Check specific products** by link or product number
- ⚖️ **Compare fairly** with unit prices (`$1.34 per 100g`, `$0.38 / 100G`)
- 🧾 **One schema for both stores**: price, was-price, saving, promotion text, stock, category, image, link
- 💸 **Pay only for products returned**. Error rows are free.

### Quick start

**Compare a product across both stores:**

```json
{
  "searchTerms": ["full cream milk 2l", "tim tam"],
  "maxItemsPerSearch": 50
}
```

**All current specials of both stores:**

```json
{
  "onlySpecials": true,
  "maxItemsPerSearch": 2000
}
```

**A category, specials only:**

```json
{
  "categoryUrls": [
    "https://www.coles.com.au/browse/dairy-eggs-fridge",
    "https://www.woolworths.com.au/shop/browse/fruit-veg"
  ],
  "onlySpecials": true
}
```

**Track specific products (e.g. on a daily schedule):**

```json
{
  "productIds": [
    "https://www.woolworths.com.au/shop/productdetails/277728/woolworths-white-sandwich-bread-loaf",
    "https://www.coles.com.au/product/coles-cheese-shredded-tasty-light-700g-8145346",
    "woolworths:49622"
  ]
}
```

### Input

| Field | Default | What it does |
|---|---|---|
| `stores` | both | `coles`, `woolworths`. Applies to search terms, bare product numbers and "Only specials". Links always run on their own store. |
| `searchTerms` | – | Keywords; each is searched in every selected store. |
| `categoryUrls` | – | Category pages from coles.com.au (`/browse/...`, `/on-special`) or woolworths.com.au (`/shop/browse/...`, `/shop/browse/specials`). |
| `productIds` | – | Product links, `coles:1234567` / `woolworths:123456`, or bare numbers (looked up in every selected store). |
| `onlySpecials` | `false` | Keep only products on special. With nothing else filled in, returns the full specials lists. |
| `maxItemsPerSearch` | `100` | Max products saved per search term / category / specials list, per store. |
| `includeSponsored` | `false` | Also keep paid "sponsored/promoted" tiles (marked `isSponsored`). |
| `proxyConfiguration` | Apify Proxy | See **Proxies** below. |
| `useBrowserForCookies` | `true` | Pass Coles' bot protection with a real browser, then use fast JSON requests. |
| `browserFallback` | `true` | If fast requests keep getting blocked, fetch the JSON from inside the browser. |
| `maxPagesPerSearch` | `30` | Safety limit on result pages per search (48 per page on Coles, 36 on Woolworths). |
| `maxRetries`, `requestDelayMs` | `4`, `800` | Retries per request and average pause between requests. |
| `saveDebugPages` | `true` | Save block pages/screenshots as `DEBUG-*` records for diagnosis. |
| `includeRaw` | `false` | Add the store's original product object as `raw`. |

### Output

One item per product. Example output:

```json
[
  {
    "store": "coles",
    "productId": "8145346",
    "name": "Coles Cheese Shredded Tasty Light",
    "brand": "Coles",
    "size": "700g",
    "price": 9.5,
    "wasPrice": null,
    "savings": null,
    "unitPrice": 13.57,
    "unitPriceMeasure": "1kg",
    "unitPriceText": "$13.57 per 1kg",
    "isOnSpecial": false,
    "promoType": "EVERYDAY",
    "promoText": null,
    "inStock": true,
    "isSponsored": false,
    "category": "Dairy, Eggs & Fridge > Cheese > Grated Cheese",
    "barcode": null,
    "imageUrl": "https://productimages.coles.com.au/productimages/8/8145346.jpg",
    "url": "https://www.coles.com.au/product/coles-cheese-shredded-tasty-light-700g-8145346",
    "currency": "AUD",
    "searchTerm": "cheese",
    "categoryUrl": null,
    "scrapedAt": "2026-09-27T08:30:00.588Z"
  },
  {
    "store": "woolworths",
    "productId": "49622",
    "name": "Golden Crumpets Round 6 pack",
    "brand": "Golden",
    "size": "6 pack",
    "price": 2,
    "wasPrice": 4.8,
    "savings": 2.8,
    "unitPrice": 0.33,
    "unitPriceMeasure": "1EA",
    "unitPriceText": "$0.33 / 1EA",
    "isOnSpecial": true,
    "promoType": "HALF_PRICE",
    "promoText": "Half price · Save $2.80",
    "inStock": true,
    "isSponsored": false,
    "category": "Bakery > Packaged Bread & Bakery",
    "barcode": "9310043003014",
    "imageUrl": "https://cdn1.woolworths.media/content/wowproductimages/large/049622.jpg",
    "url": "https://www.woolworths.com.au/shop/productdetails/49622/golden-crumpets-round",
    "currency": "AUD",
    "searchTerm": "crumpets",
    "categoryUrl": null,
    "scrapedAt": "2026-09-27T08:30:00.588Z"
  }
]
```

| Field | Meaning |
|---|---|
| `price` | Current shelf price in AUD (`null` if the store shows no price, e.g. unavailable). |
| `wasPrice`, `savings` | Only filled when the product is really discounted (`wasPrice > price`). |
| `unitPrice`, `unitPriceMeasure`, `unitPriceText` | The store's comparable unit price. |
| `isOnSpecial`, `promoType`, `promoText` | Special flag, type (Coles: `SPECIAL`, `DOWNDOWN`, `EVERYDAY`…; Woolworths: `HALF_PRICE`, `SPECIAL`) and the promotion wording. |
| `inStock` | Whether the product can be bought online. |
| `isSponsored` | Paid placement (only output if `includeSponsored`). |
| `barcode` | EAN/GTIN (Woolworths). |
| `searchTerm` / `categoryUrl` / `productInput` | Which of your inputs produced the row. |

**Error rows** (free) have `isError: true`, the input that failed, `error`, `errorStep`, `httpStatus`, `blocked` and `blockMarkers` — so integrations know exactly which search failed and why. The dataset has three views: **Products**, **Specials & savings** and **Errors**. A run summary (products, requests, retries, blocks, method used per store) is saved as `OUTPUT` in the key-value store.

### Proxies and reliability

Both supermarkets protect their sites against bots (Coles: Imperva; Woolworths: Akamai). The Actor:

1. opens the Coles homepage once in a **real Chrome browser** (with a virtual display, not headless) to pass the check and collect cookies, then loads products with fast JSON requests using those cookies;
2. uses fast plain requests for Woolworths;
3. when a request is blocked: re-acquires cookies → switches to a new IP → loads the JSON **from inside the browser**, and logs every step (HTTP status, what block page was detected, exit IP).

The default **Apify Proxy** works for most runs. If the log shows `BLOCKED` for every attempt, choose proxy group **RESIDENTIAL** with country **Australia (AU)** — residential Australian IPs are the most reliable option, especially for Coles.

### Pricing

Pay per event: **$1.00 per 1,000 products** saved (`product` event). Error rows, retries, blocked attempts and the browser warm-up are not charged. Set a maximum cost per run and the Actor stops cleanly when it is reached.

### Good to know

- Prices are the stores' **default online prices** (Coles online store 0584, Woolworths national online catalogue). Prices of individual physical stores or delivery postcodes can differ slightly and are not selected by this Actor.
- Search results are ranked by the store; sponsored tiles are removed by default and products are de-duplicated per search.
- Woolworths "Everyday Market" (third-party marketplace) items can appear in search results like on the website.
- Data is publicly visible on the stores' websites; use it in line with the stores' terms and applicable law.

### FAQ

**Why did a search return fewer products than `maxItemsPerSearch`?** The store had fewer results, `onlySpecials` filtered them, or `maxPagesPerSearch` was reached (the log says which).

**A run shows "BLOCKED" in the log.** That is the store's bot protection; the Actor retries automatically. If a search still fails, it appears as an error row with the detected block page. Use the RESIDENTIAL proxy with country AU and slow down by raising `requestDelayMs` to 1500–3000 ms.

**Can I get Aldi or IGA?** Not yet — planned.

# Actor input Schema

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

Which supermarkets to search. Search terms, bare product numbers and "Only specials" run on every selected store. Category and product links always run on the store they belong to.

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

Keywords to search in each selected store, e.g. "milk", "tim tam", "nappies". Each term returns up to "Max products per search" products per store.

## `categoryUrls` (type: `array`):

Category pages copied from the store website, e.g. https://www.coles.com.au/browse/dairy-eggs-fridge or https://www.woolworths.com.au/shop/browse/fruit-veg. Sub-categories work too. Use https://www.woolworths.com.au/shop/browse/specials or https://www.coles.com.au/on-special for the current specials.

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

Specific products to check: product links (https://www.coles.com.au/product/...-1234567, https://www.woolworths.com.au/shop/productdetails/123456/...), prefixed IDs ("coles:1234567", "woolworths:123456") or bare product numbers, which are looked up in every selected store.

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

Return only products that are on special (a was-price, a half-price or a promotion). With no search terms, categories or products, the Actor returns the stores' full specials lists.

## `maxItemsPerSearch` (type: `integer`):

Maximum number of products saved for each search term, category or specials list, per store. You pay only for products saved.

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

Also save the paid 'sponsored' / 'promoted' products the stores insert into results. Off by default because they often don't match the search and repeat on every page. Sponsored rows are marked with isSponsored.

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

Proxy used for both stores. The default Apify Proxy works in most cases. If the log says requests are BLOCKED, switch to the RESIDENTIAL group with country Australia (AU) — Coles in particular is protected by Imperva.

## `useBrowserForCookies` (type: `boolean`):

Open the Coles homepage once in a real Chrome browser to pass its bot protection and collect cookies, then load products with fast JSON requests. Keep this on: Coles blocks plain requests. Woolworths never needs it (a browser is only used there if plain requests get blocked).

## `browserFallback` (type: `boolean`):

If fast requests keep getting blocked, load the JSON from inside the real browser (slower, but looks exactly like a visitor). Recommended.

## `maxPagesPerSearch` (type: `integer`):

Safety limit on result pages read per search term or category (Coles shows 48 products per page, Woolworths 36). Mostly matters with "Only specials", where many pages may be checked to find enough specials.

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

How many times a failed or blocked request is retried (with a new IP and new cookies when blocked) before that search is reported as failed.

## `requestDelayMs` (type: `integer`):

Average pause between two requests to the same store. Slower is less likely to be blocked.

## `saveDebugPages` (type: `boolean`):

When a store answers with a block/captcha page, save up to 4 such pages (and a browser screenshot) per store to the run's key-value store as DEBUG-\* records. Free; helps report problems.

## `includeRaw` (type: `boolean`):

Add the original product object from the store's API as a "raw" field on every product (large; for debugging or fields not in the unified format).

## `colesBaseUrl` (type: `string`):

For testing only: send Coles requests to this address instead of https://www.coles.com.au (e.g. a local mock server). Leave empty.

## `woolworthsBaseUrl` (type: `string`):

For testing only: send Woolworths requests to this address instead of https://www.woolworths.com.au (e.g. a local mock server). Leave empty.

## Actor input object example

```json
{
  "stores": [
    "coles",
    "woolworths"
  ],
  "searchTerms": [
    "milk"
  ],
  "onlySpecials": false,
  "maxItemsPerSearch": 100,
  "includeSponsored": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "useBrowserForCookies": true,
  "browserFallback": true,
  "maxPagesPerSearch": 30,
  "maxRetries": 4,
  "requestDelayMs": 800,
  "saveDebugPages": true,
  "includeRaw": false
}
```

# Actor output Schema

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

All result items of this run.

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

Summary of the run with counts and download links.

# 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"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("egra_van/au-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"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("egra_van/au-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"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call egra_van/au-grocery-prices --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,egra_van/au-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/ffINZ3zNw3LYRsR6h/builds/VY3cH9ed44H2Wltst/openapi.json
