# Coles AU Scraper - Groceries, Prices & Reviews (`abotapi/coles-au-scraper`) Actor

Scrape Coles.com.au grocery products and customer reviews. Search by keyword, browse categories, or use product/search URLs. Returns name, brand, price, was price, unit price, size, specials, availability, aisle/category, nutrition, allergens, ingredients, ratings, and reviews.

- **URL**: https://apify.com/abotapi/coles-au-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 40 total users, 5 monthly users, 90.8% runs succeeded, 3 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.20 / 1,000 product 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

## Coles Scraper: Grocery Prices, Specials, Nutrition & Reviews

Coles Scraper turns the Coles Australia online grocery store into structured product data. Search by keyword, browse whole categories, pull the On Special catalogue, or paste product and listing links. Every product comes back as one flat record with price, was price and savings, unit price, size, availability, category data, nutrition, ingredients, allergens and, optionally, customer ratings and reviews. Export to JSON, CSV or Excel, or read the results through the API.

### Why This Scraper?

- **Two input types, one filter surface.** Search keywords, browse category slugs, or combine both, then apply the same price, rating and specials filters either way. Paste product, search, category or On Special links when you already have them.
- **Specials done properly.** Pull the storefront's On Special catalogue by type (half price, multi buy, online only), or run a complete sweep that also catches genuinely reduced products the curated On Special listing itself misses.
- **Was price and savings, worked out correctly.** Strike through price, saving amount and percent, promo label and, for multi buy offers, the structured deal detail, all read straight off each product's own pricing data.
- **Unit price that is actually usable.** Comparable price recovered even when Coles' own structured unit price field is empty, always paired with the basis it is quoted against so a per gram value is never mistaken for a per kilogram one.
- **Full grocery labelling.** Long description, ingredients, allergens, dietary statement, storage instructions, dimensions, country of origin, GTIN, nutrition panel and images when detail collection is switched on.
- **Ratings and reviews on demand.** The aggregate rating and star distribution come with basic detail collection; the full review list, with star rating, text, author, date and helpful count, is a separate switch.
- **Built for monitoring.** Resume one interrupted run from its previous dataset, or turn on incremental mode so a daily schedule returns only new, updated and reappeared products instead of a full snapshot every time.

### Use Cases

- **Price tracking and comparison sites:** collect current price, was price, unit price and specials across categories to power a grocery comparison tool.
- **Deal and specials alerting:** monitor the On Special catalogue and specific departments, and get notified only when something changes.
- **Nutrition and ingredient research:** build datasets of allergens, dietary claims and nutrition panels across a category for dietary or health apps.
- **Market and assortment research:** track category depth, brand presence and product variants across Coles' catalogue over time.
- **Customer sentiment analysis:** pull ratings and review text for the products that carry them to understand what shoppers say.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live record.

| Field | Example |
| --- | --- |
| `productId` | `"8150288"` |
| `name` / `title` | `"Coles Full Cream Milk 3L"` / `"Coles Full Cream Milk 3L"` |
| `brand` / `size` | `"Coles"` / `"3L"` |
| `price` / `wasPrice` | `3.1` / `6.2` |
| `savingsAmount` / `savingsPercent` | `3.1` / `50` |
| `promoLabel` / `promotionType` / `specialType` | `"1/2 Price"` / `"SPECIAL"` / `"PERCENT_OFF"` |
| `comparablePrice` / `unitPrice` / `unitOfMeasure` | `"$1.03/ 1L"` / `1.03` / `"l"` |
| `isOnSpecial` / `isOnlineOnly` | `true` / `false` |
| `isAvailable` / `availabilityType` | `true` / `"InStoreAndOnline"` |
| `aisle` / `category` / `department` | `"Full Cream Milk"` / `"Milk"` / `"DAIRY"` |
| `departments` | `["dairy-eggs-fridge"]` |
| `image` | Coles product image link |
| `longDescription` | `"A fresh Australian full cream milk, rich and creamy."` |
| `ingredients` / `allergens` | `"Full cream milk."` / `"Contains Milk"` |
| `nutrition` | serving size and the full nutrition breakdown, when published |
| `gtin` / `barcode` | `"9300601123456"` / same value (alias) |
| `breadcrumbs` | `["Dairy", "Milk", "Fresh Milk"]` (category, sub-category, aisle) |
| `inStock` / `stockStatus` | `true` / `"in_stock"` (or `"out_of_stock"`); mirrors `isAvailable` |
| `countryOfOrigin` | `"Australia"` |
| `rating` / `reviewCount` | `4.6` / `128` |
| `ratingDistribution` | `{ "5": 96, "4": 20, "3": 7, "2": 3, "1": 2 }` |
| `reviews` | star rating, title, text, author, date, helpful count (when enabled) |
| `url` | Coles link to the product page |

