# Coles AU Scraper (Products, Prices, Specials) (`webdatatools/coles-au-scraper`) Actor

Scrape Coles Australia search results by keyword: product name, brand, pack size, price, was-price specials, unit price, category, stock flag, image, product link and product id.

- **URL**: https://apify.com/webdatatools/coles-au-scraper.md
- **Developed by:** [Murat Uzun](https://apify.com/webdatatools) (community)
- **Categories:** E-commerce, Lead generation, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 results

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

### What is Coles AU Scraper?

Coles AU Scraper collects product search results from coles.com.au, one of Australia's two largest supermarket chains. Give it a keyword such as `milk` or `oat milk` and it returns one row per product: name, brand, pack size, price in AUD, was-price on specials, unit price, stock availability, category, image, product link and product id. It reads the search data that the Coles search page embeds in its HTML, so no login is needed.

### What data does Coles AU Scraper extract?

| Field | Type | Description |
|---|---|---|
| `sku` | string | Coles product id (stable key). |
| `name` | string | Short product name, e.g. `Full Cream Milk`. |
| `brand` | string | Brand as listed, e.g. `Coles`, `Devondale`. |
| `fullName` | string | Long product name with brand and size. |
| `packageSize` | string | Pack size, e.g. `3L`. |
| `price` | number | Current price in AUD. |
| `wasPrice` | number | Previous price when it is above `price`; otherwise null. |
| `onSpecial` | boolean | Online special flag from the price block. |
| `unitPrice` | number | Price per unit of measure. |
| `unitPriceText` | string | Unit price as shown, e.g. `$1.65/ 1L`. |
| `unitOfMeasure` | string | Unit of the unit price, e.g. `1 l`. |
| `inStock` | boolean | Availability flag from the search data. |
| `availabilityType` | string | e.g. `InStoreAndOnline`. |
| `category`, `subCategory`, `aisle` | string | Coles category tree of the first online heir. |
| `imageUrl` | string | Product image from the Coles image host. |
| `url` | string | Product page on coles.com.au (`/product/<name-and-size>-<id>`). |
| `isSponsoredAd` | boolean | True for sponsored product tiles. |
| `searchTerm`, `page`, `position` | mixed | Keyword, search page and rank. |
| `totalResults` | number | Total hits Coles reported for the keyword. |
| `scrapedAt` | string | ISO time of the scrape. |

Banner tiles that Coles mixes into search results are skipped; only product tiles become rows.

### How to use Coles AU Scraper

1. Open the Actor and enter one or more keywords separated by `;`, for example `milk; bread; eggs`.
2. Set **Max products per search** (default 100). Each keyword is scraped separately, up to this limit. About 48 products come per page.
3. Leave **Proxy mode** on `auto`. The Actor tries a direct connection first and switches to Apify's Australian residential proxy only when Coles blocks the request.
4. Click **Start**, then download the dataset as JSON, CSV or Excel, or read it through the API.

### Example input

```json
{
    "keywords": "milk; bread",
    "maxProducts": 60
}
```

### Example output

Real row from a run on 2026-10-23 (keyword `milk`, sixth result, sponsored tile):

```json
[
  {
    "sku": "1329781",
    "name": "High Protein Full Cream Milk",
    "brand": "Devondale",
    "fullName": "DEVONDALE HIGH PROTEIN FULL CREAM MILK 1L",
    "packageSize": "1L",
    "price": 2,
    "wasPrice": 2.5,
    "onSpecial": true,
    "unitPrice": 2,
    "unitPriceText": "$2.00/ 1L",
    "unitOfMeasure": "1 l",
    "inStock": true,
    "availabilityType": "InStoreAndOnline",
    "category": "Long-Life Milk",
    "subCategory": "Drinks",
    "aisle": "Long Life Milk",
    "imageUrl": "https://productimages.coles.com.au/productimages/1/1329781.jpg",
    "url": "https://www.coles.com.au/product/high-protein-full-cream-milk-1l-1329781",
    "isSponsoredAd": true,
    "searchTerm": "milk",
    "page": 1,
    "position": 6,
    "totalResults": 323
  }
]
```

### Input parameters

| Parameter | Default | Meaning |
|---|---|---|
| `keywords` | `milk` | Search terms separated by `;`. |
| `maxProducts` | 100 | Products per keyword, 1 to 5000. |
| `proxyMode` | `auto` | `auto` (direct, residential only after a block), `never` (direct only), `always` (residential from the start). |

### Pricing

Pay per result: **$0.80 per 1,000 products** on the free tier, falling to $0.60 per 1,000 on the highest tiers. The Actor start is charged separately ($0.05 per 1,000 starts). Measured on 2026-10-23: a 120-product run cost $0.0016 at 1 GB, direct only. A 639-product run (4 keywords) cost $0.0165 at 1 GB, including 1.07 MB of residential proxy traffic ($0.008) after Coles blocked one direct page request; the Actor switched to residential and the search continued. The closest public Coles scraper, `dromb/coles-au-product-search-specials-stores-unofficial` (278 monthly users on 2026-10-23), charges $1.00 per 1,000 results on its free tier and $0.70 at its top tiers.

### Coles AU Scraper vs. the alternative

The closest public Coles scraper charges $1.00 per 1,000 results on its free tier. This Actor charges $0.80 on the same tier and returns the unit price, was-price, category and product id in every row.

### Using Coles AU Scraper with AI agents / MCP

The Actor is pay per result and takes a plain keyword input, so an AI agent can call it through the Apify MCP server with `{"keywords": "milk", "maxProducts": 50}`. The output is one flat row per product.

### FAQ

**Does it need a Coles account?** No. It reads the public search page.

**Why do some rows have a was-price?** Coles shows a previous price on many products. In the 120 test rows, 58 had a was-price above the current price. `onSpecial` is the separate online special flag from the same price block.

**Are prices per store?** No. The search page shows the online price set. Store-level prices are not covered.

**Is the `url` and `imageUrl` verified?** Yes. The sample product page and image both returned HTTP 200 when checked on 2026-10-23.

**What happens when Coles blocks the Actor?** Imperva sometimes answers with a page that has no search data. The Actor retries after short waits and then switches to Apify's Australian residential proxy. Searches that still fail go into the `ERRORS` record and are not charged.

**Can I scrape a category page?** Not yet. The Actor searches by keyword only.

**What if the same product matches two keywords?** It is returned once, under the first keyword that found it, and counted once in the charge.

### Limitations

- Keyword search only. No category browsing and no store-level prices or stock.
- `inStock` is the search-data availability flag, not a live stock count.
- A search returns at most the hits Coles reports (`totalResults`); the Actor stops at `maxProducts`.
- Scale tested: 639 products in one run. One direct page was blocked and fetched through the residential proxy. Heavy, sustained blocking was not tested.

### Support

Open an issue on the Actor's Issues tab. Include the keyword, the input JSON and the run ID.

# Actor input Schema

## `keywords` (type: `string`):

What to search for on coles.com.au, several separated by `;` (e.g. `milk; bread; eggs`).

## `maxProducts` (type: `integer`):

For each keyword (about 48 per page).

## `proxyMode` (type: `string`):

auto: direct first, Apify Residential proxy (Australia) only if Coles blocks. never: direct only. always: Residential from the start.

## Actor input object example

```json
{
  "keywords": "milk",
  "maxProducts": 100,
  "proxyMode": "auto"
}
```

# Actor output Schema

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

All products from this run.

# 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 = {
    "keywords": "milk"
};

// Run the Actor and wait for it to finish
const run = await client.actor("webdatatools/coles-au-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 = { "keywords": "milk" }

# Run the Actor and wait for it to finish
run = client.actor("webdatatools/coles-au-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 '{
  "keywords": "milk"
}' |
apify call webdatatools/coles-au-scraper --silent --output-dataset

```

## MCP server setup

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