# ALDI Australia Products & Special Buys Scraper (`automation-lab/aldi-australia-products-special-buys`) Actor

Export ALDI Australia products and dated Special Buys with AUD prices, unit prices, pack sizes, brands, images and source URLs for recurring assortment and promotion comparisons.

- **URL**: https://apify.com/automation-lab/aldi-australia-products-special-buys.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.62 / 1,000 item processeds

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

## ALDI Australia Products & Special Buys Scraper

Collect **ALDI Australia products** from public grocery categories and dated Special Buys listings. Export names, brands, current AUD prices, unit-price text, pack sizes, images, product IDs, source categories and displayed on-sale dates for assortment and promotion comparisons.

This is an unofficial, logged-out collection tool for **aldi.com.au**. It does not check live store inventory, purchase goods, search by keyword or collect other countries.

### Who is this for?

Retail analysts can compare category snapshots over time. Promotion teams can track the products announced for a displayed Special Buys date. Data teams can join recurring exports by product ID, keeping the retrieval timestamp and listing URL as provenance.

### Why use this scraper?

- Collect category cards without downloading product images or visiting every detail page.
- Follow listing pagination while respecting global product and page caps.
- Discover current dated Special Buys links rather than hard-coding last week's dates.
- Preserve missing values as null instead of inventing pack sizes or sale dates.
- Deduplicate by ALDI product ID across overlapping listings within each run.

Each run is a snapshot, not a built-in historical database or change-alert service. Schedule and compare snapshots downstream.

### Getting started

1. Open an Australian ALDI category and copy its full URL.
2. Add the URL to **Category or Special Buys URLs**.
3. Choose a maximum number of unique products and a page cap.
4. Run the Actor and inspect its default dataset.
5. Download JSON, CSV or Excel using Apify's dataset export controls.

A small category example:

```json
{
  "startUrls": [
    {"url": "https://www.aldi.com.au/products/snacks-confectionery/k/1588161408332087"}
  ],
  "maxItems": 100,
  "maxPages": 20
}
```

### Inputs

| Field | Default | Behavior |
|---|---|---|
| `startUrls` | `[]` | Category or Special Buys URLs; omitted/empty discovers public top-level categories and the Special Buys hub. |
| `maxItems` | `100` | Global unique-product cap, 1–10,000; form prefill 20; zero/unlimited is unsupported. |
| `maxPages` | `20` | Global successful listing/hub-page cap, 1–200. Initial homepage discovery is outside this count. |

Accepted routes are `/products/.../k/ID`, `/special-buys`, and `/special-buys/YYYY-MM-DD` on HTTPS aldi.com.au. The non-www hostname is normalized to www. Product detail URLs, search URLs, foreign domains and unknown query parameters are rejected.

Only `page` and dated-listing `theme` URL parameters are supported. A positive `page` begins at that listing page; subsequent pages are followed. A theme is ALDI's own URL filter, not a free-text keyword match. There are no additional text filters.

### Special Buys and navigation discovery

Use `https://www.aldi.com.au/special-buys` to discover currently linked dated listings. Alternatively, supply a current dated URL copied from ALDI, optionally with its `theme` parameter.

An empty `startUrls` list fetches the homepage and discovers top-level grocery category links plus the Special Buys hub. The discovered order is source-controlled and may change. A small `maxItems` may fill entirely from the first category: it does not ensure balanced category coverage. Supply explicit URLs for focused comparisons.

Dates in examples are illustrative; ALDI removes or changes old promotion pages. The Actor does not promise historical Special Buys retrieval.

### Extracted fields

| Field | Meaning |
|---|---|
| `productId` | Source SKU as a string, including leading zeros. |
| `name`, `brand` | Product name and displayed brand. |
| `price`, `currency` | Current relevant listing price in AUD dollars; `currency` is AUD. |
| `unitPrice` | ALDI comparison text, such as `$2.20 per 100 g`; not a computed unit price. |
| `packSize` | Source selling size or displayed selling unit. |
| `categories` | Source product category labels; may differ from the seed's navigation category. |
| `saleDate`, `saleDateDisplay` | Source on-sale date and display label, when supplied. |
| `imageUrl` | First source image URL with a 600-pixel width. Images are not downloaded. |
| `url` | Australian product detail link. |
| `sourceUrl` | First listing page that supplied this product in the run. |
| `retrievedAt` | UTC normalization timestamp. |

Missing optional values are null; absent categories are an empty array. A price is not an assurance that a product is in stock locally. No store availability field is inferred from online purchase flags.

### Output example

This representative category record was observed during implementation; price and assortment can change:

```json
{
  "productId": "000000000000173130",
  "name": "Mega Roulette 45g",
  "brand": "HARIBO",
  "price": 0.99,
  "currency": "AUD",
  "unitPrice": "$2.20 per 100 g",
  "packSize": "45 g",
  "categories": ["Pantry", "Confectionery"],
  "saleDate": null,
  "saleDateDisplay": null,
  "imageUrl": "https://dm.apac.cms.aldi.cx/is/image/aldiprodapac/product/jpg/scaleWidth/600/f565efbc-67cf-4f99-bbcc-20145ad72315/haribo-mega-roulette-45g",
  "url": "https://www.aldi.com.au/product/haribo-mega-roulette-45g-000000000000173130",
  "sourceUrl": "https://www.aldi.com.au/products/snacks-confectionery/k/1588161408332087",
  "retrievedAt": "2026-10-15T20:05:23.799Z"
}
```

### Pagination, limits and completeness

Seeds are processed in order. The Actor finishes a selected listing's pages before moving to the next seed. It stops on the first of the item cap, global page cap, source exhaustion, charge ceiling or platform runtime limit.

Products are unique by SKU within a run. The first encountered row wins, including source context. Separate runs intentionally collect the same IDs again for snapshot comparison. A capped run is a partial snapshot, not a complete catalogue. A failed run may retain partial rows; do not treat those as a complete successful collection.

### How much does it cost to export ALDI Australia products?

Pricing is pay-per-event: **$0.00005 per run** plus each product successfully saved. There is no separate charge event for images, categories, sale dates or pagination.

| Apify plan tier | Per product | Per 1,000 products, excluding start |
|---|---:|---:|
| FREE | $0.001196 | $1.196 |
| BRONZE | $0.00104 | $1.04 |
| SILVER | $0.0008112 | $0.8112 |
| GOLD | $0.000624 | $0.624 |
| PLATINUM | $0.000624 | $0.624 |
| DIAMOND | $0.000624 | $0.624 |

Example BRONZE total event charges (start plus saved rows): 10 rows → $0.01045; 100 rows → $0.10405; 1,000 rows → $1.04005. These are Actor event charges, not a quote for any separate Apify account charges. A run with no saved products can still incur the start fee. Set a charge ceiling and reasonable collection limits.

### Integrations

- **Google Sheets:** export each snapshot into a dated sheet and compare price changes by `productId`.
- **Make or Zapier:** trigger a run on your schedule, wait for completion and send bounded dataset rows to your workflow.
- **Data warehouses:** retain `retrievedAt` and `sourceUrl`, then compare daily or weekly assortment snapshots.
- **Promotion calendars:** group rows by displayed `saleDate` without assuming every product has one.

Apify provides scheduling, webhooks and dataset exports; this Actor does not independently send alerts or retain a cross-run history.

### API usage

Start a run with your own token stored securely outside code. Keep the returned run and dataset IDs, check the same run until terminal, then retrieve its dataset.

```bash
curl -X POST 'https://api.apify.com/v2/acts/automation-lab~aldi-australia-products-special-buys/runs' \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"startUrls":[{"url":"https://www.aldi.com.au/special-buys"}],"maxItems":50}'
```

JavaScript, using the official Apify client:

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/aldi-australia-products-special-buys').call({
  startUrls: [{ url: 'https://www.aldi.com.au/special-buys' }], maxItems: 50
});
if (run.status !== 'SUCCEEDED') throw new Error(`Run ${run.id}: ${run.status}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems({ limit: 50 });
```

Python:

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/aldi-australia-products-special-buys').call(
    run_input={'startUrls': [{'url': 'https://www.aldi.com.au/special-buys'}], 'maxItems': 50})
if run['status'] != 'SUCCEEDED':
    raise RuntimeError(f"Run {run['id']}: {run['status']}")
rows = client.dataset(run['defaultDatasetId']).list_items(limit=50).items
```

### MCP use

Use the Actor-specific hosted endpoint with an authorized Apify account:

```bash
claude mcp add --transport http apify \
  'https://mcp.apify.com?tools=automation-lab/aldi-australia-products-special-buys'