Fields added for cross-site parity: `barcode` (same value as `gtin`), `breadcrumbs` (category, sub-category, aisle), `inStock` and `stockStatus` (mirror `isAvailable`). They are additive and never count as a change in incremental mode.

Category, department and specials records carry the same underlying product fields; a variant matrix and category breadcrumb are added once product detail is switched on.

### How to Use

1. Pick an **input type**: search or browse with keywords and category slugs, or paste product, search, category and On Special links.
2. Add filters: price range, minimum rating, specials category or exclusions, department exclusions.
3. Switch on **Fetch product details** and **Fetch customer reviews** if you need the full label and reviews, and set **Max products** to control run size and cost.
4. Click **Start**, then download the dataset as JSON, CSV or Excel, or read it through the API.

**Search for a keyword inside a category:**

```json
{
  "inputMode": "search",
  "queries": ["milk"],
  "categories": ["dairy-eggs-fridge"],
  "fetchDetails": true,
  "maxItems": 20
}
```

**Half price specials, skipping one department:**

```json
{
  "inputMode": "search",
  "specialsCategory": "halfprice",
  "excludeCategories": ["liquorland"],
  "maxItems": 50
}
```

**A complete sweep of everything currently reduced:**

```json
{
  "inputMode": "search",
  "specialsCategory": "allspecials-complete",
  "maxItems": 200
}
```

**Paste a product link and a category link, with reviews:**

```json
{
  "inputMode": "url",
  "urls": [
    "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288",
    "https://www.coles.com.au/browse/dairy-eggs-fridge/milk"
  ],
  "fetchReviews": true
}
```

#### Supported link shapes

In `url` mode every one of these Coles link shapes is accepted (the `www.` prefix is optional, and tracking parameters such as `utm_source` are ignored):

| Link | Example |
| --- | --- |
| Product page (slug and id) | `/product/coles-full-cream-milk-3l-8150288` |
| Product page, shared with tracking | `/product/coles-full-cream-milk-3l-8150288?utm_source=share` |
| Product page by id only | `/product/8150288` |
| Product page without `www.` | `https://coles.com.au/product/...` |
| Bare numeric product id | `8150288` |
| Search results | `/search/products?q=milk` |
| Search results (short form) | `/search?q=milk` |
| Search results from a page | `/search/products?q=milk&page=2` |
| Search results, sorted | `/search/products?q=milk&sort=priceAscending` |
| Category | `/browse/dairy-eggs-fridge` |
| Sub-category | `/browse/dairy-eggs-fridge/milk` |
| Category from a page | `/browse/dairy-eggs-fridge?page=2` |
| Category, sorted | `/browse/dairy-eggs-fridge?sort=priceAscending` |
| On Special, all | `/on-special` |
| On Special from a page | `/on-special?page=2` |
| On Special by department | `/on-special/dairy-eggs-fridge` |
| On Special, half price | `/on-special?filter_Special=halfprice` |

The half-price filter is applied only on On Special links; on a category link it is ignored (the run logs a note and collects the whole category), so paste `/on-special/<department>?filter_Special=halfprice` instead. `page=` starts that listing on that page; `sort=` accepts the site's own `priceAscending` / `priceDescending` values, the short forms `priceAsc` / `priceDesc`, or `name`.

