# Chemist Warehouse AU – Products, Prices & Reviews (`abotapi/chemistwarehouse-com-au-scraper`) Actor

Scrape chemistwarehouse.com.au products with prices, RRP, discounts, stock, images, ingredients, directions, warnings, categories, and full customer reviews. Search by keyword or product URLs, with brand, category, price, in-stock filters, and price sorting.

- **URL**: https://apify.com/abotapi/chemistwarehouse-com-au-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce, Developer tools, Automation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 products

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/platform/actors/running/actors-in-store#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

## Chemist Warehouse Scraper - Products & Reviews

Scrape products and customer reviews from **Chemist Warehouse** (chemistwarehouse.com.au), Australia's largest pharmacy retailer. Browse the **Promotions (catalogue specials)** and **Clearance** collections, search by keyword, or scrape specific product pages — and get rich product data, **was/original price + savings**, and every individual customer review.

### What you get

For every product (50+ fields):

- **Identity** - name, canonical title, brand, manufacturer, product type, SKU, product id, page URL, slug
- **Pricing & specials** - current price, was/RRP price, savings amount, savings percent, on-special flag, promo label (e.g. "Better Than Half Price", "50% Off", "Clearance", "In Catalogue"), discount %, currency
- **Availability** - in stock, click & collect, fast delivery, international shipping, marketplace
- **Pharmacy** - prescription type, schedule, mandatory statement, adult-product flag
- **Content** - description, ingredients, directions, warnings
- **Media** - main image + full image gallery
- **Categories** - full category path and category keys
- **Ratings** - average rating and review count
- **Reviews** (optional) - every individual review with **rating, title, author, body text, date, and helpful-vote counts**, plus the star-rating breakdown and true review total
- **Extras** - dimensions (H/W/D/weight), pack quantity, multipack quantity, product flags, created date, scrape timestamp

### Input

#### Mode

- **Search** - run one or more keyword queries with optional specials, brand, category, price and in-stock filters, and price sorting.
- **URL** - provide specific Chemist Warehouse product page URLs, or a specials/category listing URL (e.g. `/catalogue`, `/shop-online/3240/clearance`).

#### Search options

| Field | Description |
|---|---|
| Search keywords | One or more keywords, e.g. `panadol`, `vitamin c`. Leave empty to browse the whole catalogue with the filters below. |
| Specials / offers | Limit to a specials collection: **Promotions** (current weekly-catalogue offers — ½-price, 50% off, better-than-half-price) or **Clearance** (reduced-to-clear). Combine with keywords/brand/price to narrow within the specials. Leave as *Any* for all products. |
| Brand | Restrict to one brand, e.g. `Blackmores` (exact spelling). |
| Category | Restrict to one category, e.g. `Vitamins & Supplements` (exact spelling). |
| Minimum / Maximum price (AUD) | Price range in whole dollars. |
| In-stock only | Exclude out-of-stock products. |
| Sort | Relevance (default), price low→high, or price high→low. |

#### Specials, was-price & discount

Chemist Warehouse shows a struck-through **RRP** with a **"Save $X"** on most product cards (their standard below-RRP pricing). Whenever the current price is below RRP, the Actor fills `wasPrice` (the RRP), `savingsAmount`, `savingsPercent` and sets `isOnSpecial: true`; when the price equals RRP there is no saving, so those fields are `null`/`false` — **never fabricated**. The **curated** promotional offers are the `Promotions` (weekly catalogue) and `Clearance` collections (the **Specials / offers** input above), and each product's own catalogue badge is surfaced verbatim in `promoLabel`.

#### Reviews

| Field | Description |
|---|---|
| Fetch reviews | Collect individual customer reviews for each product. |
| Max reviews per product | Cap on reviews per product. Leave empty for all reviews. |

#### Limits

- **Max items** is the run cap (default 20). Set to 0 for no item limit.
- **Max pages** limits result pages walked per query. Leave empty (0) for no page limit; the run stops at **Max items**.

#### Resume and recurring updates

Two different things:

- **Resume from a previous run** — paste a previous run ID or dataset ID to continue one specific interrupted catalogue pull without re-scraping (or re-charging) products already collected there.
- **Incremental changes for scheduled runs** — turn on for daily/recurring monitoring of the same search. Each product is classified as `NEW`, `UPDATED`, `UNCHANGED`, `REAPPEARED`, or `EXPIRED` against the last run's state (`changeType`/`changedFields`/`firstSeenAt`/`lastSeenAt` on the record). Off by default; `emitUnchanged` and `emitExpired` opt into returning (and billing) those extra rows. State is tracked separately per mode/query/filter/fetch-reviews setup unless you set a **State key**.

### Output example

