# Woolworths & ALDI Scraper AU | Prices & Specials $0.90/1k (`programmx/au-grocery-price-feed`) Actor

Scrape Woolworths and ALDI Australia grocery prices, was-prices, unit (cup) prices, specials and GTINs by search term or the weekly specials. Price-change monitoring mode for scheduled daily runs. No login, no browser.

- **URL**: https://apify.com/programmx/au-grocery-price-feed.md
- **Developed by:** [ProgrammX](https://apify.com/programmx) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 product price records

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

## Woolworths & ALDI Scraper AU | Prices & Specials $0.90/1k

**Keywords:** Woolworths scraper, ALDI Australia scraper, Australian supermarket prices, grocery price API, Woolworths specials, half price specials, ALDI Super Savers, unit price, cup price, GTIN barcode, price monitoring, grocery price comparison, AU grocery data

Get **Woolworths and ALDI Australia** product prices, was-prices, unit (cup) prices, specials and GTIN barcodes as clean JSON, CSV or Excel. You can search by keyword, or leave the search empty to get **this week's specials** (Woolworths Half Price and Lower Shelf Price, ALDI Super Savers and Lower Prices). Turn on **price-change monitoring** to get only the products whose price or special status changed since your last run. No login, no browser, no cookies to paste.

### Who uses it and why

- **Price-comparison and budgeting apps:** one normalised row format for both retailers, with unit prices for like-for-like comparison.
- **CPG brands and agencies:** track your own and your competitors' promotions every week (half price, lower shelf price, savings in AUD).
- **Researchers and journalists:** build grocery inflation and shrinkflation series from daily price snapshots, keyed by GTIN (Woolworths) or SKU.
- **Deal sites and newsletters:** a Wednesday specials feed, ready to publish.

### What you get (one row per product per retailer)

`retailer`, `productId` (Woolworths Stockcode or ALDI SKU), `gtin` (Woolworths), `name`, `brand`, `size`, `price`, `wasPrice`, `unitPrice`, `unitMeasure`, `unitPriceText`, `isOnSpecial`, `isHalfPrice`, `savings`, `promoLabel`, `inStock`, `category`, `url`, `image`, `searchTerm`, `source`, `scrapedAt`. Monitoring mode adds `changeType` (`new` or `changed`), `previousPrice` and `previousIsOnSpecial`.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `retailers` | array | `["woolworths","aldi"]` | Which supermarkets to scrape. |
| `searchTerms` | string list | `["milk","coffee"]` | Keywords searched on every retailer. **Leave empty for the weekly specials feed.** |
| `specialsOnly` | boolean | `false` | Only products on special (Woolworths specials filter; ALDI Super Savers, Lower Prices or a was-price). |
| `maxItemsPerSearch` | integer | `50` | Products read per retailer per search term (or per specials category). |
| `maxItems` | integer | `50` | Hard cap on rows pushed and charged in the run, shared fairly across retailers and terms. |
| `onlyChanged` | boolean | `false` | Monitoring: emit only new products, or products whose price, was-price or special status changed since the previous run. |
| `onlyNew` | boolean | `false` | Monitoring: emit only products never seen before. |
| `proxyConfiguration` | proxy | no proxy | Optional Apify Proxy (RESIDENTIAL works best for Woolworths). |

Example: the full Woolworths and ALDI specials for this week

```json
{ "retailers": ["woolworths", "aldi"], "searchTerms": [], "maxItemsPerSearch": 2000, "maxItems": 5000 }
```

### Output sample (real rows from a test run on 2026-10-03)

```json
[
  {"retailer":"woolworths","productId":"195108","gtin":"9300605157460","name":"Nescafe Cappuccino Coffee Sachets 10 pack","brand":"Nescafe","size":"10 pack","price":4,"wasPrice":8,"unitPrice":0.4,"unitMeasure":"1EA","unitPriceText":"$0.40 / 1EA","isOnSpecial":true,"isHalfPrice":true,"savings":4,"promoLabel":"Save $4.00","inStock":true,"category":"Tea & Coffee > Coffee","url":"https://www.woolworths.com.au/shop/productdetails/195108/nescafe-cappuccino-coffee-sachets","searchTerm":"coffee","scrapedAt":"2026-10-03T15:31:46.721Z"},
  {"retailer":"aldi","productId":"000000000000398691","gtin":null,"name":"Light Milk 2L","brand":"FARMDALE","size":"2 L","price":3.39,"wasPrice":null,"unitPrice":1.7,"unitMeasure":"1 L","unitPriceText":"$1.70 per 1 L","isOnSpecial":true,"promoLabel":"Lower Prices","category":"Dairy, Eggs & Fridge > Milk","url":"https://www.aldi.com.au/product/farmdale-light-milk-2l-000000000000398691","searchTerm":"milk","scrapedAt":"2026-10-03T15:31:49.387Z"}
]
```

(Some fields, such as `image` and `source`, are left out of this sample to keep it short.)

### Pricing (pay per result)

You pay only for the product rows you get. In monitoring mode, unchanged products are skipped and **not charged**.

| Apify plan | Price per 1,000 results |
|---|---|
| Free | $0.90 |
| Bronze | $0.80 |
| Silver | $0.70 |
| Gold | $0.50 |

Apify's standard actor-start fee also applies. Example: a daily price-change check on 20 search terms usually returns a few dozen changed rows, which costs a few cents a day.

### How to schedule daily (price-change monitoring)

1. Save a task with your `searchTerms` (or an empty list for the specials) and `"onlyChanged": true`.
2. In **Schedules**, add the task with a daily cron such as `0 7 * * *` (Australia/Sydney).
3. For the weekly specials feed, schedule `searchTerms: []` on **Wednesdays** (`30 6 * * 3`). The weekly specials cycle starts on Wednesday; this day is UNVERIFIED for ALDI.
4. Connect a webhook, Google Sheets, Slack or Zapier integration to the dataset to get only what changed.

The first monitoring run returns every product as `new`. Later runs return only changes. State lives in the named key-value store `au-grocery-price-feed-state` (keys `prices-woolworths` and `prices-aldi`). Delete that store to reset.

### Use it from the API, n8n, Make, Zapier or an AI agent

- **API:** start a run and get the results in one call:
  ```bash
  curl -X POST "https://api.apify.com/v2/acts/programmx~au-grocery-price-feed/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"searchTerms": ["milk", "coffee"], "maxItems": 50}'
  ```
  The response is the dataset as JSON; add `&format=csv` for CSV. This endpoint waits up to 5 minutes; for longer runs, start the run asynchronously and read the dataset when it finishes.
- **n8n, Make and Zapier:** use the Apify node or app, choose *Run Actor*, pick this actor and paste the input JSON.
- **Google Sheets, Slack, email and webhooks:** add an integration on the actor or task in Apify Console.
- **AI agents:** add this actor to Apify's MCP server (`https://mcp.apify.com`) and call it from any MCP client.

### FAQ

#### Do I need a Woolworths or ALDI account?

No. The actor uses the same public product data that the websites show to guest shoppers.

#### Which store's prices do I get?

Woolworths returns prices for its default online store (guest session). Postcode-specific pricing is not supported yet. ALDI AU prices are national walk-in prices (ALDI AU does not sell groceries online, so there is no stock data).

#### Why is `gtin` empty for ALDI?

ALDI's API does not publish barcodes. Use `productId` (the SKU) as the key.

#### What does ALDI "Lower Prices" mean?

It is ALDI's own range of products with permanently lowered prices. ALDI rarely shows a was-price, so `wasPrice` is usually null for ALDI.

#### What counts as `isOnSpecial`?

Woolworths: the site's special flag, or a "Lower shelf price" label (Woolworths lists Lower Shelf Price under its specials menu). ALDI: products in the Super Savers or Lower Prices ranges, or with a was-price.

#### Are unavailable products included?

No. Listings with no current price (for example, temporarily unavailable at Woolworths) are skipped and not charged. `RUN_STATS.skippedNoPrice` counts them.

#### Is Coles supported?

Not yet. Coles is protected by a JavaScript bot challenge that needs a real browser. It is on the roadmap.

#### Is scraping this data allowed?

The actor only reads publicly visible prices, without logging in. You are responsible for how you use the data. Check the retailers' terms for your use case.

#### How much does a daily price tracker cost?

Example on the Free plan: a daily `onlyChanged` run over 20 search terms that returns 50 changed products costs 50 × $0.0009 = $0.045 a day, about $1.35 a month.

#### Can I export Woolworths and ALDI prices to CSV or Google Sheets?

Yes. Each run's dataset downloads as CSV, Excel or JSON, and the Google Sheets integration can append every run to a sheet.

#### Can an AI agent use this actor?

Yes. Apify's MCP server (`https://mcp.apify.com`) can expose this actor as a tool to Claude, Cursor, VS Code and other MCP clients, so an agent can fetch fresh prices on request.

### Limitations

- Woolworths: prices are for the default guest store. Very deep pagination (thousands of results for one term) has not been tested; use specific terms or the specials feed.
- ALDI: deep pagination stops around 1,000 results per query, so the specials categories and keyword searches are used instead of a full-catalogue walk.
- Coles is not included (roadmap).
- Woolworths sits behind Akamai Bot Manager. The actor warms up a guest session first and retries with a fresh session if that fails. If the warm-up keeps failing, the remaining Woolworths searches in that run are skipped (logged in `RUN_STATS.errors`) and the ALDI searches still run. Very heavy use from a single datacenter IP may get blocked; a residential proxy helps.

# Actor input Schema

## `retailers` (type: `array`):

Which supermarkets to scrape. Coles is not supported yet (see README roadmap).

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

Product keywords, searched on every selected retailer (e.g. milk, coffee, Cadbury, nappies). Leave EMPTY to get the weekly specials feed instead: Woolworths Half Price + Lower Shelf Price and ALDI Super Savers + Lower Prices.

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

Only return products on special. Woolworths: the site's 'specials' filter. ALDI: products in the Super Savers / Lower Prices ranges or with a was-price.

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

Upper limit of products read per retailer per search term (or per specials category). In monitoring mode this is how many products are checked for changes.

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

Hard cap on results pushed (and charged) in this run. The budget is shared fairly across retailers and search terms.

## `onlyChanged` (type: `boolean`):

Emit only products that are new or whose price, was-price or special status changed since the previous run (keyed by retailer + productId, state kept in the named key-value store 'au-grocery-price-feed-state'). Use with a daily schedule. The first run emits everything as 'new'.

## `onlyNew` (type: `boolean`):

Stricter variant: emit only products never seen in earlier monitoring runs (new listings). Price changes of known products are skipped.

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

Optional. If Apify Proxy is enabled here it is used (RESIDENTIAL recommended for Woolworths). Otherwise the actor uses Decodo credentials from the DECODO_USER / DECODO_PASS secret env vars if set, else connects directly.

## Actor input object example

```json
{
  "retailers": [
    "woolworths",
    "aldi"
  ],
  "searchTerms": [
    "milk",
    "coffee"
  ],
  "specialsOnly": false,
  "maxItemsPerSearch": 50,
  "maxItems": 50,
  "onlyChanged": false,
  "onlyNew": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per product: price, was price, unit price, special flag, promo label, size, brand, category, URL and GTIN where available. In monitoring mode only new or price changed products are returned.

## `runStats` (type: `string`):

Summary of the run: rows emitted and charged, requests, retries, proxy mode, errors and duration.

# 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 = {
    "retailers": [
        "woolworths",
        "aldi"
    ],
    "searchTerms": [
        "milk",
        "coffee"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("programmx/au-grocery-price-feed").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 = {
    "retailers": [
        "woolworths",
        "aldi",
    ],
    "searchTerms": [
        "milk",
        "coffee",
    ],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("programmx/au-grocery-price-feed").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 '{
  "retailers": [
    "woolworths",
    "aldi"
  ],
  "searchTerms": [
    "milk",
    "coffee"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call programmx/au-grocery-price-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,programmx/au-grocery-price-feed"
        }
    }
}
```

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/08n8tRAaY45UUlldH/builds/j1NzAENLsjKJFPLVd/openapi.json