**Behaviour change: `urls` is no longer empty by default.** In `url` mode, if you leave the **URLs** field untouched, the run now scrapes one example of each supported link shape (seven example links, one per distinct target) instead of returning nothing. Set your own links, or lower **Max products**, to control the run. The default input mode is `search`, so runs that do not select `url` are not affected: outside `url` mode the example links are ignored and do not change the incremental state key, so existing scheduled search and category runs keep their saved baseline.

#### Output views

The dataset has four ready-made tables in the Console **Output** tab:

- **Products**: price, was price, savings, promo label, unit price, size, specials flags, departments and rating, one row per product.
- **Product detail**: GTIN and barcode, category path, ingredients, allergens, dietary statement, nutrition, storage, country of origin and long description.
- **Reviews**: one row per review, with the product, its total review count, and each review's star rating, title, text, author, date, verified-purchase flag and helpful votes.
- **Changes (incremental mode)**: change type, changed fields, price, was price and first/last seen times.

A run summary (counts of products returned, enriched, scanned and excluded) is also saved as the `OUTPUT` record in the run's key-value store.

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/coles-au-scraper").call(run_input={"inputMode": "search", "queries": ["milk"]})
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(product["name"], product.get("price"))
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/coles-au-scraper').call({ inputMode: 'search', queries: ['milk'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Resume and recurring updates

- **Resume** (`resumeFromRunId`) continues one specific interrupted run: paste its run or dataset id and this run skips every product id already in that dataset, so it returns only the remaining new products and you don't pay twice.
- **Incremental mode** (`incrementalMode`) is for a schedule against the same search. The first run returns everything as `NEW`; later runs return only `NEW`, `UPDATED` (with `changedFields`) and `REAPPEARED` products, while unchanged ones are suppressed and not billed unless `emitUnchanged` is on. `EXPIRED` products (no longer found) are only produced once a run has scanned the whole tracked search, not when a cap or Resume cut it short, and only with `emitExpired` on. `stateKey` names or shares the stored state; leave it empty and the actor derives one automatically from your search and filter setup. `ignoreFieldsForChanges` lists field names (or dotted nested paths such as `a.b`) that must not count as a change: they are still returned in every row but never turn a product into `UPDATED`. For example, `["promoLabel"]` stops a changed promo label alone from re-reporting a product. Ratings, review counts and the parity fields above are always ignored.

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step **after** the scrape; the Apify dataset is never changed.

