# 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
- **Stats:** 6 total users, 5 monthly users, 90.1% runs succeeded, 1 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Coles Australia Grocery Product & Reviews Scraper

Scrape coles.com.au grocery products and customer reviews at scale. Search by keyword across the whole store or within selected categories, browse complete 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, specials, size, availability, category data, nutrition, allergens, ingredients, rating and - optionally - customer reviews.

### What it does

- **Two simple input types**
  - **Search or browse products** - enter keywords, category slugs, or both. Keywords alone search the whole store; categories alone browse every product in those categories; keywords plus categories search only inside those categories. Price, rating and specials filters apply to all three combinations.
  - **Pasted URLs / product IDs** - paste product pages (`/product/<slug>-<id>`), search pages (`/search/products?q=...`), category pages (`/browse/<category>`), On Special pages (`/on-special`, `/on-special/<department>`), or bare numeric product IDs.
- **Specials catalogue** - optionally add Coles' own On Special catalogue: **All specials**, **Half price**, **Multi buy** or **Online only**. Every product from this source carries its was-price, saving amount/percent and promo label.
- **Was-price & discounts** - on every discounted product the record carries the strike-through was-price, the saving amount and percent, the promo label (e.g. `1/2 Price`), the promotion type, and, for multi-buy offers, the multi-buy detail (e.g. buy 2 for $7).
- **Full product detail** - collect each product's canonical title, long description, ingredients, allergens, dietary statement, storage instructions, dimensions, country of origin, GTIN, brand, category path, product variants, the nutrition panel and images.
- **Ratings & reviews** - the aggregate rating (average score, review count and the 5-star-to-1-star distribution) plus customer reviews: star rating, title, review text, author display name, date, verified-purchase flag and helpful-vote count.
- **Send results into your apps** - optional Notion / Linear / Airtable / Apify export via MCP connectors, without changing the dataset.

### Ratings & reviews: what you get

Coles shows an **aggregate rating** and a **customer review list** on product pages. This actor captures both:

- The **aggregate rating** and star distribution are collected during enrichment (`fetchDetails`), so every enriched product that has ratings carries `rating`, `ratingCount`, `reviewCount` and `ratingDistribution`.
- The **review list** is collected when `fetchReviews` is on, walked across review pages up to your `maxReviewsPerProduct` cap. Each review carries star rating, title, text, author display name, ISO date, verified-purchase flag and helpful-vote count.

> **Note:** most Coles grocery lines carry no reviews at all - reviews cluster on health, beauty, vitamins, pet and baby lines. When a product has no ratings, the rating and reviews fields are **omitted (not guessed)**. Products with reviews return them in full.

### Specials & discounts

Select `specialsCategory` to add Coles' own **On Special** catalogue to the run, subject to the same page and product limits as other searches:

| Value | What it returns |
|-------|-----------------|
| `allspecials` | The whole On Special listing. |
| `halfprice` | Products at half price (50% off). |
| `multibuy` | Multi-buy offers (e.g. buy 2 for $7). |
| `onlineonly` | Online-only specials. |

In URL mode, paste an On Special link instead - `https://www.coles.com.au/on-special` for everything, or `https://www.coles.com.au/on-special/<department>` (e.g. `/on-special/bakery`) to scope it to one department.

Every product returned from a specials source is on special, so each record carries `wasPrice`, `savingsAmount`, `savingsPercent`, `savingsLabel`, `promoLabel`, `promotionType` and `specialType`; multi-buy offers also carry `offerDescription` and a structured `multibuyPromotion`. The `specialsOnly` toggle is a separate client-side filter that keeps only on-special products from any search, category or specials source.

Use `excludeSpecialsCategories` to do the opposite of `specialsCategory`: drop products in the categories you list (`allspecials`, `halfprice`, `multibuy`, `onlineonly`) instead of collecting and paying to enrich them. Excluding `allspecials` drops every on-special product. Dropped products are never pushed or charged.

#### Skipping departments you don't want

To scrape the specials catalogue *except* certain ranges, use `excludeCategories` rather than listing the departments you do want:

