Coles AU Scraper – Groceries, Prices & Reviews avatar

Coles AU Scraper – Groceries, Prices & Reviews

Pricing

from $1.20 / 1,000 product results

Go to Apify Store
Coles AU Scraper – Groceries, Prices & Reviews

Coles AU Scraper – Groceries, Prices & Reviews

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.

Pricing

from $1.20 / 1,000 product results

Rating

5.0

(1)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

1

Bookmarked

6

Total users

5

Monthly active users

3.4 hours

Issues response

an hour ago

Last modified

Share

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:

ValueWhat it returns
allspecialsThe whole On Special listing.
halfpriceProducts at half price (50% off).
multibuyMulti-buy offers (e.g. buy 2 for $7).
onlineonlyOnline-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:

{
"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

FieldTypeDescription
inputModeselectsearch to use keywords/categories/filters, or url for pasted links and product IDs.
queriesstring[]Optional search keywords. Leave empty to browse the selected categories in full.
categoriesstring[]Optional /browse/ category slugs. With keywords, they limit where Coles searches; without keywords, their complete listings are returned.
specialsCategoryselectOptionally add allspecials, halfprice, multibuy or onlineonly from Coles' On Special catalogue.
excludeSpecialsCategoriesselect (multi)Drop products in these specials categories instead of collecting them. Same values as specialsCategory; excluding allspecials drops every on-special product.
sortByselectrelevance, price_asc, price_desc, name (applied over the collected products).
minRatingselectKeep products rated at least 3, 4 or 5 stars (requires enrichment).
specialsOnlybooleanKeep only products currently on special (any source).
excludeCategoriesstring[]Optional. Departments to skip entirely, e.g. liquorland, deliver-more-range, big-pack-value. Skipped products are never collected, so they cost nothing.
minPrice / maxPriceintegerKeep products within an AUD price range.
urlsstring[]Product, search, category or On Special URLs, or bare product IDs (inputMode: "url").
fetchDetailsbooleanCollect full product detail + aggregate rating. Default true.
fetchReviewsbooleanAlso collect customer reviews. Default false.
maxReviewsPerProductintegerCap reviews per product (0 = all). Default 20.
maxItemsintegerMax products for the whole run (0 = unlimited). Default 20.
maxPagesintegerMaximum result pages per keyword, category, or URL. Leave empty for all available pages. This does not cap products; maxItems does.
resumeFromRunIdstringOptional. 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.
incrementalModebooleanTurn on for daily/recurring monitoring: remembers the previous run of the same search and returns only what changed. Default false. See Resume & recurring updates.
stateKeystringOptional. Name the incremental-mode monitoring campaign, or share state across differently-configured runs. Auto-derived from your search/filter settings when left empty.
emitUnchangedbooleanIncremental mode only. Also return (and bill) products unchanged since the last run, marked UNCHANGED. Default false.
emitExpiredbooleanIncremental mode only. Also return (and bill) products no longer found, marked EXPIRED. Only produced after a complete scan. Default false.
proxyobjectProxy configuration (Australian residential recommended).
mcpConnectorsarrayOptional MCP connectors to export results into (Notion, Linear, Airtable, Apify).
notionParentPageUrlstringNotion connector only: page under which item pages are created.
maxNotifyListingsintegerCap on items exported to each connector per run. Does not affect the dataset.

Example input

{
"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:

NeedUse
A crawl stopped and should continueresumeFromRunId / automatic checkpoint recovery
Run the same search every day and receive only changesincrementalMode
Keep separate daily campaigns for similar searchesdistinct stateKey values
Run a normal full snapshotleave 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:

FieldDescription
changeTypeNEW | UPDATED | UNCHANGED | REAPPEARED | EXPIRED
changedFieldsTop-level fields that changed since last seen; non-empty only for UPDATED
firstSeenAtWhen this product was first observed by this monitoring campaign
lastSeenAtWhen 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):

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

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

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

{ "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):

{
"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

FieldDescription
productIdColes product id.
name, title, brand, description, size, urlProduct name, fuller canonical title (brand + name + size), brand, short description, size, product page URL.
price, wasPrice, savingsAmount, savingsPercent, savingsLabel, isOnSpecialCurrent price, strike-through was-price, saving amount/percent, saving label and specials flag.
promoLabel, promotionType, specialType, offerDescription, multibuyPromotionPromo 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, currencyComparable (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, ageRestrictedAvailability, purchase limits and age-restriction flag.
aisle, category, subCategory, department, productClass, categoryPathCategory path (online aisle / category, internal department and product class), plus the breadcrumb path (with details).
departments, departmentIdsEvery 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.
isOnlineOnlyWhether the offer is available only for online orders. availabilityType does not distinguish these.
variantCount, variantsNumber of sibling variations and, with details, the variant matrix (productId, name, brand, size, url, image).
image, imagesPrimary image and the image list.
longDescription, gtin, brandSlug, countryOfOrigin, countryOfOriginStatement, lastUpdatedLong 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, disclaimersGrocery labelling and nutrition (with details, when published).
rating, ratingCount, reviewCount, ratingDistribution, recommendedCountAggregate rating and the 5★→1★ split (with enrichment, when the product has ratings).
reviews, reviewsCollectedCollected 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.