# Coles Scraper: Prices, Specials, Down Down & Unit Prices (`vant47/coles-scraper`) Actor

Get Coles products with price, was price, specials, Down Down, half price, multi-buys, unit price, stock, brand, size and category at a verified store for your postcode. Optional barcode, ingredients and nutrition. About $0.0016 per product, including details. No login.

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

## Pricing

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

## Coles Scraper: Prices, Specials, Down Down & Unit Prices

For retail price analysts, grocery brands and comparison services that need current Coles prices tied to an identifiable Australian store.

About **US$0.0016 per product**, including optional barcode, ingredients and nutrition. A 20-product check costs about **US$0.032**, plus the small Actor start fee. Product prices are in AUD. No login.

Search milk, coffee or Tim Tam, read a category or specials page, or provide product links and IDs. Every delivered product row names its price store. Repeated products at the same store are delivered and charged once.

### What you get

Missing fields are `null`; was prices and promotion dates are never guessed. Displayed comparable units take precedence over inconsistent structured unit fields.

| Field | Meaning |
| --- | --- |
| `retailer`, `country`, `currency` | Coles, AU and AUD |
| `storeId`, `storeName` | The verified Coles online price store |
| `location` | Requested postcode, or null for an explicit/default store |
| `productId` | Coles product identifier, returned as a string |
| `sku` | A separate SKU only if supplied by the source |
| `gtin` | Source barcode, normally available with product details |
| `title`, `brand`, `size` | Product name, brand and pack size |
| `price` | Current price at the confirmed store |
| `regularPrice` | The source's was price; zero sentinels become null |
| `onSale` | Whether the current source record indicates a price promotion |
| `promoText`, `promoType` | Offer wording and the source promotion classification |
| `promoStart`, `promoEnd` | Explicit source promotion dates, otherwise null |
| `memberPrice`, `memberProgram` | Public member pricing when supplied, otherwise null |
| `unitPrice`, `unitOfMeasure` | Comparable price and its quantity/measure, such as 100g |
| `inStock`, `stockLevel` | Source availability flag and available quantity when supplied |
| `rating`, `reviewCount` | Source review information, otherwise null |
| `category` | Readable Coles category path |
| `url`, `imageUrl` | Product link and primary image |
| `scrapedAt` | Observation timestamp in UTC |

Extras preserve `onlineHeirs`, `rawPricing`, comparable-price text, multi-buys, availability type, purchase limits and aisles. Details add ingredients, allergens, nutrition, origin and description.

Overview shows prices, promotions, availability and store. The Deals view shows promotion fields. Use `dealsOnly` for a dataset containing only promotional products.

### Choose a price store

Provide `locations` as four-digit Australian postcodes, including leading zeroes. Coles resolves a postcode into one or more localities. This Actor uses the first matching locality returned by Coles and selects the nearest trading Coles supermarket that has a collection point. The result identifies the selected suburb, distance and store postcode separately from your requested postcode.

In the 28 October 2026 test, postcode 2000 selected **Coles Pyrmont, store 728**, and 3000 selected **Coles Collingwood, store 7842**. Store postcodes can differ from the requested postcode. This does not establish delivery service for a street address.

For repeat monitoring, use `storeIds` once you have chosen the exact store. Store 313 is Coles Karratha. Empty `locations` and `storeIds` use the site's default online price store, which is resolved and identified in the output.

Before accepting a product response, the Actor checks Coles' returned store identifier against the selected store. A mismatched response becomes a free note. It is never relabelled as the requested store's price.

### Start in three steps

1. Open the input form and enter a search term, postcode and maximum product count.
2. Run the Actor and inspect the Overview and run summary.
3. Export JSON for complete nested detail, or CSV for a spreadsheet. Save the same input as a task for repeat checks.

The prefill delivered **20 milk prices near postcode 2000 in 33 seconds**. All three products in a Tim Tam detail check were enriched. Times vary with source responses and retries.

#### Search prices near one postcode

```json
{
  "searchTerms": ["milk"],
  "locations": ["2000"],
  "maxItemsPerSearch": 20,
  "maxItems": 20,
  "includeDetails": false
}
```

#### Compare an exact store and enrich products

```json
{
  "searchTerms": ["tim tam"],
  "storeIds": ["313"],
  "maxItemsPerSearch": 10,
  "maxItems": 10,
  "includeDetails": true
}
```

#### Read categories and half-price offers

```json
{
  "startUrls": [
    "https://www.coles.com.au/browse/pantry",
    "https://www.coles.com.au/on-special?filter_Special=halfprice"
  ],
  "locations": ["3000"],
  "maxItemsPerSearch": 20,
  "maxItems": 40
}
```

Combine plain URL strings and numeric `productIds` in one run. Canonical redirects, including apostrophes in brand names, are followed.

### Input reference