**What gets written to the connector:** for Notion, one page per product with its key fields and a short summary. For other connectors, a best effort write of the same condensed summary. The **complete record always stays in the Apify dataset**.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where products should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third party credentials. Leave the field empty to skip.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `inputMode` | select | (none, prefilled `search`) | `search` to use keywords, categories and filters, or `url` for pasted links and product ids. |
| `mode` | string (hidden) | `search` | Legacy compatibility field for saved tasks and API integrations made before `inputMode`. New runs should use `inputMode`. |
| `queries` | array | (none, prefilled `["milk"]`) | Keywords to search for. Leave empty to browse the selected categories in full. |
| `categories` | array | (none, prefilled `["dairy-eggs-fridge"]`) | Category slugs (the part after `/browse/` in a Coles category URL). With keywords, they limit where the search looks; without keywords, their full listings are returned. |
| `specialsCategory` | select | `""` (not selected) | Add products from Coles' On Special catalogue: all specials, a complete sweep of everything reduced, half price, multi buy, or online only. |
| `urls` | array | seven example links, one per distinct target | Coles product, search, category or On Special URLs, or bare numeric product ids (`url` mode). A `page=` number starts that listing on that page; `sort=` (`priceAscending` / `priceDescending`, the short forms `priceAsc` / `priceDesc`, or `name`) orders that URL's results. If you select URL mode without editing this field, the run scrapes one example of each supported link shape (product page, search, category, sub-category, On Special all / department / half-price), so set `maxItems` or your own links. |
| `sortBy` | select | `relevance` | Order applied to the collected products: `relevance`, `price_asc`, `price_desc`, or `name`. Coles itself only serves relevance order; the others are applied after collection. |
| `minRating` | select | `"0"` | Keep only products rated at least `3`, `4` or `5` stars. Requires product detail or review collection; products with no reviews are excluded when this is set. |
| `specialsOnly` | boolean | `false` | Keep only products currently showing a special price or offer. |
| `excludeSpecialsCategories` | array (select) | (none) | Drop products in these specials categories instead of collecting and paying to enrich them. Excluding `allspecials` drops every on-special product. |
| `excludeCategories` | array | (none) | Departments to skip entirely, so they are never collected or charged. A product is skipped if it belongs to any listed department, even if it also appears under one you keep. |
| `minPrice` | integer | (none) | Only keep products priced at or above this amount (AUD). |
| `maxPrice` | integer | (none) | Only keep products priced at or below this amount (AUD). |
| `fetchDetails` | boolean | `true` | Collect each product's full detail (description, ingredients, allergens, dietary statement, storage, dimensions, country of origin, GTIN, nutrition panel, images) plus its aggregate rating. |
| `fetchReviews` | boolean | `false` | Also collect customer reviews for each product. Most Coles grocery products carry no reviews; those records leave the rating and review fields absent. |
| `maxReviewsPerProduct` | integer | `20` | Cap on reviews collected per product when `fetchReviews` is on. Cost guard: review collection per product is always bounded, with a maximum of `200` per product (`0` or a larger value is treated as `200`), so a single product can never produce an unbounded review run. Lower it to keep runs smaller. |
| `maxItems` | integer | `20` | Maximum number of products to return across the whole run. Use `0` for unlimited. |
| `maxPages` | integer | (none, all pages) | Maximum result pages per keyword, category or URL. Does not cap the number of products; `maxItems` does that. |
| `resumeFromRunId` | string | (none) | Id of a previous run (or dataset) of this actor. Products already in that dataset are skipped, so this run returns only new products. |
| `incrementalMode` | boolean | `false` | Turn on for daily or recurring monitoring: returns only new, updated and reappeared products on repeated runs over the same search. |
| `stateKey` | string | (none) | Name this monitoring campaign to keep its state stable, or share state across differently configured runs. Auto-derived from your search and filter settings when left empty. |
| `emitUnchanged` | boolean | `false` | Incremental mode only. Also return (and bill) products unchanged since the last run. |
| `emitExpired` | boolean | `false` | Incremental mode only. Also return (and bill) products no longer found, once a run has fully scanned the tracked search. |
| `ignoreFieldsForChanges` | array | `[]` | Incremental mode only. Field names (or dotted paths) that never count as a change. They are still returned in every row. |
| `proxy` | object | `{ "useApifyProxy": true }` | Connection settings. |
| `mcpConnectors` | array | (none) | Optional: send a summary of each product to apps you authorized under Integrations. |
| `notionParentPageUrl` | string | (none) | Notion connector only: page under which product pages are created. |
| `maxNotifyListings` | integer | `50` | Cap on items written to each connector per run. Does not affect the dataset. |

### Output Example

> Sample shape: values are illustrative placeholders, not from a live record.