```json
{
  "name": "Blackmores Bio C 1000 150 Tablets",
  "title": "Blackmores Bio C 1000 150 Tablets",
  "brand": "Blackmores",
  "sku": "2720171",
  "url": "https://www.chemistwarehouse.com.au/buy/57134-blackmores-bio-c-1000-150-tablets",
  "price": 21.99,
  "rrp": 48.99,
  "wasPrice": 48.99,
  "savingsAmount": 27.00,
  "savingsPercent": 55.11,
  "isOnSpecial": true,
  "promoLabel": "Better Than Half Price",
  "discountPercent": 55.11,
  "currency": "AUD",
  "isInStock": true,
  "rating": 4.6286,
  "reviewCount": 35,
  "categories": ["Chemist Warehouse Australia", "Categories", "Vitamins & Supplements"],
  "ingredients": "Ascorbic Acid (Vitamin C) ...",
  "directions": "Adults take 1 tablet a day ...",
  "warnings": "Vitamin supplements should not replace ...",
  "images": ["https://static.chemistwarehouse.com.au/..."],
  "reviews": [
    {
      "rating": 5,
      "title": "Great product",
      "author": "belly76",
      "content": "Works really well ...",
      "createdAt": "2025-11-20T00:44:12.000+00:00",
      "positiveFeedbackCount": 2,
      "negativeFeedbackCount": 0
    }
  ]
}
```

### Proxy & plan

Apify Proxy is recommended and enabled by default. The Actor runs on any Apify plan. If results look incomplete, switch the Apify Proxy group in the Proxy input to a higher-reliability option.

### Pricing

This Actor uses pay-per-event pricing: a one-time start charge, a per-product charge, and a per-product reviews-enrichment charge that applies only when **Fetch reviews** is enabled.

### Send results into your apps (MCP connectors)

Results can be pushed into your apps and workflows via Apify's integrations and MCP connectors.

# Actor input Schema

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

How to collect products. Search runs keyword/filter queries. URL scrapes specific product pages you provide.

## `queries` (type: `array`):

Search mode only. One or more keywords, e.g. "panadol", "vitamin c". Leave empty to browse the whole catalogue with the filters below.

## `brand` (type: `string`):

Search mode only. Restrict results to one brand, e.g. "Blackmores" or "Panadol" (exact spelling as shown on site).

## `category` (type: `string`):

Search mode only. Restrict results to one category, e.g. "Vitamins & Supplements" or "Pain Relief" (exact spelling as shown on site).

## `minPrice` (type: `integer`):

Search mode only. Only products priced at or above this amount, in whole dollars.

## `maxPrice` (type: `integer`):

Search mode only. Only products priced at or below this amount, in whole dollars.

## `inStockOnly` (type: `boolean`):

Search mode only. Exclude out-of-stock products.

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

Search mode only. Result ordering.

## `specialsCategory` (type: `string`):

Search mode only. Limit results to a Chemist Warehouse specials collection. Promotions covers the current weekly-catalogue offers (½-price, 50% off, better-than-half-price); Clearance is reduced-to-clear stock. Combine with keywords, brand or price to narrow within the specials. Leave as 'Any' for all products.

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

URL mode only. Chemist Warehouse product page URLs, e.g. https://www.chemistwarehouse.com.au/buy/145683/panadol-500mg-16-tablets

## `fetchReviews` (type: `boolean`):

Fetch individual customer reviews (rating, title, author, body, date, helpful counts) for each product. Adds a review-enrichment charge per product.

## `maxReviewsPerProduct` (type: `integer`):

Cap on reviews collected per product when Fetch reviews is on. Leave empty for all reviews.

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

Maximum number of products to collect. This is the run cap. Set to 0 for no item limit (the run then stops at Max pages).

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

Maximum number of search result pages to walk per query. Leave empty (0) for no page limit; the run stops at Max items.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large catalogue pull without returning or charging for products already collected there. Use this after an interrupted run. For recurring monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns all matching products as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED products. Turn on "Emit unchanged" or "Emit expired" only when you also want those products returned (and billed). State is kept separately for each mode/query/filter/fetch-reviews setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the mode/query/filter/fetch-reviews settings — different searches then never mix state with each other.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return products that have not changed since the last run, marked UNCHANGED. This returns — and bills — extra rows you already have, so leave it off unless you specifically want the full snapshot every run.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return products that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search — not when Max items capped it or when Resume was used. This returns — and bills — extra synthetic rows, so leave it off unless you need expiry tracking.

## `proxy` (type: `object`):

Proxy configuration. Apify Proxy is recommended.

## `mcpConnectors` (type: `array`):

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify Settings, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON; the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "queries": [
    "vitamin c"
  ],
  "inStockOnly": false,
  "sort": "relevance",
  "specialsCategory": "",
  "productUrls": [
    "https://www.chemistwarehouse.com.au/buy/145683/panadol-500mg-16-tablets"
  ],
  "fetchReviews": false,
  "maxReviewsPerProduct": 20,
  "maxItems": 20,
  "maxPages": 0,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true
  },
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (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 = {
    "queries": [
        "vitamin c"
    ],
    "productUrls": [
        "https://www.chemistwarehouse.com.au/buy/145683/panadol-500mg-16-tablets"
    ],
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/chemistwarehouse-com-au-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 = {
    "queries": ["vitamin c"],
    "productUrls": ["https://www.chemistwarehouse.com.au/buy/145683/panadol-500mg-16-tablets"],
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/chemistwarehouse-com-au-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "vitamin c"
  ],
  "productUrls": [
    "https://www.chemistwarehouse.com.au/buy/145683/panadol-500mg-16-tablets"
  ],
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false
}' |
apify call abotapi/chemistwarehouse-com-au-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=abotapi/chemistwarehouse-com-au-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/IH1pxf2wKuTuseJdd/builds/ZrWsg8uzGVO0G9g7h/openapi.json