| Input | Purpose |
| --- | --- |
| `searchTerms` | Array of search terms; milk is used when no source is provided |
| `startUrls` | Optional public Coles product, category, search or specials links |
| `productIds` | Optional numeric Coles product IDs |
| `locations` | Postcodes used to select online stores |
| `storeIds` | Explicit Coles supermarket IDs; can combine with postcodes |
| `maxItemsPerSearch` | New product rows per source per store; default 20, maximum 5,000 |
| `maxItems` | Overall product/store row limit; default 20, maximum 10,000 |
| `dealsOnly` | Keep price promotions; without other sources, reads specials |
| `includeDetails` | Fetch slower barcode, ingredients, nutrition and other extras at no extra price |
| `proxyConfiguration` | Optional custom proxy settings; empty uses automatic fallback |

For ten products in each of three stores, set `maxItemsPerSearch` to 10 and overall `maxItems` to 30. Duplicates can reduce the total.

`dealsOnly` recognises source specials and multi-buy signals. An Every Day label by itself is not treated as a discount. A missing source price cannot become a paid product row. A search with no matches can complete with no product charge.

### A real product example

This shortened row came from the 28 October 2026 detail test at Coles Karratha. Stock quantities can change between observations.

```json
{
  "retailer": "Coles",
  "country": "AU",
  "currency": "AUD",
  "storeId": "313",
  "storeName": "Coles Karratha",
  "location": null,
  "productId": "329607",
  "gtin": "9310072000282",
  "title": "Tim Tam Chocolate Biscuits Original",
  "brand": "Arnott's",
  "size": "200g",
  "price": 4.5,
  "regularPrice": 6.42,
  "onSale": true,
  "promoText": "save $1.92",
  "promoType": "SPECIAL",
  "promoStart": null,
  "promoEnd": null,
  "memberPrice": null,
  "unitPrice": 2.25,
  "unitOfMeasure": "100g",
  "inStock": true,
  "stockLevel": 275,
  "detailsStatus": "complete"
}
```

Milk at Coles Pyrmont showed A$4.95 for 3L and A$1.65 per litre. The absent was price remained null.

### Pricing and spending limits

One Product charge covers one distinct product at one store. Enabling details changes the amount of source work and the available fields, not the Product price. There is no separate detail, retry, failure or automatic dataset-item charge.

| Job | Product price before plan discounts |
| --- | --- |
| 20 product/store rows | US$0.032 |
| 100 product/store rows | US$0.16 |
| 1,000 product/store rows | US$1.60 |
| 20 products at three stores | US$0.096 |

The platform start fee is US$0.00005 per GB, with a minimum of one start unit. Bronze receives 5% off the Product price, Silver 10%, and Gold and higher tiers 20%. Platform compute, storage and the automatic Apify proxy path are included in the Actor price.

Set a maximum total charge in Apify for a firm budget. The Actor checks room for the next Product before fetching more product work, saves a row before charging it, and stops cleanly at the limit. Free note rows explain invalid inputs or refused sources. A repeated product at another store is a separate useful price observation and is charged once for that store.

### Monitor prices every day

Create a saved task with a fixed store ID, stable product IDs or a category link. Add a daily Apify schedule at your preferred local time. Keep the store and product identifiers with each export, and retain `scrapedAt` so changes can be ordered correctly.

For promotions, schedule a specials task. Key observations by `productId`, `storeId` and `scrapedAt`. This Actor returns current snapshots, not historical backfill. Webhooks can move completed data to a database, spreadsheet, n8n or Make. Compare equivalent pack sizes and unit measures before calculating changes.

### API use

Start a bounded run with a token from your own Apify account:

```bash
curl -X POST \
  'https://api.apify.com/v2/acts/vant47~coles-scraper/runs?memory=512&maxTotalChargeUsd=0.10' \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"searchTerms":["milk"],"locations":["2000"],"maxItems":20}'
```

Poll the run ID, then read its dataset. `SUMMARY` is in its key-value store. Use asynchronous runs for larger jobs.

Python example:

```python
import os
import time
import requests

base = "https://api.apify.com/v2"
headers = {"Authorization": "Bearer " + os.environ["APIFY_TOKEN"]}
response = requests.post(
    base + "/acts/vant47~coles-scraper/runs",
    params={"memory": 512, "maxTotalChargeUsd": 0.10},
    headers=headers,
    json={"searchTerms": ["milk"], "locations": ["2000"], "maxItems": 20},
    timeout=60,
)
response.raise_for_status()
run = response.json()["data"]
while run["status"] in ("READY", "RUNNING"):
    time.sleep(2)
    response = requests.get(base + "/actor-runs/" + run["id"], headers=headers, timeout=60)
    response.raise_for_status()
    run = response.json()["data"]
items = requests.get(
    base + "/datasets/" + run["defaultDatasetId"] + "/items",
    headers=headers,
    timeout=60,
).json()
```

JavaScript can use the same endpoints with `fetch`:

```javascript
const headers = {
  Authorization: `Bearer ${process.env.APIFY_TOKEN}`,
  'Content-Type': 'application/json',
};
const response = await fetch(
  'https://api.apify.com/v2/acts/vant47~coles-scraper/runs?maxTotalChargeUsd=0.10',
  { method: 'POST', headers, body: JSON.stringify({
      searchTerms: ['coffee'], storeIds: ['313'], maxItems: 20,
  }) },
);
if (!response.ok) throw new Error(`Apify returned ${response.status}`);
const { data: run } = await response.json();
console.log(run.id);
```