```json
{
  "productId": "8150288",
  "name": "Coles Full Cream Milk 3L",
  "title": "Coles Full Cream Milk 3L",
  "brand": "Coles",
  "description": "COLES FULL CREAM MILK 3L",
  "size": "3L",
  "url": "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288",
  "price": 4.5,
  "isOnSpecial": false,
  "comparablePrice": "$1.50/ 1L",
  "unitPrice": 1.5,
  "unitOfMeasure": "l",
  "unitMeasure": "1l",
  "currency": "AUD",
  "isAvailable": true,
  "availabilityType": "InStoreAndOnline",
  "aisle": "Full Cream Milk",
  "category": "Milk",
  "subCategory": "Dairy, Eggs & Fridge",
  "department": "DAIRY",
  "departments": ["dairy-eggs-fridge"],
  "isOnlineOnly": false,
  "image": "https://cdn.productimages.coles.com.au/productimages/1/8150288.jpg",
  "longDescription": "A fresh Australian full cream milk, rich and creamy.",
  "gtin": "9300601123456",
  "brandSlug": "coles",
  "countryOfOrigin": "Australia",
  "countryOfOriginStatement": "Made in Australia from at least 99% Australian ingredients",
  "categoryPath": ["Milk", "Dairy, Eggs & Fridge", "Full Cream Milk"],
  "ingredients": "Full cream milk.",
  "allergens": "Contains Milk",
  "dietary": "Source of Calcium",
  "storageInstructions": "Keep refrigerated. Store at or below 5 degrees C.",
  "nutrition": { "servingSize": "250mL", "servingsPerPackage": "12.00", "breakdown": [{ "name": "Energy", "perServe": "450kJ", "per100": "180kJ" }] },
  "rating": 4.6,
  "ratingCount": 128,
  "reviewCount": 128,
  "ratingDistribution": { "5": 96, "4": 20, "3": 7, "2": 3, "1": 2 },
  "recommendedCount": 118,
  "reviews": [
    {
      "reviewId": "1000000001",
      "rating": 5.0,
      "title": "Family favourite",
      "body": "Fresh and creamy, our family buys it every week.",
      "author": "sampleShopper",
      "date": "2025-02-14T06:01:00.000+00:00",
      "verifiedPurchase": true,
      "isRecommended": true,
      "helpfulCount": 4
    }
  ],
  "reviewsCollected": 1,
  "searchMode": "search"
}
```

### Plan Requirement

The default connection setting works on a standard (datacenter) connection, but Coles' protection intermittently refuses individual connections: roughly one request in two to three is answered with a short "Request unsuccessful" page instead of the product page. The actor detects that page, treats it as a refusal rather than an empty result, and retries on a fresh connection, so a normal run still completes. If refusals persist, it switches to a residential connection, then to a built-in backup connection. For large or frequent runs, pinning the residential proxy group under Connection gives more consistent access and fewer retries.

An Apify free plan does not include proxy access. If your plan denies the proxy connection and the backup connection cannot reach the store either, the run stops with this message: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required: https://apify.com/pricing. If you entered your own proxy URLs, check that their credentials are valid." If the store itself is down, the run reports that Coles' website is offline instead of a connection problem.

### FAQ

#### How much does it cost?

You pay per product returned, plus a detail enrichment charge per product when product details and/or reviews are collected, plus a per-run start fee. The **Pricing** tab shows the current rates. Use **Max products** to cap the cost of any run.

#### Is it legal to scrape Coles?

This actor collects only publicly available product data. You are responsible for how you use it: follow Coles' terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Prices and product facts are generally not protected, but images and some descriptions may be subject to third party rights.

#### Can I get only new or changed products on a schedule?

Yes. Schedule the actor from the **Schedules** tab and turn on **Incremental mode**. Each run then returns only new, updated and reappeared products, classified against the previous run of the same search, and unchanged ones are not billed unless you turn that on too.

#### Why does a GTIN show as scientific notation in Excel or Google Sheets?

This is an import display issue, not a data problem: the dataset itself always stores `gtin` as text. Excel and Google Sheets both auto-detect long all-digit columns as numbers on a plain CSV import and re-render them in scientific notation, losing trailing digits. Import through *Data → From Text/CSV* (Excel) or choose "Do not convert" (Google Sheets), and set the `gtin` column to Text; the JSON and Excel dataset downloads are not affected.

#### Why did my run fail instead of returning an empty dataset?

The run is marked failed only when it could never establish a working connection to the store at all, when the Resume id you supplied is not a readable run or dataset from your account, or when the resume and incremental mode inputs conflict (for example, incremental mode already has saved state for this search and you also supplied Resume). A run that connects successfully but finds no matching products, or where your filters and exclusions removed everything collected, completes normally with an empty dataset and a status message explaining why.

#### Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

