# Woolworths Australia Scraper (`tortuga/woolworths-scraper`) Actor

Scrape Woolworths Australia grocery products by category, search term or stock code: price, was-price, specials, unit price, brand, size, images, ratings, ingredients and nutrition.

- **URL**: https://apify.com/tortuga/woolworths-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 product scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## Woolworths Australia Scraper

Scrape Woolworths Australia (woolworths.com.au) grocery products by category, search term or stock code: current price, was-price and savings, specials and half-price deals, multibuy promotions ("2 for $6"), unit price per kg/L, stock code and barcode, brand, package size, images, ratings, health star rating, ingredients, allergens, dietary claims and nutrition. Track grocery prices, monitor promotions, build price-comparison datasets or feed a product catalogue.

Built for reliability: it talks to the same JSON endpoints the Woolworths website uses (no headless browser, no CSS selectors, no login), with browser TLS fingerprinting, automatic cookie refresh and retries. Runs of a few hundred products finish in under a minute. You pay only for the products you get.

### What data does Woolworths Australia Scraper extract?

Every product (category, search or product mode):

| Field | Description |
|---|---|
| `stockcode` | Woolworths stock code (the number in the product URL) |
| `name`, `shortName` | Product name with size ("Woolworths Lite Milk 3L") and without |
| `url` | Product page URL |
| `brand` | Brand ("Woolworths", "Dove", …) |
| `packageSize`, `unit` | Pack size ("200g", "each", "per 350g") and selling unit (`Each` or `KG` for weighed produce) |
| `price` | Current shelf price in AUD (number); `null` when the product is unavailable |
| `wasPrice` | Previous price when the product is marked down, else `null` |
| `savingsAmount` | `wasPrice - price` (0 when not on special) |
| `isOnSpecial`, `isHalfPrice` | Special / half-price flags |
| `specialText` | Header badge text such as "Save $6.00" |
| `promotion` | Promotion text such as "2 for $6.00 - $0.38/10G" or a member offer |
| `multibuy` | `{quantity, price, unitPriceText}` for "N for $X" deals, else `null` |
| `isMemberPrice` | True when the tile shows an Everyday Rewards member price |
| `unitPrice`, `unitMeasure`, `unitPriceText` | Comparative unit price, e.g. `1.65`, `"1L"`, `"$1.65 / 1L"` |
| `isAvailable`, `inStock`, `isPurchasable` | Availability flags for online shopping |
| `isNew`, `isOnlineOnly`, `isSponsored` | New-product flag, online-only flag, sponsored tile flag |
| `rating`, `reviewCount`, `ratingCount` | Average star rating (0-5) and review counts (`rating` is `null` when there are no ratings) |
| `imageUrl`, `images` | Large product image and all gallery images |
| `barcode` | GTIN / EAN barcode |
| `department`, `category`, `subcategory`, `breadcrumbs` | Woolworths taxonomy, e.g. "Fruit & Veg" > "Vegetables" > "Mushrooms" |
| `healthStarRating` | Health Star Rating (0.5-5) where displayed |
| `description` | Product description (HTML stripped) |
| `ingredients` | Ingredient list |
| `allergens`, `allergensMayBePresent`, `allergyStatement` | "Contains", "May contain" and "X Free" lists |
| `dietaryClaims` | "Gluten Free", "Vegan", "Low Fat", … |
| `countryOfOrigin`, `storageInstructions` | Where available on the listing tile |
| `nutrition` | `[{name, per100g, perServe}]` from the nutrition information panel |
| `supplyLimit`, `minimumQuantity` | Purchase limits |
| `tags` | Tile badges: "Australian Grown", "Half Price", "Fresh Special", "Buy More Save More", … |
| `sourceUrl`, `searchTerm`, `scrapedAt` | Category URL or search term that produced the item, and the run timestamp |

With **Include product details** on (or in product mode), each item also gets:

