# Coles Australia Scraper: Unit Prices, Specials, Stock & Alerts (`getascraper/coles-scraper`) Actor

Scrape product data, live prices, and weekly specials from Coles Australia (coles.com.au). Search by keyword, category or specials URLs, or specific SKUs. Get true unit pricing per kg, per L, or each, stock availability, purchase limits, category taxonomy, and optional price or stock change alerts.

- **URL**: https://apify.com/getascraper/coles-scraper.md
- **Developed by:** [GetAScraper](https://apify.com/getascraper) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 288 total users, 216 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.00 / 1,000 product records

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 Australia Scraper: Unit Prices, Specials, Stock & Alerts

<table width="100%">
<tr>
<td style="padding:24px 28px;background:#FBEDEC;border:1px solid #F5C6C4;border-top:4px solid #E01A22;border-radius:12px">
<span style="font-size:23px;font-weight:800;color:#1C1917;line-height:1.3">Coles prices you can actually compare</span><br>
<span style="font-size:15px;color:#57534E;line-height:1.6">Scrape Coles Australia products with a true per-kg or per-L price already worked out, honest specials math, and optional alerts when a price or stock level moves.</span>
</td>
</tr>
</table>

<table width="100%">
<tr>
<td style="padding:14px 12px;width:25%;background:#FFFFFF;border:1px solid #F5C6C4;border-radius:10px 0 0 10px;vertical-align:top">
<span style="font-size:15px;font-weight:800;color:#E01A22">📏 True unit pricing</span><br>
<span style="font-size:12px;color:#57534E">A real price per kg or per L on every row, not a label that mixes per-100g and per-kg listings.</span>
</td>
<td style="padding:14px 12px;width:25%;background:#FFFFFF;border:1px solid #F5C6C4;border-left:none;vertical-align:top">
<span style="font-size:15px;font-weight:800;color:#E01A22">🏷️ Honest specials math</span><br>
<span style="font-size:12px;color:#57534E">A markdown only shows as a markdown when the original price genuinely beats today's price.</span>
</td>
<td style="padding:14px 12px;width:25%;background:#FFFFFF;border:1px solid #F5C6C4;border-left:none;vertical-align:top">
<span style="font-size:15px;font-weight:800;color:#E01A22">🔔 Price & stock alerts</span><br>
<span style="font-size:12px;color:#57534E">Turn on change tracking for new, dropped, risen, and restocked items on every scheduled run.</span>
</td>
<td style="padding:14px 12px;width:25%;background:#FFFFFF;border:1px solid #F5C6C4;border-left:none;border-radius:0 10px 10px 0;vertical-align:top">
<span style="font-size:15px;font-weight:800;color:#E01A22">📦 Full stock detail</span><br>
<span style="font-size:12px;color:#57534E">Purchase limits, available quantity, and stock channel on every row.</span>
</td>
</tr>
</table>

Point this scraper at any Coles search term, category page, or product SKU. It returns clean pricing, was/now markdown discounts, a normalized unit price, stock availability, and full product details. No login required.

### 🔍 What does this actor do?

Coles is one of Australia's two largest supermarket chains, with more than 800 stores. This scraper pulls structured product data from Coles Australia (coles.com.au) so you can track prices, specials, and availability at scale.

You can scrape three ways: by keyword search, by pasting category or weekly specials URLs, or by feeding a list of product SKUs. Results download as JSON, CSV, Excel, or XML.

### 💡 Who uses this?

- **I am a pricing analyst at a competing grocery brand.** Every morning I need to know exactly what Coles charges per kilo on my category, not just the sticker price, before I set today's price match.
- **I am a category manager at an FMCG supplier.** I need to know which of my SKUs just went on markdown and by how much, without opening dozens of product pages by hand.
- **I am a data journalist covering cost of living.** I track a weekly grocery basket and need true per-kg and per-L prices on staples like milk, bread, and eggs, not numbers that mix per-100g and per-kg listings.
- **I am an online reseller.** I want an alert the moment a product goes on markdown or comes back in stock, not a reason to keep refreshing the page.

### 🚀 How to use

<table width="100%">
<tr>
<td style="padding:16px 14px;width:33%;background:#FBEDEC;border:1px solid #F5C6C4;border-radius:10px 0 0 10px;vertical-align:top">
<span style="font-size:12px;font-weight:800;color:#E01A22;letter-spacing:1px">STEP 1</span><br>
<span style="font-size:14px;font-weight:700;color:#1C1917">Choose your scope</span><br>
<span style="font-size:12px;color:#57534E">Search a keyword, paste a category or specials URL, or drop in a SKU list.</span>
</td>
<td style="padding:16px 14px;width:33%;background:#FBEDEC;border:1px solid #F5C6C4;border-left:none;vertical-align:top">
<span style="font-size:12px;font-weight:800;color:#E01A22;letter-spacing:1px">STEP 2</span><br>
<span style="font-size:14px;font-weight:700;color:#1C1917">Get comparable data</span><br>
<span style="font-size:12px;color:#57534E">Every row lands with a true per-kg or per-L price and clean specials math, ready to sort.</span>
</td>
<td style="padding:16px 14px;width:33%;background:#FBEDEC;border:1px solid #F5C6C4;border-left:none;border-radius:0 10px 10px 0;vertical-align:top">
<span style="font-size:12px;font-weight:800;color:#E01A22;letter-spacing:1px">STEP 3</span><br>
<span style="font-size:14px;font-weight:700;color:#1C1917">Track what changes</span><br>
<span style="font-size:12px;color:#57534E">Turn on change monitoring to see only what's new, dropped, risen, or restocked on repeat runs.</span>
</td>
</tr>
</table>

### 📥 Input

| Field | Type | Required | Description |
|---|---|---|---|
| `scrapeMode` | enum | Yes | How to find products: `searchKeyword`, `providedUrls`, or `skuList`. |
| `searchQuery` | string | No | Search term, product name, or barcode. Used in keyword search mode. |
| `startUrls` | array of URLs | No | Coles search, category, or weekly specials URLs. Used in category mode. |
| `skuList` | array | No | Specific Coles product SKU IDs to scrape. Used in SKU list mode. |
| `includeDescription` | boolean | No | Include the full product description text. Default: true. |
| `maxItems` | integer | No | Maximum number of products to scrape per run. Default: 25. |
| `maxRequestsPerCrawl` | integer | No | Maximum pages to load per run. Set to 0 for no limit. |
| `monitorMode` | enum | No | `snapshot` (default) returns current data every run. `changes` compares against the last run of the same Watchlist name and adds change fields to every row. |
| `stateName` | string | No | Watchlist name that separates independent change-tracking scopes. Only used when `monitorMode` is `changes`. |
| `onlyChanged` | boolean | No | When `monitorMode` is `changes`, emit only rows that changed since the last run. Default: false. |
| `proxyConfiguration` | proxy | No | Keep the datacenter default. Blocked attempts are retried automatically on a fresh IP, and residential proxies cost far more per run for the same data. Switch only if a very large run still fails after retries. |

### 📊 Data table

| Field                 | Type            | Description                                                                                                                                         |
| --------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `product_id`          | string          | Unique Coles product SKU.                                                                                                                           |
| `name`                | string          | Product name as listed on Coles.                                                                                                                    |
| `brand`               | string | null  | Brand name, when published by the source.                                                                                                           |
| `description`         | string          | Full product description text.                                                                                                                      |
| `size`                | string | null  | Pack size or volume, for example "2L", when published.                                                                                              |
| `availability`        | boolean | null | Whether the product is currently in stock, when published.                                                                                          |
| `availability_type`   | string | null  | Stock channel, for example "InStoreAndOnline", when published.                                                                                      |
| `available_quantity`  | integer | null | Units currently available, including a genuine 0 for an out-of-stock item.                                                                          |
| `price`               | number | null  | Current retail price.                                                                                                                               |
| `original_price`      | number | null  | Pre-discount "was" price, only when the source published a real one.                                                                                |
| `on_special`          | boolean         | Whether `original_price` genuinely exceeds `price`.                                                                                                 |
| `discount_amount`     | number | null  | `original_price` minus `price`, only when `on_special` is true.                                                                                     |
| `discount_percent`    | number | null  | Discount as a percentage of `original_price`, only when `on_special` is true.                                                                       |
| `currency`            | string          | Currency code, always AUD.                                                                                                                          |
| `comparable`          | string          | The unit price exactly as Coles displays it, for example "$3.39/ 100g".                                                                             |
| `unit_price`          | number | null  | The numeric unit price behind `comparable`.                                                                                                         |
| `unit_price_quantity` | number | null  | The quantity that `unit_price` is per, for example 100.                                                                                             |
| `unit_price_unit`     | string | null  | The unit that `unit_price` is per, for example "g".                                                                                                 |
| `unit_price_basis`    | string | null  | Normalized comparison basis: `kg`, `L`, or `ea`.                                                                                                    |
| `price_per_base_unit` | number | null  | The true price per full `unit_price_basis` unit, always comparable across products, unlike `comparable`, which mixes per-100g and per-1kg displays. |
| `image_url`           | string | null  | Full-resolution product image URL.                                                                                                                  |
| `category`            | string          | Top-level Coles category for the product.                                                                                                           |
| `url`                 | string          | Direct link to the Coles product page.                                                                                                              |
| `scraped_at`          | string          | Timestamp when the record was extracted.                                                                                                            |
| `retail_limit`        | integer | null | Maximum units a shopper can buy.                                                                                                                    |
| `promotional_limit`   | integer | null | Purchase limit that applies during a promotion.                                                                                                     |
| `online_special`      | boolean | null | Whether the item is an online-only special.                                                                                                         |
| `sub_category`        | string | null  | More specific category below the top level.                                                                                                         |
| `class_name`          | string | null  | Coles product classification label.                                                                                                                 |
| `trade_profit_centre` | string | null  | Coles's internal merchandise grouping, e.g. "DAIRY".                                                                                                |
| `category_group`      | string | null  | A broader grouping above `category`.                                                                                                                |
| `change_type`         | string          | Only present in `changes` mode: `NEW`, `PRICE_DROP`, `PRICE_RISE`, `BACK_IN_STOCK`, `OUT_OF_STOCK`, or `UNCHANGED`.                                 |
| `old_price`           | number | null  | Only present in `changes` mode: the price from the previous run.                                                                                    |
| `price_delta`         | number | null  | Only present in `changes` mode: `price` minus `old_price`.                                                                                          |
| `price_delta_pct`     | number | null  | Only present in `changes` mode: `price_delta` as a percentage of `old_price`.                                                                       |
| `old_available_quantity` | integer | null | Only present in `changes` mode: `available_quantity` from the previous run.                                                                      |
| `is_changed`          | boolean         | Only present in `changes` mode: whether this row differs from the previous run in any tracked field.                                                |

You can download the dataset in JSON, HTML, CSV, or Excel from the Output tab of any run.

### 📤 Sample output

```json
{
    "product_id": "8150288",
    "name": "Full Cream Milk",
    "brand": "Coles",
    "description": "Coles Full Cream Milk | 3L",
    "size": "3L",
    "availability": true,
    "availability_type": "InStoreAndOnline",
    "available_quantity": 245,
    "price": 4.95,
    "currency": "AUD",
    "on_special": false,
    "comparable": "$1.65/ 1L",
    "unit_price": 1.65,
    "unit_price_quantity": 1,
    "unit_price_unit": "l",
    "unit_price_basis": "L",
    "price_per_base_unit": 1.65,
    "image_url": "https://productimages.coles.com.au/productimages/8/8150288.jpg",
    "category": "MILK",
    "url": "https://www.coles.com.au/product/8150288",
    "scraped_at": "2026-09-08T12:00:00.000Z",
    "retail_limit": 20,
    "promotional_limit": 12,
    "online_special": false,
    "sub_category": "WHITE MILK",
    "class_name": "FULL CREAM",
    "trade_profit_centre": "DAIRY",
    "category_group": "DAIRY"
}
```

### 💰 Pricing

Pricing is pay per result. You are charged only for products successfully written to your dataset. Empty runs and blocked requests cost nothing. There are no monthly subscriptions or minimum commitments.

Free-plan requests are limited to 25 products per run, 3 admitted runs per rolling 24 hours, and a 30-minute wait between runs. These limits do not apply to paid plans. When a frequency limit is reached, the run completes without starting a crawl or writing dataset items; the terminal run status and logs explain the limit and upgrade path.

### ⭐ Enjoying Coles Australia Scraper?

<table width="100%">
<tr>
<td style="padding:20px 24px 14px;background:#FBEDEC;border:1px solid #F5C6C4;border-left:5px solid #E01A22;border-radius:10px 10px 0 0">
<span style="font-size:20px;letter-spacing:4px">⭐ ⭐ ⭐ ⭐ ⭐</span><br>
<span style="font-size:17px;font-weight:800;color:#1C1917">One run just told you which Coles price actually wins, not just which one looks cheapest.</span><br>
<span style="font-size:14px;color:#57534E">A 5-star rating takes 10 seconds and helps other pricing analysts and category managers find this actor. Your feedback also tells us what to build next.</span>
</td>
</tr>
<tr>
<td style="padding:0;background:#E01A22;border:1px solid #F5C6C4;border-top:none;border-radius:0 0 10px 10px;text-align:center">
<a href="https://apify.com/getascraper/coles-scraper/reviews" style="display:block;padding:13px 16px;color:#FFFFFF;text-decoration:none;font-weight:800;font-size:15px;letter-spacing:0.3px">★&nbsp;&nbsp;Rate this Actor on Apify</a>
</td>
</tr>
</table>

### ✨ Tips

- **Track weekly specials.** Paste a specials URL like the half-price page as a start URL to capture every markdown in one run.
- **Compare prices fairly.** Sort or filter on `price_per_base_unit`, not `price` or the raw `comparable` string. Coles displays some products per-100g and others per-1kg, so the sticker numbers alone aren't comparable.
- **Get alerted, not just logged.** Set `monitorMode` to `changes` and schedule the run. Each run after the first only reports what actually moved.
- **Start small.** Set a low `maxItems` for your first run to confirm the output matches what you need before scaling up.

### ❓ FAQ

##### Which Coles pages can I scrape?

You can scrape keyword search results, category and browse pages, weekly specials pages, and individual product SKUs. Pick the mode that matches your input.

##### Can I get prices for a specific store or region?

No, this actor does not support pinning a specific Coles store. Coles resolves store-specific pricing automatically based on network location, and there is no way to override that from a scraper input. Every run reflects whatever store Coles resolves for that run.

##### Why is there no in-store aisle location field?

Coles's own product data confirms this isn't published online for any product. The field that would carry it is a placeholder message telling shoppers to ask staff in-store, so no scraper can extract data the source doesn't have.

##### How fresh is the data?

Every run fetches live data directly from Coles. Results reflect the prices, specials, and stock shown on the site at the moment the run executes.

##### Is scraping Coles legal?

This actor reads publicly available product pages, the same pages any shopper can open without logging in. You are responsible for complying with Coles' terms of service and applicable laws. For questions or custom fields, contact the author at <devanshtiwari365@gmail.com>.

### 🔗 Other actors

- [🛒 Kroger Scraper: Product Prices, Stock & Search](https://apify.com/getascraper/kroger-scraper) ↗ - extracts product prices, stock, and search results from Kroger in the US.
- [🛒 Kroger Price Monitor: Price & Stock Change Alerts](https://apify.com/getascraper/kroger-price-monitor) ↗ - tracks price and stock changes on Kroger grocery listings.
- [💰 Falabella Price Monitor: Alerta de Precios (Chile, Peru, Colombia)](https://apify.com/getascraper/falabella-price-monitor) ↗ - watches prices and stock alerts across Falabella in Chile, Peru, and Colombia.
- [💰 Trendyol Price Monitor: Fiyat Takibi (Türkiye)](https://apify.com/getascraper/trendyol-price-monitor) ↗ - tracks price and stock changes on Trendyol listings in Turkey.
- [Woot Scraper: Daily Deals, Flash Sales & Clearance Prices](https://apify.com/getascraper/woot-scraper) ↗ - collects daily deal listings and prices from Woot.

# Changelog

This Actor's version history is a separate document: https://apify.com/getascraper/coles-scraper/changelog.md

# Actor input Schema

## `scrapeMode` (type: `string`):

Choose whether to search by keyword, browse category URLs, or input a custom SKU list.

## `searchQuery` (type: `string`):

The search keyword, product name, or barcode/EAN to query (e.g., 'milk', '9300601385150'). Only used in Keyword Search mode.

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

Paste Coles search, category, or weekly Specials URLs (e.g., 'https://www.coles.com.au/specials/half-price') to scrape directly.

## `skuList` (type: `array`):

Input specific Coles product SKU IDs to scrape their specifications directly. Only used in Direct SKU List mode.

## `includeDescription` (type: `boolean`):

Extract full text product descriptions for each item when found.

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

Maximum number of product listings to extract. Free-plan requests above 25 are capped at 25; paid plans may use the requested value.

## `maxRequestsPerCrawl` (type: `integer`):

Maximum number of page requests/paginations that can be made by this crawler (0 = unlimited).

## `monitorMode` (type: `string`):

Snapshot returns the current data every run. Changes compares each run against the last run of the same Watchlist name and adds change_type (NEW, PRICE_DROP, PRICE_RISE, BACK_IN_STOCK, OUT_OF_STOCK, UNCHANGED) plus the prior price to every row.

## `stateName` (type: `string`):

Distinguishes separate change-tracking scopes (e.g. different searches on a schedule). Only used when Monitor mode is Changes.

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

When Monitor mode is Changes, emit only rows whose price or stock changed since the last run (skips UNCHANGED rows). The first run always emits every row as NEW.

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

Keep the datacenter default. It is measurably the cheapest option that works on Coles, and blocked attempts are retried automatically on a fresh IP. Australian residential proxies cost roughly 10 to 75 times more per run for the same data, so switch only if a very large run is still failing after retries.

## Actor input object example

```json
{
  "scrapeMode": "searchKeyword",
  "searchQuery": "milk",
  "startUrls": [
    {
      "url": "https://www.coles.com.au/browse/fruit-vegetables/vegetables"
    }
  ],
  "skuList": [
    "5900530",
    "4845732"
  ],
  "includeDescription": true,
  "maxItems": 25,
  "maxRequestsPerCrawl": 100,
  "monitorMode": "snapshot",
  "stateName": "default",
  "onlyChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "scrapeMode": "searchKeyword",
    "searchQuery": "milk",
    "startUrls": [
        {
            "url": "https://www.coles.com.au/browse/fruit-vegetables/vegetables"
        }
    ],
    "skuList": [
        "5900530",
        "4845732"
    ],
    "includeDescription": true,
    "maxItems": 25,
    "maxRequestsPerCrawl": 100,
    "monitorMode": "snapshot",
    "stateName": "default",
    "onlyChanged": false,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("getascraper/coles-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 = {
    "scrapeMode": "searchKeyword",
    "searchQuery": "milk",
    "startUrls": [{ "url": "https://www.coles.com.au/browse/fruit-vegetables/vegetables" }],
    "skuList": [
        "5900530",
        "4845732",
    ],
    "includeDescription": True,
    "maxItems": 25,
    "maxRequestsPerCrawl": 100,
    "monitorMode": "snapshot",
    "stateName": "default",
    "onlyChanged": False,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("getascraper/coles-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 '{
  "scrapeMode": "searchKeyword",
  "searchQuery": "milk",
  "startUrls": [
    {
      "url": "https://www.coles.com.au/browse/fruit-vegetables/vegetables"
    }
  ],
  "skuList": [
    "5900530",
    "4845732"
  ],
  "includeDescription": true,
  "maxItems": 25,
  "maxRequestsPerCrawl": 100,
  "monitorMode": "snapshot",
  "stateName": "default",
  "onlyChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call getascraper/coles-scraper --silent --output-dataset

```

## MCP server setup

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