### 🔗 Want more grocery data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>🥦 <a href="https://apify.com/abotapi/woolworths-au-scraper"><b>Woolworths AU Scraper</b></a><br>Scrape Woolworths Australia (woolworths.com.au) grocery products and reviews. Search by...</td><td>🥦 <a href="https://apify.com/abotapi/aldi-com-au-scraper"><b>ALDI AU Scraper</b></a><br>Scrape ALDI Australia (aldi.com.au) products: name, brand, price, was-price, savings...</td></tr>
<tr><td>🥦 <a href="https://apify.com/abotapi/carrefour-es-scraper"><b>Carrefour Spain Scraper</b></a><br>Scrape Carrefour Spain (carrefour.es) products. Search by keyword, browse a category, or...</td><td>🥦 <a href="https://apify.com/abotapi/rewe-de-scraper"><b>REWE.de Scraper</b></a><br>Scrape REWE Germany (rewe.de) grocery products: current price, was-price and discount...</td></tr>
<tr><td>🥦 <a href="https://apify.com/abotapi/auchan-fr-scraper"><b>Auchan France Scraper</b></a><br>Scrape Auchan.fr products: grocery, drinks, household and general merchandise. Real price...</td><td>🍷 <a href="https://apify.com/abotapi/danmurphys-scraper"><b>Dan Murphy’s Scraper</b></a><br>Scrape Dan Murphy’s products by category, keyword, or specials. Extract 45+ fields...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/coles-au-scraper/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

## `mode` (type: `string`):

Deprecated compatibility field for saved tasks and API integrations. New runs should use inputMode.

## `inputMode` (type: `string`):

Choose Search / browse to use keywords, categories and filters together. Choose Pasted URLs to scrape product, search, category or On Special links, or bare product IDs.

## `queries` (type: `array`):

Words to search for, such as 'milk' or 'tim tam'. Leave empty if you want every product from the selected categories.

## `categories` (type: `array`):

Limit keyword searches to specific Coles categories, or browse whole categories when Keywords is empty. Copy the part after /browse/ from a Coles category URL, for example 'dairy-eggs-fridge' or 'dairy-eggs-fridge/milk'.

## `specialsCategory` (type: `string`):

Optionally add products from Coles' On Special catalogue. Choose all specials or one offer type. This is an additional source alongside your keyword/category search; use Only products on special below when you want to filter the search results themselves.

• "All Specials (complete)" sweeps every department and keeps only products whose price is actually reduced. Coles' own On Special listing is a curated view rather than an index of every markdown — measured across 10 departments, about 7% of genuinely-reduced products never appear in it. This option catches those, at the cost of a much larger walk, so set "Max products" to bound the run. Department exclusions and excluded specials categories still apply.

## `urls` (type: `array`):

