Coles Scraper: Prices, Specials, Stock by Store
Pricing
from $0.63 / 1,000 products
Coles Scraper: Prices, Specials, Stock by Store
Scrape Coles Australia products and prices by keyword, category, specials or product link: price, was price, half price and multi buy offers, unit price per kg or litre, stock, barcode, nutrition, category. Prices and stock by store or postcode. Monitor mode returns price changes only.
Pricing
from $0.63 / 1,000 products
Rating
0.0
(0)
Developer
The Mine Works
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Security
Limited permissionsShare
From The Mine Works, makers of ALDI Australia Scraper and B2B Leads Finder, with over 290,000 runs across 310+ public actors.
Updated 31 Oct 2026: first release. Keywords, categories by name, slug or link, the full catalogue, all specials, half price, multi buy and online only specials, product links and ids; prices and stock for chosen stores or postcodes; barcode, ingredients and nutrition; monitor mode that returns only price changes; one flat row per product. Bookmark this Actor on its Store page so it is one click away next time.
Why choose this actor?
- Every price a category manager compares, in columns.
price,was_price,save_amount,is_half_priceand the multi buy offer split intomultibuy_quantityandmultibuy_total_price. Coles shows some unit prices per 100 g and others per kg;unit_price_normalizedputs every row on one scale (per kg, per litre or each), so a whole aisle sorts by real value. - Each store's own price and stock. Give store ids or postcodes and every list is read once per store, each row carrying
store_id,store_nameandstore_state. In our test the same Tim Tam Original 200g was $4.50, was $6.42 with 279 packs at Coles Karratha, and $4.50, was $6.00 with 557 packs at Coles Collingwood. - Cheap to run every day. Monitor mode remembers the last price of each product and returns only what changed, so a daily watch of 2,000 products pays for the dozens that moved, not the 2,000. Plain HTTP to the data coles.com.au loads itself, no browser.
- Pay per product, nothing for errors. Links that are not Coles links, unknown store ids, the summary row and duplicates found by two lists are never charged. No Coles account.
Part of The Mine Works E-commerce and marketplaces family: Ozon.ru Scraper, ⭐ Amazon Reviews Scraper, Amazon Product Scraper, Etsy Listings Scraper, AliExpress Scraper, Kleinanzeigen.de Scraper.
Try it in one minute
Paste this into the input (JSON view) and press Start. It returns the first 30 products for "milk" at Coles' default online store. It took 7 seconds in our test run:
{"searchQueries": ["milk"],"maxItems": 30}
Put several keywords on separate lines, add categories or a specials list, or paste product links. A product that two of your lists find is delivered once per store.
Apify's free plan includes $5 of credit every month, which covers about 5,300 products at this actor's price.
Copy to your AI assistant
themineworks/coles-scraper on Apify. Reads Coles Australia (coles.com.au) by keyword, category, specials list or product link and returns one flat row per product with price, was price, special and multi buy offer, unit price and a unit price per kg or litre, stock quantity, purchase limit, department, category and aisle, image and link, for Coles' default online store or chosen stores, with no login. Call ApifyClient("TOKEN").actor("themineworks/coles-scraper").call(run_input={"searchQueries": ["milk"], "maxItems": 100}), then client.dataset(run["defaultDatasetId"]).list_items().items. Inputs: searchQueries (keywords or any coles.com.au link), categories (names such as Milk, slug paths such as dairy-eggs-fridge/milk, browse links, or "all"), specials (none, all, halfprice, multibuy, onlineonly), productUrls (product links or ids), storeIds (store ids such as 313 or store page links), postcodes (4 digit postcodes, nearest Coles that sells online), fullCatalogue (bool), maxItems (default 100, per list and store), sortBy (recommendedDescending, priceAscending, priceDescending, unitPriceAscending, productNameAscending, productNameDescending, salesDescending), includeDetails (bool, adds barcode, ingredients, allergens, nutrition, country of origin, images to list rows), includeSponsored (default true), monitorMode (bool) with monitorName, monitorWatch (price or all) and includeNewProducts, residentialRetry (default true). Product rows have no _type field and carry retailer, product_id, barcode, name, brand, display_name, description, size, price, was_price, currency, on_special, promotion_type, special_type, price_description, is_half_price, offer_description, save_amount, save_percent, save_statement, multibuy_quantity, multibuy_unit_price, multibuy_total_price, online_special, unit_price, unit_price_quantity, unit_price_unit, unit_price_display, unit_price_normalized, unit_price_normalized_unit, sold_by_weight, in_stock, availability_type, stock_quantity, purchase_limit, promotional_purchase_limit, age_restricted, department, category, subcategory, category_path, department_id, category_id, subcategory_id, merchandise_hierarchy, fresh_life, variations_count, image_url, images, url, is_sponsored, long_description, ingredients, allergens, dietary, lifestyle, storage, dimensions, nutrition, serving_size, servings_per_pack, country_of_origin, details_scraped, store_id, store_name, store_state, store_postcode, price_scope, specials_filter, found_by, search_keyword, search_category, sort_by, results_in_list, page, position, scraped_at, and in monitor mode change_type, changed_fields, previous_price, previous_was_price, price_change, price_change_percent, previous_scraped_at. Each run also writes one row with _type "summary", one with _type "info" when products were delivered, and a row with _type "error" for each input that could not be read; none of these is charged. Full spec: GET https://api.apify.com/v2/acts/themineworks~coles-scraper/builds/default (Bearer TOKEN), which returns inputSchema and readme. Token: https://console.apify.com/account/integrations?fpr=ymnoit&utm_source=apify-readme&utm_medium=referral
Key features
- Keywords, categories, specials or links. Type keywords as in the coles.com.au search box, give categories by name (Milk, Soft Drinks), slug path (dairy-eggs-fridge/milk) or link, pick a specials list, or paste any Coles link into any field: product, category, specials, search or store page.
- Store prices. Coles prices, was prices and stock differ by store.
storeIdstakes the number at the end of a store page link;postcodestakes the nearest Coles supermarket that sells online, and skips a store without an online range for the next nearest. Up to 50 stores per run. - The whole catalogue.
fullCatalogue(orcategories: ["all"]) reads all 18 departments. Coles serves the first 5,000 products of any one list, so a bigger list is read category by category: Pantry (6,113 products) came back as 6,106 in our test. - Barcode and nutrition. Product links always come with the barcode (GTIN), ingredients, allergens, dietary and storage text, nutrition panel per serve and per 100 g, country of origin and all images.
includeDetailsadds the same to list rows, one extra call per 24 products (96 products with details took 41 seconds in our test, barcode on 95). - Monitor mode. Remembers the last price of each product per store and returns only new products and those whose price or was price moved (
monitorWatch: "all"adds specials starting or ending and stock changes), withprevious_price,price_changeandprice_change_percent. - Stops cleanly. A run ends after the first call if Coles refuses it, after 6 refused calls in a row, at the last page of a list or at
maxItems, and before its time limit, keeping every row. The summary row says why.
How to use it
Basic: products for a keyword
{"searchQueries": ["coffee beans", "oat milk"],"maxItems": 200}
Each keyword is its own list, labelled in search_keyword, in Coles' relevance order.
A whole category, cheapest per litre first
{"categories": ["Milk"],"sortBy": "unitPriceAscending","maxItems": 500}
category_path names the aisle of each product (Dairy, Eggs & Fridge > Milk > Full Cream Milk). Categories without a sort come back A to Z, which keeps long lists complete and stable between runs.
This week's half price specials in three states
{"specials": "halfprice","postcodes": ["2000", "3000", "6000"],"maxItems": 5000}
Coles changes its specials on Wednesday; schedule this for Wednesday morning. Every row carries store_id, store_name and store_state.
Daily price change alerts
{"categories": ["dairy-eggs-fridge", "pantry/coffee"],"monitorMode": true,"monitorName": "dairy-and-coffee","includeNewProducts": false}
The first run saves the baseline and returns nothing, so it costs nothing: the start fee is charged only once a product row is stored. Every run after it returns the products whose price or was price changed, with change_type price_down or price_up. Unchanged products are not delivered and not charged.
One product at a time from Clay, n8n or an AI agent
{"productUrls": ["https://www.coles.com.au/product/coles-full-cream-milk-3l-8150288"],"storeIds": ["313"]}
One row with the price, was price and barcode of that product at Coles Karratha. A bare product id (8150288) works too. Product links come back 24 to a call; the stock quantity comes on list rows only (in_stock is on both).
Input parameters
| Parameter | Type | Default | What it does |
|---|---|---|---|
searchQueries | array of strings | empty | Keywords, or any Coles link. |
categories | array of strings | empty | Category names, slug paths or links; all for every department. |
specials | string | none | all, halfprice, multibuy or onlineonly. |
productUrls | array of strings | empty | Product links or product ids, 24 per call, with barcode and full details. |
storeIds | array of strings | empty | Coles store ids or store page links. |
postcodes | array of strings | empty | Postcodes; the nearest Coles that sells online. |
fullCatalogue | boolean | false | Every department. |
maxItems | integer | 100 | Most products per list and store, 1 to 30,000. |
sortBy | string | relevance for keywords, name A to Z for lists | Any Coles sort order. |
includeDetails | boolean | false | Barcode, ingredients, nutrition and images on list rows. |
includeSponsored | boolean | true | Keep Coles' paid placements (marked is_sponsored). |
monitorMode | boolean | false | Return only products that changed since the last run. |
monitorName | string | default | Separate price memories for separate watch lists. |
monitorWatch | string | price | all also counts specials and stock changes. |
includeNewProducts | boolean | true | Return products the monitor has not seen before. |
residentialRetry | boolean | true | Use Australian residential IPs for pages Coles refuses on datacenter IPs. |
Give searchQueries, categories, specials, productUrls or any mix. Up to 100 lists and 5,000 product links per run.
What data do you get?
One row per product and store. Product rows have no _type field; the summary, info and error rows do, so a filter on _type separates them.
| Field | What it is |
|---|---|
product_id, barcode | Coles product id; barcode (GTIN) with product links or includeDetails |
name, brand, display_name, description, size | Product, brand, brand with name and size, Coles' short text, pack size |
price, was_price, currency | Price now, price before the special, AUD |
on_special, promotion_type, special_type, price_description | Special flag, Coles promotion type (SPECIAL, EVERYDAY, NEW), special type (PERCENT_OFF, MULTI_SAVE), label such as 1/2 Price |
is_half_price, save_amount, save_percent, save_statement | Half price flag and the saving |
offer_description, multibuy_quantity, multibuy_unit_price, multibuy_total_price | Multi buy offer, e.g. Pick any 2 for $5 |
online_special | Special online only |
unit_price, unit_price_quantity, unit_price_unit, unit_price_display | Unit price as Coles shows it, e.g. $2.25/ 100g |
unit_price_normalized, unit_price_normalized_unit | The same per kg, per litre or each |
sold_by_weight | Price is for an approximate weight |
in_stock, availability_type, stock_quantity | Availability at the store and the units Coles reports (stock quantity on list rows) |
purchase_limit, promotional_purchase_limit | Most units per order, normally and on special |
age_restricted | Liquor or tobacco |
department, category, subcategory, category_path and their ids | Where the product sits on coles.com.au |
merchandise_hierarchy | Coles' internal grouping (trade profit centre, category group, class) |
fresh_life, variations_count | Shelf life guarantee, other sizes and varieties |
image_url, images, url | Main image, all images (details), product page |
is_sponsored | Paid placement |
ingredients, allergens, dietary, lifestyle, storage, dimensions, long_description | Product page text (details) |
nutrition, serving_size, servings_per_pack, country_of_origin | Nutrition panel per serve and per 100 g, origin (details) |
store_id, store_name, store_state, store_postcode, price_scope | The store the prices are for |
found_by, search_keyword, search_category, specials_filter, sort_by, results_in_list, page, position | The list that found the product and its place in it |
change_type, changed_fields, previous_price, previous_was_price, price_change, price_change_percent, previous_scraped_at | Monitor mode only |
scraped_at | When the row was written |
Summary row (_type: "summary", never charged): lists read and failed, products delivered and charged, duplicates skipped, stores with the store each postcode resolved to, requests, refused calls, kilobytes on the wire, per_list (one entry per list with products found, delivered and why it stopped) and shortfall_reason when fewer products came back than asked. The same summary is saved as the OUTPUT record of the run.
Error rows (_type: "error", never charged): one per input that could not be read, with error_type (invalid_input, not_found, category_not_found, store_not_online, postcode_not_found, blocked, fetch_error), identifier and reason.
Stable fields for automations
These were present in every product row of our test runs (6,725 rows from Dairy, Eggs & Fridge and Pantry), and their names will not change:
| Field | What it is |
|---|---|
product_id | The key to store and join on (with store_id) |
display_name | Brand, name and size |
brand | Brand |
on_special | Special flag |
is_half_price | Half price flag |
in_stock | Availability |
image_url | Main image |
url | Product page |
store_id | Store the prices are for |
position | Place in its list |
Nearly always present: price (6,694 of 6,725; products Coles shows as unavailable have no price), size, category_path, stock_quantity (6,699), purchase_limit, unit_price_display and unit_price_normalized (6,465: some products, such as gift cards, have no unit price). Present when the product is on special: was_price, save_amount (1,453 of 6,725), multi buy fields (575). Barcode and nutrition fields need product links or includeDetails.
Output examples
A product at a chosen store, from the keyword "tim tam original" with storeIds: ["313"] (test run, 30 Oct 2026, trimmed):
{"retailer": "Coles","product_id": "329607","display_name": "Arnott's Tim Tam Chocolate Biscuits Original 200g","brand": "Arnott's","size": "200g","price": 4.5,"was_price": 6.42,"on_special": true,"save_amount": 1.92,"unit_price_display": "$2.25/ 100g","unit_price_normalized": 22.5,"unit_price_normalized_unit": "kg","in_stock": true,"stock_quantity": 279,"purchase_limit": 20,"category_path": "Chips, Chocolates & Snacks > Biscuits & Cookies > Chocolate Biscuits","image_url": "https://cdn.productimages.coles.com.au/productimages/3/329607.jpg","url": "https://www.coles.com.au/product/arnott's-tim-tam-chocolate-biscuits-original-200g-329607","store_id": "313","store_name": "Coles Karratha","store_state": "WA","price_scope": "store","found_by": "keyword_search","position": 1}
A multi buy special from the Dairy, Eggs & Fridge department (same day, trimmed):
{"product_id": "2807164","display_name": "Pauls Zymil Full Cream Long Life Milk 1L","price": 3,"on_special": true,"special_type": "MULTI_SAVE","offer_description": "Pick any 2 for $5","multibuy_quantity": 2,"multibuy_unit_price": 2.5,"multibuy_total_price": 5,"unit_price_display": "$3.00/ 1L","stock_quantity": 146,"category_path": "Drinks > Long-Life Milk > Lactose Free Milk","store_id": "7674","price_scope": "default_online_store"}
A product link (details always on, trimmed):
{"product_id": "8150288","display_name": "Coles Full Cream Milk 3L","price": 4.95,"barcode": "9300601186945","ingredients": "Homogenised and Pasteurised Full Cream Milk.","allergens": "Contains Milk","country_of_origin": "Australian Milk","serving_size": "250mL","nutrition": { "per_100g": { "Energy (kJ)": "258 kJ", "Protein": "3.4 g", "Calcium": "118 mg" } },"found_by": "product"}
An error row for a store id without an online range (nothing charged):
{ "_type": "error", "error_type": "store_not_online", "identifier": "99999", "reason": "Coles shows no online prices for store 99999: it does not exist or has no online range. Use a store that sells online, or a postcode for the nearest one." }
Pricing
Pay per event: you pay for the products you receive, plus a flat $0.003 per run, whatever memory you choose. Barcode and nutrition reads and store prices cost nothing extra.
| Event | When it is charged | Free plan | Bronze (Starter) | Silver (Scale) | Gold (Business) |
|---|---|---|---|---|---|
product-scraped | Once per product row stored in your dataset | $0.90 per 1,000 | $0.81 per 1,000 | $0.72 per 1,000 | $0.63 per 1,000 |
run-start | Once per run, after the first product row is stored | $0.003 | $0.003 | $0.003 | $0.003 |
The price of one product is the price per 1,000 divided by 1,000.
Never charged:
- links that are not Coles links, unknown product ids and store ids (each gets an error row);
- a product that a second list of the same run finds again for the same store;
- products past your
maxItems, and sponsored products whenincludeSponsoredis off; - unchanged products in monitor mode, and new ones when
includeNewProductsis off; - the summary, info and error rows;
- a run that delivers no product: the start fee is charged only after the first product row is stored;
- anything past your "Max cost per run". The actor checks the budget before each batch of rows and stops while the total is still below your limit, so the run ends SUCCEEDED with a partial result and a status message saying so.
Run it on a schedule
- Open the actor in Apify Console, set your input and click Save as a new task.
- In the task, open Schedules, click Add schedule and pick how often (every day, every Wednesday at 07:00 for the new specials, and so on).
- Turn on
monitorModein the task so each run returns only the products whose price changed, or compare runs yourself onproduct_id,store_idandprice. - Optional: add an integration (Google Sheets, Slack, a webhook) so each run lands where your team works.
FAQ
What does this actor read?
The same data coles.com.au loads in your browser to fill its search, category, specials, product and store pages, as anyone sees it without logging in. It does not log in, add anything to a trolley or read account data.
Do Coles prices really differ by store?
Yes, for some products: was prices, specials and stock differ, and some products are not ranged at every store. In our test the same Tim Tam pack had a was price of $6.42 in Karratha and $6.00 in Melbourne, and 279 against 557 packs in stock. Without stores you get Coles' default online store (store 7674).
How many products can I get?
Up to 30,000 per list and store. The full catalogue returned 24,926 products for one store in our test (18 departments, duplicates across departments removed). Coles serves the first 5,000 products of any one list; the actor reads bigger categories and the full specials list part by part. A keyword search is not split: narrow it if it has more than 5,000 results.
Why do some rows have no price?
Coles still lists some products it does not sell online at the moment; they come back with in_stock: false and no price. 31 of 6,725 rows in our test.
How does monitor mode know what changed?
It keeps the last price, was price, special and stock of every product it delivered, per store, in a key value store named after monitorName in your Apify account. Each run compares against it and saves the new values. Use a different monitorName for each watch list.
How long does a run take?
In our tests: 7 seconds for the "Try it" input, 90 seconds for the 1,805 half price specials, 165 seconds for 6,725 products from two departments, and 41 seconds for 96 products with includeDetails. The default time limit is 3,600 seconds; the actor stops before it and keeps every row.
Do I need an account, cookies or a proxy?
No. The actor uses Apify Proxy, included in the price. Coles sometimes answers a datacenter IP with a bot check page; such a page is retried on a new IP, and a page refused twice gets a last try on an Australian residential IP. When most datacenter calls are refused, the actor goes to residential IPs first until datacenter IPs are answered again. All at our cost.
Which formats can I download?
JSON, CSV, Excel, XML, RSS and HTML from the run's Storage tab or through the API. The dataset has four ready views: Products, Prices and stock, Barcode and nutrition, and Price changes. In CSV and Excel, nutrition is flattened into columns such as nutrition/per_100g/Protein.
Can I use it from Claude, ChatGPT or Cursor (MCP)?
Yes, through Apify's MCP server. Connector URL: https://mcp.apify.com/?tools=themineworks/coles-scraper
- Claude: Settings > Connectors > Add custom connector, paste the URL, sign in with Apify.
- ChatGPT: turn on developer mode, add an MCP connector with the URL, sign in with Apify.
- Cursor or VS Code: add it as an HTTP MCP server with that URL.
- Claude Code:
claude mcp add -t http coles-scraper "https://mcp.apify.com/?tools=themineworks/coles-scraper"
Is it legal to scrape Coles?
The actor reads public product and price data that Coles shows to anyone without logging in, and no personal data. Coles' robots.txt asks crawlers to stay away from its /search/ pages; the actor does not load those pages, it reads the search data the site loads for them, with the keyword you give. Decide for yourself whether that suits your use. You are responsible for how you use the data and for following the site's terms and the law. This is general information, not legal advice. Coles is a trademark of Coles Group; this actor is independent and not affiliated with it.
Integrations
- Google Sheets: send each run's products to a sheet with Apify's Google Sheets integration; one row per product fits a sheet as is.
- Make, Zapier and n8n: start a run and read its dataset with the Apify apps and nodes, for example "Coles price drops on our watch list every morning to Slack".
- Webhooks: have Apify call your URL when a run succeeds, then fetch the dataset.
- API and SDKs: run it from Python or JavaScript with the Apify client, or with a plain HTTP call (see "Copy to your AI assistant" above).
- MCP clients: Claude, ChatGPT, Cursor and VS Code can run it as a tool through the connector URL in the FAQ.
More from The Mine Works
E-commerce and marketplaces
- Ozon.ru Scraper
- ⭐ Amazon Reviews Scraper
- Amazon Product Scraper
- Etsy Listings Scraper
- AliExpress Scraper
- Kleinanzeigen.de Scraper
- Carsales.com.au Scraper
- eBay Product Listings Scraper
- Shopify Store Scraper
- 🛒 TikTok Shop Scraper
- Walmart Product & Price Scraper
- Vinted Scraper
Social media and video
Leads and business directories
Marketing, SEO and reviews
Real estate
Science, health and government data
Jobs and hiring
Company and business data
Food and local services
Developer and AI tools
More tools
Support
Found a list that returns fewer products than the site, or a field that comes back empty? Open an issue in the Issues tab with the input and the run ID, and we will look at it. For a field you need or a new source, email dmineworks@gmail.com.
Search Coles Australia by keyword, category, specials or product link and get every product back as one row, with price, was price, half price and multi buy offers, unit price per kg or litre, stock by store and, on request, barcode and nutrition, no login.