```json
{
  "specialsCategory": "allspecials",
  "excludeCategories": ["liquorland", "deliver-more-range", "big-pack-value"]
}
```

Listing the other departments individually does **not** give the same result. The same product is routinely shelved under several departments at once — a Liquorland wine is also carried under Dietary & World Foods — so it comes back through whichever department you kept. `excludeCategories` skips a product if it belongs to *any* excluded department, wherever it was found. Skipped products are dropped from the listing page before any detail is fetched, so they cost nothing.

To drop **promo types** rather than departments (half price, multi buy, online only), use `excludeSpecialsCategories` instead — the two combine freely.

### Ordering

Coles serves search and category pages in **relevance order**. The optional `sortBy` (`price_asc`, `price_desc`, `name`) is applied over the products the run collects, so it orders the gathered result set rather than re-querying the store. Leave it on `relevance` to keep the storefront's own order.

### Input

| Field | Type | Description |
|-------|------|-------------|
| `inputMode` | select | `search` to use keywords/categories/filters, or `url` for pasted links and product IDs. |
| `queries` | string\[] | Optional search keywords. Leave empty to browse the selected categories in full. |
| `categories` | string\[] | Optional `/browse/` category slugs. With keywords, they limit where Coles searches; without keywords, their complete listings are returned. |
| `specialsCategory` | select | Optionally add `allspecials`, `halfprice`, `multibuy` or `onlineonly` from Coles' On Special catalogue. |
| `excludeSpecialsCategories` | select (multi) | Drop products in these specials categories instead of collecting them. Same values as `specialsCategory`; excluding `allspecials` drops every on-special product. |
| `sortBy` | select | `relevance`, `price_asc`, `price_desc`, `name` (applied over the collected products). |
| `minRating` | select | Keep products rated at least `3`, `4` or `5` stars (requires enrichment). |
| `specialsOnly` | boolean | Keep only products currently on special (any source). |
| `excludeCategories` | string\[] | Optional. Departments to skip entirely, e.g. `liquorland`, `deliver-more-range`, `big-pack-value`. Skipped products are never collected, so they cost nothing. |
| `minPrice` / `maxPrice` | integer | Keep products within an AUD price range. |
| `urls` | string\[] | Product, search, category or On Special URLs, or bare product IDs (`inputMode: "url"`). |
| `fetchDetails` | boolean | Collect full product detail + aggregate rating. Default `true`. |
| `fetchReviews` | boolean | Also collect customer reviews. Default `false`. |
| `maxReviewsPerProduct` | integer | Cap reviews per product (`0` = all). Default `20`. |
| `maxItems` | integer | Max products for the whole run (`0` = unlimited). Default `20`. |
| `maxPages` | integer | Maximum result pages per keyword, category, or URL. Leave empty for all available pages. This does not cap products; `maxItems` does. |
| `resumeFromRunId` | 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. |
| `incrementalMode` | boolean | Turn on for daily/recurring monitoring: remembers the previous run of the same search and returns only what changed. Default `false`. See [Resume & recurring updates](#resume--recurring-updates). |
| `stateKey` | string | Optional. Name the incremental-mode monitoring campaign, or share state across differently-configured runs. Auto-derived from your search/filter settings when left empty. |
| `emitUnchanged` | boolean | Incremental mode only. Also return (and bill) products unchanged since the last run, marked `UNCHANGED`. Default `false`. |
| `emitExpired` | boolean | Incremental mode only. Also return (and bill) products no longer found, marked `EXPIRED`. Only produced after a complete scan. Default `false`. |
| `proxy` | object | Proxy configuration (Australian residential recommended). |
| `mcpConnectors` | array | Optional MCP connectors to export results into (Notion, Linear, Airtable, Apify). |
| `notionParentPageUrl` | string | Notion connector only: page under which item pages are created. |
| `maxNotifyListings` | integer | Cap on items exported to each connector per run. Does not affect the dataset. |

#### Example input

```json
{
  "inputMode": "search",
  "queries": ["milk"],
  "categories": ["dairy-eggs-fridge"],
  "sortBy": "relevance",
  "specialsOnly": false,
  "minPrice": 1,
  "maxPrice": 20,
  "fetchDetails": true,
  "fetchReviews": true,
  "maxReviewsPerProduct": 20,
  "maxItems": 20,
  "proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "AU" }
}
```

### Resume & recurring updates

There are two different things here - pick the one that matches what you're doing:

| Need | Use |
| --- | --- |
| A crawl stopped and should continue | `resumeFromRunId` / automatic checkpoint recovery |
| Run the same search every day and receive only changes | `incrementalMode` |
| Keep separate daily campaigns for similar searches | distinct `stateKey` values |
| Run a normal full snapshot | leave both off |

**Resume** (`resumeFromRunId`) continues one specific interrupted or previous large crawl: paste a run ID or dataset ID and this run skips products already collected there, returning only the remaining new products. An automatic same-run checkpoint also protects against platform migrations/Resurrects without any input needed.

**Incremental mode** (`incrementalMode`) is for a schedule (for example, daily): the actor remembers the previous run of the *same* search by itself, so you never paste a run ID. The first run returns everything as `NEW`. Later runs return only `NEW`, `UPDATED`, and `REAPPEARED` products by default - duplicates and unchanged products are suppressed (and not charged). Turn on `emitUnchanged` or `emitExpired` only when you also want those rows returned (and billed for). State is isolated automatically per `inputMode`/`mode`/keywords/categories/URLs/`sortBy`/`minRating`/specials selection/exclusions/price range/detail/review setup - the richest filter surface in this run's input, so an exclusion like `excludeCategories` isolates state exactly like an inclusion filter does. Set `stateKey` to name or deliberately share a monitoring campaign. `EXPIRED` is only synthesized once a run fully scans every keyword/category/URL/specials target (not capped by Max products/Max pages, not a Resume run).

When `incrementalMode` is on, every returned record also carries:

| Field | Description |
|---|---|
| `changeType` | `NEW` | `UPDATED` | `UNCHANGED` | `REAPPEARED` | `EXPIRED` |
| `changedFields` | Top-level fields that changed since last seen; non-empty only for `UPDATED` |
| `firstSeenAt` | When this product was first observed by this monitoring campaign |
| `lastSeenAt` | When this product was last observed |

`rating`, `ratingCount`, `reviewCount`, `ratingDistribution`, `recommendedCount`, `reviews` and `reviewsCollected` are always returned, but they do **not** drive `changeType` - other shoppers post reviews independently of and far more often than a product's own price/stock/specials change, so counting them would mark almost every product `UPDATED` on every scheduled run and defeat suppression. A genuine price, was-price, or specials change still triggers `UPDATED` as usual - on a grocery actor that movement is real data and the whole point of monitoring, so it is never screened out.

A product dropped by a filter (for example `minRating`, which is only known after enrichment) is not tracked that run; if it was tracked before, it may show as `EXPIRED` next time even though it may still exist on the site under different criteria.

Scheduled-run example - same search, run daily:

Day 1 (first run ever for this search):

```json
{ "inputMode": "search", "queries": ["milk"], "incrementalMode": true }
```

→ every product comes back with `"changeType": "NEW"`.

Day 2 (the schedule fires again, identical input):

```json
{ "inputMode": "search", "queries": ["milk"], "incrementalMode": true }
```

→ products whose price/was-price/specials/etc. changed come back as `"changeType": "UPDATED"` with `changedFields` listing what changed, brand-new products come back as `"changeType": "NEW"`, products that vanished and came back come back as `"changeType": "REAPPEARED"` - and products that are still there, unchanged, are **not** returned at all (suppressed, not charged) unless `emitUnchanged` is on.

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

Optionally pipe results into the apps you already use through Model Context Protocol (MCP) connectors. Authorize a connector once under Apify, Settings, Integrations, then select it in the `mcpConnectors` field. Each connector receives a condensed, human-readable summary per product (title plus key fields), while the complete record always stays in the Apify dataset. For Notion, set `notionParentPageUrl` to the page the item pages should be created under. Supported connectors: Notion, Linear, Airtable, and Apify. Leave the field empty to skip; it never changes the dataset output.

### Output

One record per product. Example (values below are illustrative):

```json
{
  "productId": "100000",
  "name": "Example Full Cream Milk 2L",
  "title": "ExampleBrand Full Cream Milk 2L",
  "brand": "ExampleBrand",
  "description": "EXAMPLE FULL CREAM MILK 2L",
  "size": "2L",
  "url": "https://www.coles.com.au/product/example-full-cream-milk-2l-100000",
  "price": 3.0,
  "wasPrice": 6.0,
  "savingsAmount": 3.0,
  "savingsPercent": 50,
  "savingsLabel": "save $3.00",
  "promoLabel": "1/2 Price",
  "promotionType": "SPECIAL",
  "specialType": "PERCENT_OFF",
  "isOnSpecial": true,
  "comparablePrice": "$1.50 per 1L",
  "unitPrice": 1.5,
  "unitOfMeasure": "l",
  "unitMeasure": "1l",
  "currency": "AUD",
  "isAvailable": true,
  "availabilityType": "InStoreAndOnline",
  "availableQuantity": 500,
  "retailLimit": 20,
  "promotionalLimit": 12,
  "ageRestricted": false,
  "aisle": "Full Cream Milk",
  "category": "Milk",
  "subCategory": "Dairy, Eggs & Fridge",
  "department": "DAIRY",
  "productClass": "FULL CREAM",
  "variantCount": 3,
  "image": "https://cdn.productimages.coles.com.au/productimages/1/100000.jpg",
  "images": ["https://cdn.productimages.coles.com.au/productimages/1/100000.jpg"],
  "longDescription": "A fresh Australian full cream milk, rich and creamy.",
  "gtin": "9300000000000",
  "brandSlug": "examplebrand",
  "countryOfOrigin": "Australia",
  "countryOfOriginStatement": "Made in Australia from at least 99% Australian ingredients",
  "categoryPath": ["Milk", "Dairy, Eggs & Fridge", "Full Cream Milk"],
  "variants": [
    { "productId": "100001", "name": "Example Full Cream Milk 1L", "brand": "ExampleBrand", "size": "1L", "url": "https://www.coles.com.au/product/example-full-cream-milk-1l-100001", "image": "https://cdn.productimages.coles.com.au/productimages/1/100001.jpg" }
  ],
  "ingredients": "Full cream milk.",
  "allergens": "Contains Milk",
  "dietary": "Source of Calcium",
  "storageInstructions": "Keep refrigerated. Store at or below 5°C.",
  "dimensions": "250.00 x 100.00 x 100.00 mm",
  "nutrition": { "servingSize": "250mL", "servingsPerPackage": "8.00", "breakdown": [] },
  "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",
      "isRecommended": true,
      "helpfulCount": 4
    }
  ],
  "reviewsCollected": 1,
  "searchMode": "search"
}
```

#### Field reference

| Field | Description |
|-------|-------------|
| `productId` | Coles product id. |
| `name`, `title`, `brand`, `description`, `size`, `url` | Product name, fuller canonical title (brand + name + size), brand, short description, size, product page URL. |
| `price`, `wasPrice`, `savingsAmount`, `savingsPercent`, `savingsLabel`, `isOnSpecial` | Current price, strike-through was-price, saving amount/percent, saving label and specials flag. |
| `promoLabel`, `promotionType`, `specialType`, `offerDescription`, `multibuyPromotion` | Promo label (e.g. `1/2 Price`), promotion/special type, and, for multi-buy offers, the offer text and structured multi-buy detail (`quantity`, `price`, `unitPrice`, `description`). Present on discounted products. |
| `comparablePrice`, `unitPrice`, `unitOfMeasure`, `unitMeasure`, `currency` | Comparable (unit) price string, numeric unit price, unit, the measure the unit price is quoted against (e.g. `100g`), and currency (AUD). |
| `isAvailable`, `availabilityType`, `availableQuantity`, `retailLimit`, `promotionalLimit`, `ageRestricted` | Availability, purchase limits and age-restriction flag. |
| `aisle`, `category`, `subCategory`, `department`, `productClass`, `categoryPath` | Category path (online aisle / category, internal department and product class), plus the breadcrumb path (with details). |
| `departments`, `departmentIds` | Every department the product is shelved under, as names and ids. Products are commonly listed under several at once, so this is the reliable field to filter on — `subCategory` reports only the first. |
| `isOnlineOnly` | Whether the offer is available only for online orders. `availabilityType` does not distinguish these. |
| `variantCount`, `variants` | Number of sibling variations and, with details, the variant matrix (`productId`, `name`, `brand`, `size`, `url`, `image`). |
| `image`, `images` | Primary image and the image list. |
| `longDescription`, `gtin`, `brandSlug`, `countryOfOrigin`, `countryOfOriginStatement`, `lastUpdated` | Long description, GTIN, brand slug, country of origin (country name plus the full origin statement) and last-updated timestamp (with details). |
| `ingredients`, `allergens`, `dietary`, `storageInstructions`, `dimensions`, `nutritionalClaims`, `nutrition`, `disclaimers` | Grocery labelling and nutrition (with details, when published). |
| `rating`, `ratingCount`, `reviewCount`, `ratingDistribution`, `recommendedCount` | Aggregate rating and the 5★→1★ split (with enrichment, when the product has ratings). |
| `reviews`, `reviewsCollected` | Collected reviews and their count (present when reviews are enabled). Each review: `reviewId`, `rating`, `title`, `body`, `author`, `date`, `verifiedPurchase`, `isRecommended`, `helpfulCount`, `syndicatedFrom`, `photos`. |

Whenever a value is not published for a product, the field is omitted or `null` rather than guessed.

### Proxy

Apify Proxy is used by default and works on every plan. Leave proxy enabled for the most reliable results.

### Notes

- Prices, specials, ratings and stock are captured as shown on the storefront at scrape time.
- Filters (`minRating`, `minPrice`, `maxPrice`, `specialsOnly`, `excludeCategories`, `excludeSpecialsCategories`) are applied to each product's own values, so exact numeric ranges work independently of the on-site filters.
- `minPrice`, `maxPrice`, `specialsOnly`, `excludeCategories` and `excludeSpecialsCategories` are decided from the listing page, so products they remove are never fetched in detail and never reach your dataset. `minRating` is the exception: a product's rating is only known after it has been fetched, so rating-filtered products are collected first and then discarded. Prefer the listing-level filters when you are narrowing a large run.
- `verifiedPurchase` is included when the storefront exposes it for a review; on many reviews it is not published and the field is left out.
- The run periodically checkpoints its progress, so if the platform restarts the run (a server migration, or you use Resurrect) it picks up where it left off instead of starting over: no duplicate products and no double charges. No input is needed for this; it is automatic.

# Actor input Schema

## `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.

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

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

## `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'.

## `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.

## `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.

## `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).

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

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

## `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.

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

Paste one or more Coles product, search, category or On Special URLs, or bare numeric product IDs.

## `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. Use 0 for all available reviews.

## `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.

## `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.

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

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

## `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
{
  "inputMode": "search",
  "mode": "search",
  "queries": [
    "milk"
  ],
  "categories": [
    "dairy-eggs-fridge"
  ],
  "sortBy": "relevance",
  "minRating": "0",
  "specialsCategory": "",
  "specialsOnly": false,
  "excludeCategories": [
    "liquorland",
    "deliver-more-range",
    "big-pack-value"
  ],
  "urls": [
    "https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288"
  ],
  "fetchDetails": true,
  "fetchReviews": false,
  "maxReviewsPerProduct": 20,
  "maxItems": 20,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true
  },
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (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"
    ],
    "proxy": {
        "useApifyProxy": true
    }
};

// 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"],
    "proxy": { "useApifyProxy": True },
}

# 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("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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"
  ],
  "proxy": {
    "useApifyProxy": true
  }
}' |
apify call abotapi/coles-au-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=abotapi/coles-au-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/SEqyrh3rhhMtiabZc/builds/aUzidWnmnVtpuonNP/openapi.json