| Field | Description |
|---|---|
| `nutrition` | Full nutrition table with both per-serve and per-100 g/mL values |
| `servingSize`, `servingsPerPack` | Serving information |
| `countryOfOrigin`, `countryOfOriginText`, `australianIngredientsPercent` | Country-of-origin label ("Product of Australia", 100) |
| `storageInstructions`, `directions`, `productWarnings`, `suitableFor` | Usage and safety information |
| `aisle` | Woolworths store aisle ("skim & reduced fat milk") |
| `images`, `videoUrl`, `variants` | Extra gallery images, product video and size/colour variants (`{stockcode, name, url}`) |

### How to use Woolworths Australia Scraper

1. Pick a **Mode**:
   - **Category**: paste browse URLs such as `https://www.woolworths.com.au/shop/browse/fruit-veg`, `.../shop/browse/dairy-eggs-fridge/milk`, `.../shop/browse/fruit-veg/fruit/apples-pears` or `.../shop/browse/specials/half-price`. Every page of the category is followed.
   - **Search**: enter terms such as `almond milk` or `dishwasher tablets`.
   - **Product**: paste product URLs or stock codes to get single products with full details.
2. Set **Max items** to cap the run (and the cost).
3. Optionally switch on **Include product details**, **Only specials**, or change the **Sort order** (price low to high, unit price, newest, …).
4. Click **Start**. Results appear in the **Dataset** tab; export as JSON, CSV or Excel, or read them through the API.

### Input example

```json
{
  "mode": "category",
  "categoryUrls": ["https://www.woolworths.com.au/shop/browse/specials/half-price"],
  "maxItems": 500,
  "onlySpecials": true,
  "includeDetails": false
}
```

Search mode:

```json
{
  "mode": "search",
  "searchTerms": ["almond milk", "oat milk"],
  "maxItems": 100,
  "sort": "PriceAsc"
}
```

### Output example

```json
{
  "stockcode": 905071,
  "name": "Dove Women Advanced 72hr Deodorant Aerosol Pomegranate 250mL",
  "url": "https://www.woolworths.com.au/shop/productdetails/905071/dove-women-advanced-72hr-deodorant-aerosol-pomegranate",
  "brand": "Dove",
  "packageSize": "250mL",
  "unit": "Each",
  "price": 6.0,
  "wasPrice": 12.0,
  "savingsAmount": 6.0,
  "isOnSpecial": true,
  "isHalfPrice": true,
  "specialText": "Save $6.00",
  "promotion": null,
  "multibuy": null,
  "unitPrice": 2.4,
  "unitMeasure": "100ML",
  "unitPriceText": "$2.40 / 100ML",
  "isAvailable": true,
  "inStock": true,
  "rating": null,
  "reviewCount": 0,
  "imageUrl": "https://cdn0.woolworths.media/content/wowproductimages/large/905071.jpg",
  "barcode": "9300830087976",
  "department": "Personal Care",
  "category": "Deodorants",
  "breadcrumbs": ["Personal Care", "Deodorants", "Women's Deodorants"],
  "tags": ["Half Price"],
  "sourceUrl": "https://www.woolworths.com.au/shop/browse/specials/half-price",
  "scrapedAt": "2026-09-08T22:30:00+00:00"
}
```

### How to scrape Woolworths specials and half-price deals

Use category mode with `https://www.woolworths.com.au/shop/browse/specials/half-price` (or a department under it, e.g. `.../specials/half-price/pantry`) and, if you only want price cuts, switch on **Only specials**. `wasPrice`, `savingsAmount`, `isHalfPrice` and `specialText` tell you the size of the discount; `multibuy` captures "2 for $X" deals. Run it daily on a schedule to build a price history.

### How to get Woolworths prices per kg or per litre

Every item carries `unitPrice` and `unitMeasure` (for example `20.0` and `1KG` for a 200 g punnet at $4.00) plus the display string `unitPriceText`. Weighed produce sold per kg has `unit: "KG"` and a `packageSize` such as "per 350g".

### How to track a specific product's price

Use product mode with the product URL or stock code (`888141`). Each run returns the current `price`, `wasPrice` and availability plus the full nutrition and origin details. Schedule the Actor and diff the dataset over time.

### Does it work without login or a browser?

Yes. The Actor only reads the public JSON endpoints behind the Woolworths website, with browser-like TLS fingerprinting and the site's own anti-bot cookies obtained from a normal page load. No account, no headless browser, no captcha. Prices are the standard online prices Woolworths shows before a delivery address is chosen; store-specific pricing and in-store-only availability are not covered.