Paste one or more Coles product, search, category or On Special URLs, or bare numeric product IDs. A page= number starts the walk on that page and sort= (the site's own priceAscending / priceDescending, the short forms priceAsc / priceDesc, or name) orders that URL's results. Left untouched in URL mode, the field scrapes seven example links, one per distinct target.

## `sortBy` (type: `string`):

Order the products collected by this run. Coles supplies relevance order; price and name ordering are applied after collection.

## `minRating` (type: `string`):

Optional. Only keep products whose average customer rating is at least this many stars. Requires enrichment (ratings are collected during 'Fetch product details' / 'Fetch customer reviews'). Products with no reviews are excluded when this is set.

## `specialsOnly` (type: `boolean`):

Keep only products currently showing a special price or offer. Applies to keyword searches, category browsing and pasted listing URLs.

## `excludeSpecialsCategories` (type: `array`):

Drop products belonging to these specials categories instead of collecting and paying to enrich them. Applies to keyword searches, category browsing, the Specials category above and pasted listing URLs. Excluding 'All specials' drops every product currently on special. Leave empty to exclude nothing (existing behaviour).

## `excludeCategories` (type: `array`):

Optional. Departments to skip entirely, so they are never collected and never charged. Use the name from an On Special or category link, for example 'liquorland', 'deliver-more-range' or 'big-pack-value'. A product is skipped when it belongs to any listed department, even if it also appears under one you keep - the same product is often shelved under several at once. To skip promo types (half price, online only) instead, use Exclude specials categories above.

## `minPrice` (type: `integer`):

Optional. Only keep products priced at or above this amount.

## `maxPrice` (type: `integer`):

Optional. Only keep products priced at or below this amount.

## `fetchDetails` (type: `boolean`):

Collect each product's full detail (long description, ingredients, allergens, dietary statement, storage, dimensions, country of origin, GTIN, nutrition panel and images) plus its aggregate rating and star distribution.

## `fetchReviews` (type: `boolean`):

Also collect customer reviews for each product (star rating, title, review text, author display name, date, verified-purchase flag and helpful-vote count), walked across review pages. Note: most Coles grocery products carry no reviews; those records leave the rating/reviews fields absent.

## `maxReviewsPerProduct` (type: `integer`):

Cap on reviews collected per product when 'Fetch customer reviews' is on. At most 200 per product are collected; 0 or a larger value is treated as 200.

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

Maximum number of products to return across the whole run. Use 0 for unlimited.

## `maxPages` (type: `integer`):

Maximum result pages per keyword, category, or URL. Leave empty for all available pages. This does not cap the number of products; Max products does that.

## `proxy` (type: `object`):

Leave enabled to use Apify Proxy (recommended). You can optionally pin specific proxy groups or a country.

## `resumeFromRunId` (type: `string`):

Optional. ID of a previous run of this actor (or a dataset ID). Products already in that dataset are skipped, so this run returns only NEW products (a delta). Combine both runs' datasets for the full set. Max products then counts only the new products. For recurring daily monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns all matching products as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED products. Turn on "Emit unchanged" or "Emit expired" only when you also want those products returned (and billed). State is kept separately for each distinct search/filter setup (or by State key below).

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from your search/filter/detail settings — different searches then never mix state with each other.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return products that have not changed since the last run, marked UNCHANGED. This returns — and bills — extra rows you already have, so leave it off unless you specifically want the full snapshot every run.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return products that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search — not when Max products or Max pages capped it, or when Resume was used. This returns — and bills — extra synthetic rows.

## `ignoreFieldsForChanges` (type: `array`):

Optional. Field names that must NOT count as a change in incremental mode, for example `unitPrice` or `imageUrl`. Use a dotted path for a nested field (`a.b`). Ratings and review counts are already ignored. Ignored fields are still returned in every row; they only stop a product from being marked UPDATED. Unknown names are harmless.

## `mcpConnectors` (type: `array`):

Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write/digest. Leave empty to skip; never changes the dataset output. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL or id of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "inputMode": "search",
  "queries": [
    "milk"
  ],
  "categories": [
    "dairy-eggs-fridge"
  ],
  "specialsCategory": "",
  "urls": [
    "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288",
    "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288?utm_source=share",
    "https://www.coles.com.au/product/8150288",
    "https://coles.com.au/product/coles-full-cream-milk-3l-8150288",
    "https://www.coles.com.au/search/products?q=milk",
    "https://www.coles.com.au/search?q=milk",
    "https://www.coles.com.au/search/products?q=milk&page=2",
    "https://www.coles.com.au/search/products?q=milk&sort=priceAscending",
    "https://www.coles.com.au/browse/dairy-eggs-fridge",
    "https://www.coles.com.au/browse/dairy-eggs-fridge/milk",
    "https://www.coles.com.au/browse/dairy-eggs-fridge?page=2",
    "https://www.coles.com.au/browse/dairy-eggs-fridge?sort=priceAscending",
    "https://www.coles.com.au/on-special",
    "https://www.coles.com.au/on-special?page=2",
    "https://www.coles.com.au/on-special/dairy-eggs-fridge",
    "https://www.coles.com.au/on-special?filter_Special=halfprice"
  ],
  "sortBy": "relevance",
  "minRating": "0",
  "specialsOnly": false,
  "excludeCategories": [
    "liquorland",
    "deliver-more-range",
    "big-pack-value"
  ],
  "fetchDetails": true,
  "fetchReviews": false,
  "maxReviewsPerProduct": 20,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `detail` (type: `string`):

No description

## `reviews` (type: `string`):

No description

## `changes` (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 = {
    "inputMode": "search",
    "queries": [
        "milk"
    ],
    "categories": [
        "dairy-eggs-fridge"
    ],
    "urls": [
        "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288",
        "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288?utm_source=share",
        "https://www.coles.com.au/product/8150288",
        "https://coles.com.au/product/coles-full-cream-milk-3l-8150288",
        "https://www.coles.com.au/search/products?q=milk",
        "https://www.coles.com.au/search?q=milk",
        "https://www.coles.com.au/search/products?q=milk&page=2",
        "https://www.coles.com.au/search/products?q=milk&sort=priceAscending",
        "https://www.coles.com.au/browse/dairy-eggs-fridge",
        "https://www.coles.com.au/browse/dairy-eggs-fridge/milk",
        "https://www.coles.com.au/browse/dairy-eggs-fridge?page=2",
        "https://www.coles.com.au/browse/dairy-eggs-fridge?sort=priceAscending",
        "https://www.coles.com.au/on-special",
        "https://www.coles.com.au/on-special?page=2",
        "https://www.coles.com.au/on-special/dairy-eggs-fridge",
        "https://www.coles.com.au/on-special?filter_Special=halfprice"
    ],
    "proxy": {
        "useApifyProxy": true
    },
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/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 = {
    "inputMode": "search",
    "queries": ["milk"],
    "categories": ["dairy-eggs-fridge"],
    "urls": [
        "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288",
        "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288?utm_source=share",
        "https://www.coles.com.au/product/8150288",
        "https://coles.com.au/product/coles-full-cream-milk-3l-8150288",
        "https://www.coles.com.au/search/products?q=milk",
        "https://www.coles.com.au/search?q=milk",
        "https://www.coles.com.au/search/products?q=milk&page=2",
        "https://www.coles.com.au/search/products?q=milk&sort=priceAscending",
        "https://www.coles.com.au/browse/dairy-eggs-fridge",
        "https://www.coles.com.au/browse/dairy-eggs-fridge/milk",
        "https://www.coles.com.au/browse/dairy-eggs-fridge?page=2",
        "https://www.coles.com.au/browse/dairy-eggs-fridge?sort=priceAscending",
        "https://www.coles.com.au/on-special",
        "https://www.coles.com.au/on-special?page=2",
        "https://www.coles.com.au/on-special/dairy-eggs-fridge",
        "https://www.coles.com.au/on-special?filter_Special=halfprice",
    ],
    "proxy": { "useApifyProxy": True },
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/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 '{
  "inputMode": "search",
  "queries": [
    "milk"
  ],
  "categories": [
    "dairy-eggs-fridge"
  ],
  "urls": [
    "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288",
    "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288?utm_source=share",
    "https://www.coles.com.au/product/8150288",
    "https://coles.com.au/product/coles-full-cream-milk-3l-8150288",
    "https://www.coles.com.au/search/products?q=milk",
    "https://www.coles.com.au/search?q=milk",
    "https://www.coles.com.au/search/products?q=milk&page=2",
    "https://www.coles.com.au/search/products?q=milk&sort=priceAscending",
    "https://www.coles.com.au/browse/dairy-eggs-fridge",
    "https://www.coles.com.au/browse/dairy-eggs-fridge/milk",
    "https://www.coles.com.au/browse/dairy-eggs-fridge?page=2",
    "https://www.coles.com.au/browse/dairy-eggs-fridge?sort=priceAscending",
    "https://www.coles.com.au/on-special",
    "https://www.coles.com.au/on-special?page=2",
    "https://www.coles.com.au/on-special/dairy-eggs-fridge",
    "https://www.coles.com.au/on-special?filter_Special=halfprice"
  ],
  "proxy": {
    "useApifyProxy": true
  },
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/coles-au-scraper --silent --output-dataset

```

## MCP server setup

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