### Use with AI agents (MCP)

Connect your assistant to `https://mcp.apify.com` with your Apify account. Ask it to use `vant47/coles-scraper`, provide a small `maxItems`, and inspect the returned store IDs before making a comparison.

A useful request is: "Get Coles milk prices near postcode 2000. Return 20 products with current price, unit price and stock, and tell me which store supplied the prices. Keep the maximum charge at US$0.10."

Add `includeDetails: true` for enrichment. Preserve nulls and the run summary. No outside AI key is required.

### Reliability and data limits

Requests are serial and paced, honour Retry-After and use fresh retry sessions. Datacenter proxy comes first, then Australian residential after refusals. Custom settings override this.

The dataset is the durable delivery ledger. Reboots recover saved rows and acknowledged charges before new work. Page candidates are saved before delivery; replayed acknowledgements do not create another Product charge.

Enrichment uses small batches of public product GraphQL requests. Prices and stock are store-scoped. Split inputs exceeding 1,000 source/location combinations.

Public client configuration is cached for one hour and public store-selection metadata for six hours. Product prices, promotions and stock are fetched fresh for the run. A changed site build can refresh configuration automatically. Cached metadata does not permit an unconfirmed store price to pass.

The source often omits promotion dates, public member prices and ratings. These fields were null in the initial sample where Coles did not provide them. Personalised Flybuys offers and account-specific prices are not retrieved. Public offer text is preserved where supplied; no member benefit is inferred from an ordinary special.

`stockLevel` is the source's available quantity, which can differ from stock physically on a shelf. Some listing types provide only availability and no quantity. Variable-weight products retain the displayed current price and comparable unit information; the final basket charge can depend on purchased weight.

If one source is refused, completed products remain in the dataset and a free note identifies the affected input. Check `SUMMARY.status` and `freeFailures` before treating an export as complete. Removed products, empty searches and input mistakes do not produce paid product rows.

### FAQ

**Can I compare several stores?** Yes. Supply multiple postcodes or store IDs and increase the overall `maxItems` enough to cover them. Each row identifies its actual store.

**Does the postcode have to equal the store postcode?** No. A postcode selects a nearby online store through Coles' locality and store directory. Both values are preserved so you can audit the selection.

**Are ingredients and barcodes extra?** No. Turn on `includeDetails` for slower enrichment at the same Product price. Product links can already contain rich detail without an additional request.

**Can I use it without a Coles account?** Yes. It reads signed-out public product information. It does not sign in or solve verification challenges.

This is an independent Coles price data tool. Review the source's [website terms](https://www.coles.com.au/important-information/terms/website-terms-conditions) for your intended use.

# Actor input Schema

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

Search groceries such as milk, coffee or Tim Tam. Combine with product links, categories or product IDs. Default: milk.

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

Optional public Coles product, category, on-special or search links. Filters in links are kept.

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

Optional numeric Coles IDs. Use a full product link if a numeric-only lookup is unavailable.

## `locations` (type: `array`):

Australian postcodes as four digits. Selects the nearest online Coles store to the first locality returned by Coles. Every row identifies the actual price store. A postcode does not promise delivery-address service. Empty uses the site default.

## `storeIds` (type: `array`):

Optional Coles supermarket IDs such as 313. Combines with postcode selections; the same store and product are charged once.

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

Maximum new products from each source at each store. Overall maxItems still applies.

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

Total distinct product and store combinations across this run. 20 products cost $0.032 before discounts and the small start fee.

## `dealsOnly` (type: `boolean`):

Keep specials, half price, multi-buy and other price promotions. Every Day labels alone do not count as a discount.

## `includeDetails` (type: `boolean`):

Adds slower product detail requests for barcode, ingredients and nutrition. Details are included in the same $0.0016 Product price; there is no add-on charge.

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

Leave empty for automatic datacenter requests with fresh sessions and AU residential retries only after refusals. Custom proxy settings are used exactly as supplied.

## Actor input object example

```json
{
  "searchTerms": [
    "milk"
  ],
  "startUrls": [],
  "locations": [
    "2000"
  ],
  "maxItemsPerSearch": 20,
  "maxItems": 20,
  "dealsOnly": false,
  "includeDetails": false
}
```

# Actor output Schema

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

No description

## `deals` (type: `string`):

No description

## `summary` (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 = {
    "searchTerms": [
        "milk"
    ],
    "startUrls": [],
    "locations": [
        "2000"
    ],
    "maxItemsPerSearch": 20,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("vant47/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 = {
    "searchTerms": ["milk"],
    "startUrls": [],
    "locations": ["2000"],
    "maxItemsPerSearch": 20,
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("vant47/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 '{
  "searchTerms": [
    "milk"
  ],
  "startUrls": [],
  "locations": [
    "2000"
  ],
  "maxItemsPerSearch": 20,
  "maxItems": 20
}' |
apify call vant47/coles-scraper --silent --output-dataset

```

## MCP server setup

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