### Pricing

Pay per result: a small fee per product saved, plus a small extra fee per product detail fetched when **Include product details** is on or in product mode. There is no subscription; Apify's free plan is enough to try it.

### Integrations and API

Use the run in Zapier, Make, n8n, Google Sheets, or call it from Python/Node with the Apify client. See the **API** tab for ready-made snippets.

### Is it legal to scrape Woolworths?

This Actor collects only publicly available, non-personal product data (prices, descriptions, nutrition). It does not log in and does not collect any user or reviewer information. You are responsible for how you use the data and for complying with Woolworths' terms and applicable law.

### Support

Found a bug or need a field added? Open an issue in the **Issues** tab; it is usually answered within a day.

# Actor input Schema

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

What to scrape: `category` walks Woolworths browse pages (Category URLs), `search` runs search terms, `product` fetches individual products by URL or stock code (always with full details).

## `categoryUrls` (type: `array`):

Woolworths browse URLs, one per line: a department (https://www.woolworths.com.au/shop/browse/fruit-veg), an aisle (.../shop/browse/dairy-eggs-fridge/milk), a sub-aisle (.../fruit-veg/fruit/apples-pears) or a specials page (.../shop/browse/specials/half-price). Every page of the category is followed automatically (36 products per page). Used when Mode is `category`.

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

Search queries such as `almond milk` or `dishwasher tablets`. Each term is paginated like the website search. Used when Mode is `search`.

## `productUrls` (type: `array`):

Product page URLs like https://www.woolworths.com.au/shop/productdetails/888141/woolworths-lite-milk. Used when Mode is `product`.

## `stockcodes` (type: `array`):

Woolworths stock codes (the number in the product URL), e.g. `888141`. Used when Mode is `product`, together with or instead of Product URLs.

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

Stop after this many products in total (across all categories / search terms). Keeps cost predictable.

## `includeDetails` (type: `boolean`):

Also open every product's detail endpoint to add the full nutrition table (per serve and per 100 g, serving size), country-of-origin label with Australian-ingredient percentage, storage instructions, directions, product warnings and variants. Listing items already carry description, ingredients, allergens, dietary claims and per-100 g nutrition without this. Charged extra per product (see pricing).

## `onlySpecials` (type: `boolean`):

Keep only products that are on special: a price cut (`isOnSpecial`), a half-price deal or a promotion such as `2 for $6`. The server-side specials filter is applied first, so fewer pages are fetched.

## `includeSponsored` (type: `boolean`):

Listing pages carry 4-8 sponsored product tiles that repeat across pages and may belong to other aisles. Off by default so the dataset matches the category's real product list; switch on to keep them (flagged with `isSponsored: true`).

## `sort` (type: `string`):

Order in which Woolworths returns products (matters when Max items cuts a category short).

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

Apify Proxy is recommended. Datacenter proxies worked in testing; switch to residential (Australia) if runs report HTTP/2 stream resets or 403s.

## Actor input object example

```json
{
  "mode": "category",
  "categoryUrls": [
    "https://www.woolworths.com.au/shop/browse/fruit-veg"
  ],
  "searchTerms": [
    "almond milk"
  ],
  "maxItems": 200,
  "includeDetails": false,
  "onlySpecials": false,
  "includeSponsored": false,
  "sort": "TraderRelevance",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (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 = {
    "categoryUrls": [
        "https://www.woolworths.com.au/shop/browse/fruit-veg"
    ],
    "searchTerms": [
        "almond milk"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/woolworths-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 = {
    "categoryUrls": ["https://www.woolworths.com.au/shop/browse/fruit-veg"],
    "searchTerms": ["almond milk"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/woolworths-scraper").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 '{
  "categoryUrls": [
    "https://www.woolworths.com.au/shop/browse/fruit-veg"
  ],
  "searchTerms": [
    "almond milk"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call tortuga/woolworths-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tortuga/woolworths-scraper"
        }
    }
}
```

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/gPdO2aK1mJcso0IjN/builds/kN8xCAXnljN68VLSf/openapi.json