```

For Claude Desktop, Cursor and VS Code, use the equivalent desktop/editor configuration (client syntax may vary):

```json
{"mcpServers":{"aldi":{"url":"https://mcp.apify.com?tools=automation-lab/aldi-australia-products-special-buys"}}}
```

Example prompt: “Collect up to 25 products from ALDI Australia's current Special Buys and show name, price and sale date.” Discover actual tool names and input schemas using scoped `tools/list`. Actor selection also exposes run/data helpers; it is not exactly one tool. Discovery alone does not authorize a run.

For an authorized invocation, start once and keep the returned run ID. `call-actor` waits up to 45 seconds (`waitSecs`, default 30); returned IDs are metadata, not rows. If pending, check **that same run** using `get-actor-run`, with 2/4/8-second backoff capped at 10 seconds and a total 120-second deadline. Set client timeout above the selected server wait plus transport margin. Recover the known run after client timeout; do not blindly start another. At deadline, report pending and its ID. Report terminal failures honestly, with any rows labelled partial.

After success, read the returned `defaultDatasetId` using `get-dataset-items` with explicit offset, limit and fields. An example consumer context budget is pages of 20 source rows, at most 100 rows or 64 KiB of serialized UTF-8 content, whichever comes first. Enforce that byte ceiling host-side before model injection, including oversized pages; otherwise do not claim a hard byte guarantee. Track source offsets, report truncation and continuation offset, and keep full exports outside model context. These are consumer context limits, not smaller Actor collection defaults. Client caching and tool discovery do not guarantee universal token savings.

### Reliability and troubleshooting

Requests are sequential and use direct public HTTP, with no paid proxy fallback. Transient network, 429 and server failures receive up to three total attempts with backoff. Deterministic HTTP errors and missing structured listing state fail explicitly rather than returning a misleading empty success.

### FAQ

**Why did I receive fewer rows than expected?** Check the page cap, source count, duplicate IDs, item cap and charge ceiling. A dated theme can naturally contain few records.

**Why did an old dated URL fail?** ALDI can remove past promotions. Copy a currently linked date or use the Special Buys hub.

**Can I search for a product or check store stock?** No. Use category/date URLs; free-text search, personal accounts and stock-by-store queries are outside this Actor's scope.

**Is the sale date the retrieval date?** No. It is ALDI's source-provided on-sale date, or null. `retrievedAt` records collection time separately.

### Legality, responsible use and diagnostics

Collect only public information you are entitled to use, respect applicable terms and laws, and avoid excessive requests. ALDI names and trademarks belong to their owners; this Actor is not affiliated with ALDI. Check source pages before using prices or promotions for purchasing decisions.

No AI model is used by the running Actor or to transform its records. Data is processed transiently; output and platform logs remain in your Apify storage under your account's retention/deletion controls. Delete run storage through Apify when no longer needed. No cross-run product cache is retained by the Actor. Contact the developer through the Actor's Issues tab for help, including a run link and non-sensitive input.

Failed operations send sanitized diagnostic input, exceptions and Actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL queries are removed; reports are retained for 30 days. Do not submit credentials or personal information in input URLs.

### Related Actors

For category-only ALDI snapshots, see [ALDI Australia Grocery Category Products & Prices](https://apify.com/automation-lab/aldi-australia-grocery-products-prices). For UK grocery comparisons, see [ASDA Grocery Products & Prices](https://apify.com/automation-lab/asda-grocery-products-prices). Each Actor has its own supported sources and input contract; this Actor adds current dated Special Buys navigation to Australian category snapshots.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/aldi-australia-products-special-buys/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

Optional HTTPS aldi.com.au category /products/.../k/ID or /special-buys\[/YYYY-MM-DD] URLs. An omitted or empty list discovers top-level categories and Special Buys from public navigation. A Special Buys hub discovers displayed dated listings. URL page and dated theme parameters are preserved; other parameters, product detail URLs, other countries and search are rejected. Lists are processed in order with pagination before the next seed.

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

Global cap on unique product IDs saved across all seeds and pages after deduplication. Default 100; range 1–10000. Zero/unlimited is unsupported. The same product encountered again is skipped; its first listing supplies source context. Billing and page/runtime limits may stop collection earlier.

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

Global cap on successful listing or Special Buys hub pages fetched, including pagination. Default 20; range 1–200. The initial homepage used for empty-list discovery does not count. Collection can be partial at this cap; this is not a whole-catalog completeness guarantee.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.aldi.com.au/products/snacks-confectionery/k/1588161408332087"
    }
  ],
  "maxItems": 20,
  "maxPages": 20
}
```

# Actor output Schema

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

Products with identity, AUD prices, pack details, source URLs and displayed on-sale dates.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.aldi.com.au/products/snacks-confectionery/k/1588161408332087"
        }
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/aldi-australia-products-special-buys").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 = {
    "startUrls": [{ "url": "https://www.aldi.com.au/products/snacks-confectionery/k/1588161408332087" }],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/aldi-australia-products-special-buys").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 '{
  "startUrls": [
    {
      "url": "https://www.aldi.com.au/products/snacks-confectionery/k/1588161408332087"
    }
  ],
  "maxItems": 20
}' |
apify call automation-lab/aldi-australia-products-special-buys --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/aldi-australia-products-special-buys"
        }
    }
}
```

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/NVg2oUVM5TQ0ZxFGm/builds/KNx7vUyKZq0Rekf7P/openapi.json
