# Checkers & Shoprite Scraper: Prices, Specials & Xtra Savings (`zaiq/checkers-scraper`) Actor

Scrape Checkers and Shoprite (Shoprite group, Sixty60) products by search term, category or URL: prices, specials, Xtra Savings member prices with dates, multi-buys, barcodes, stock and unit prices, by region. For SA grocery price monitoring. Failed pages are free.

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

## Pricing

from $4.00 / 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/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

## Checkers & Shoprite Scraper: Prices, Specials & Xtra Savings

Get product prices, specials and Xtra Savings member prices from Checkers (checkers.co.za) and Shoprite
(shoprite.co.za), the Shoprite group's online stores and Sixty60 delivery, as structured data. Search by keyword,
open a category or product list, or give product links; choose one or more South African regions to see each
region's own prices and stock. Every request goes through South African home internet connections.

### What it does

- Searches the catalogue like the site's search box, reads categories, promotion product lists (`?plid=`) and single
  products, and finds products by barcode (EAN-13).
- Returns, for every product: price, was-price, Xtra Savings member price with its start and end date, every
  promotion (fixed price, rand off, percentage off, multi-buys such as "Buy 3 For R12") with dates, barcode(s), brand,
  pack size, unit price per kg, litre or item, stock status and the number in stock at the serving store, image,
  product link and the store that served it.
- Regions: prices, stock and ranging follow the stores that deliver to an address, and they differ between regions.
  Pick cities (Cape Town, Johannesburg, Pretoria, Durban, Gqeberha and others) or any latitude,longitude; each product
  is returned once per region.
- Checkers or Shoprite: both sites run on the same platform with their own prices and deals. Pick the brand with
  Store brand.
- Specials only: returns just the products the site lists under its deals filter.
- Weighed products (meat, poultry) are marked `soldByWeight` with the price per kg and the pack's weight range.

### Who uses it

- **Price comparison and basket-tracking sites** that follow grocery prices and specials across South African chains.
- **FMCG brands and their agencies** checking shelf prices, Xtra Savings deals and stock of their products by region.
- **Retail and economic analysts** tracking food inflation from real shelf prices, with unit prices.
- **Shoppers and community groups** watching specials on a list of everyday products.

### Example

Three products checked in four regions on Checkers on 4 October 2026 (product links as input, region option on):

| Product | Cape Town | Johannesburg | Durban | Polokwane |
|---|---|---|---|---|
| Jacobs Krönung Freeze Dried Instant Coffee 200g | R204.99 (Xtra Savings R156.99) | R209.99 (R159.99) | R219.99 (R159.99) | R209.99 (R159.99) |
| Clover Full Cream Milk 1L | R21.99 | R22.99 | R21.99 | R22.99 |
| Clover Fresh Full Cream Milk 2L | R37.99 (Xtra Savings R29.99) | R37.99 (R29.99) | R37.99, no member deal | R37.99 (R29.99) |

The same jar of coffee cost R15 more in Durban than in Cape Town, and the milk deal was not on in Durban. Stock at the
serving store ranged from 170 (Cape Town) to 1,625 (Polokwane) for the 1L milk.

Other test runs the same day, all through South African residential connections:

- 20 everyday search terms (milk, bread, coffee, washing powder, nappies and so on), 60 products each: 1,200 products
  in 28 seconds, no failed or blocked requests.
- A whole department (Milk, Dairy & Eggs, 797 products on the site): 350 products, paged without gaps.
- Specials only for coffee and chocolate: 72 products, 33 with an Xtra Savings member price; 10 of them out of stock.
- Shoprite in Johannesburg, "5kg chicken" and two other searches: 112 products.

### Input

```json
{
  "banner": "checkers",
  "searchTerms": ["milk", "coffee"],
  "startUrls": [{ "url": "https://www.checkers.co.za/department/bakery/bread-rolls-wraps-and-bagels-2-670437dc7a8738098af92e28" }],
  "regions": ["cape-town", "johannesburg"],
  "maxItemsPerSource": 100,
  "specialsOnly": false
}
```

| Field | What it does |
|---|---|
| `banner` | `checkers` (default) or `shoprite`. URLs must be from the chosen site. |
| `searchTerms` | Words to search for. A barcode (EAN-13) finds that product. |
| `startUrls` | Category (`/department/...`), product list (`/search?plid=...`), search (`/search?Search=...`) or product (`/product/...-10392555EA`) links, or a bare article number with its unit (`10392555EA`). |
| `regions` | Cities whose stores' prices to read; empty means the site's default (no address). |
| `customLocations` | Any other delivery location as `latitude,longitude`, for example `-33.5779,18.4967`. |
| `maxItemsPerSource` | Products per search term or URL (default 100). A product link gives one. |
| `maxItems` | Products in total for the run; 0 means no total limit. |
| `specialsOnly` | Only products on promotion. |
| `sort` | `relevance` (default), `price_low`, `price_high` or `name`. |
| `proxyConfiguration`, `maxConcurrency` | Advanced: South African residential connections by default; requests at once (default 6). |

### Output

One row per product (per region when regions are chosen). This row is from the example above, with the description
shortened:

```json
{
  "retailer": "Checkers",
  "productId": "10164411EA",
  "sku": "10164411",
  "barcode": "8711000521045",
  "name": "Jacobs Krönung Freeze Dried Instant Coffee 200g",
  "brand": "Jacobs",
  "size": "200 g",
  "sizeValue": 200.0,
  "sizeUnit": "g",
  "packCount": 1,
  "soldByWeight": false,
  "price": 209.99,
  "currency": "ZAR",
  "wasPrice": null,
  "promoPrice": null,
  "onSpecial": true,
  "savings": null,
  "unitPrice": 1049.95,
  "unitPriceUnit": "kg",
  "loyaltyPrice": 159.99,
  "loyaltyProgram": "Xtra Savings",
  "loyaltyValidFrom": "2026-09-22T22:00:00Z",
  "loyaltyValidUntil": "2026-10-11T21:59:59Z",
  "promotions": [
    {
      "text": "Now R159.99",
      "type": "fixed_discount",
      "memberOnly": true,
      "promoUnitPrice": 159.99,
      "minQuantity": 1,
      "validFrom": "2026-09-22T22:00:00Z",
      "validUntil": "2026-10-11T21:59:59Z",
      "description": null
    }
  ],
  "inStock": true,
  "stockStatus": "In stock",
  "stockQuantity": 205,
  "category": null,
  "categories": null,
  "imageUrl": "https://catalog.sixty60.co.za/v2/files/6a5afe761c9cd2b4cf594e3a?width=600&height=600",
  "url": "https://www.checkers.co.za/product/jacobs-kronung-freeze-dried-instant-coffee-200g-10164411EA",
  "rating": null,
  "reviewCount": null,
  "seller": "Checkers",
  "deliveryEstimate": "Sixty60 delivery (about 60 minutes)",
  "store": {
    "key": "johannesburg",
    "name": "Johannesburg",
    "storeId": "5e9d72dbb54e17eeda08baf3",
    "fulfilment": "sixty-min-delivery"
  },
  "position": 1,
  "sourceType": "product",
  "sourceValue": "https://www.checkers.co.za/product/jacobs-kronung-freeze-dried-instant-coffee-200g-10164411EA",
  "scrapedAt": "2026-10-04T16:18:13Z",
  "barcodes": ["8711000521045", "5901480000519"],
  "catalogueId": "5d3af63ef434cf8420737f0c",
  "maxPerOrder": 10,
  "description": "Unlock the magical aroma of Jacobs Krönung Freeze Dried Instant Coffee 200g, ...",
  "promotionFlag": false
}
```

- `price` is the shelf price for everyone; `loyaltyPrice` is the best single-item Xtra Savings price, with its dates;
  `promoPrice` is the best single-item promotion open to every shopper. Multi-buys stay in `promotions` with
  `minQuantity` and the price per item they work out to (`promoUnitPrice`).
- `unitPrice` is per kg, per litre or per item (`unitPriceUnit`), worked out from the pack size; for weighed products
  it is the site's price per kg.
- `stockQuantity` is the number the site reports for the serving store; `inStock` is false when the site says the
  product is unavailable there.
- `category` is filled for products found through a category link; search results do not carry a category.
- All prices are in rand, as the site shows them, VAT included.
- The run's key-value store has `RUN-SUMMARY`: products per search term or URL, how many the site reported, errors and
  approximate traffic.

### Use it from code, automations and AI agents

- **API**: run it and get the results in one call: `POST https://api.apify.com/v2/acts/zaiq~checkers-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN` with the input as JSON. The API tab on this page has ready-made Python, JavaScript and cURL examples.
- **Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("zaiq/checkers-scraper").call(run_input={'searchTerms': ['milk', 'coffee'], 'startUrls': [{'url': 'https://www.checkers.co.za/department/bakery/bread-rolls-wraps-and-bagels-2-670437dc7a8738098af92e28'}], 'maxItemsPerSource': 20})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

- **No code**: connect it to Google Sheets, Zapier, Make or n8n from the Integrations tab, schedule runs in Apify Console, and get a webhook when a run finishes.
- **AI agents (MCP)**: add it as a tool to Claude, Cursor or any MCP client through Apify's MCP server: `https://mcp.apify.com?tools=zaiq/checkers-scraper`.

### Pricing

$5.00 per 1,000 products ($0.005 per product row). Apify's platform usage is included.

Each product row is one charged event; a product in several regions is one row per region. Failed, blocked and empty
pages, retries and duplicates are free. Your spending limit is respected: the run stops cleanly before going over it.

### Limits

- Prices, promotions and stock are what the website shows for online orders from the stores serving each region.
  In-store shelf prices can differ.
- Without a region, the site's default store is used (no delivery address).
- Personalised offers that appear only after signing in to an Xtra Savings account are not included; nothing here
  signs in.
- Search results without a category link have no category path; ratings are only present when the site has reviews.
- A promotion page (`/merchandised-page/...`) holds several product lists; use one of its `?plid=` list links.
- Use the data in line with the retailer's terms and South African law. This Actor is not affiliated with or endorsed
  by Shoprite Holdings, Checkers or Shoprite.

### FAQ

**How current are the prices?** Each run reads the site live; `scrapedAt` is the time of reading.

**Why do prices differ between regions?** The site prices and stocks each product per serving store. Pick several
regions to compare them in one run.

**Can I look up a product by barcode?** Yes. Put the EAN-13 in Search terms; the row also lists every barcode the
product carries.

**Does it work for Shoprite?** Yes. Set Store brand to Shoprite; searches, categories, products, regions and Xtra
Savings deals work the same way.

**What happens when the site blocks a request?** It is tried again from another South African home connection. Requests
that still fail are free and are listed in `RUN-SUMMARY`.

# Actor input Schema

## `banner` (type: `string`):

Checkers (checkers.co.za) or Shoprite (shoprite.co.za). Both belong to the Shoprite group and run the same Sixty60 site, with their own prices, specials and Xtra Savings deals. URLs must be from the brand chosen here.

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

Words to search for, as you would type them on the site (for example milk, coffee, nappies). A barcode (EAN-13) also works.

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

Checkers or Shoprite pages: a category (https://www.checkers.co.za/department/...), a product list (.../search?plid=...), a search (.../search?Search=milk) or a product (.../product/...-10392555EA). A bare article number with its unit (10392555EA) works too. For shoprite.co.za links set Store brand to Shoprite.

## `maxItemsPerSource` (type: `integer`):

Stop each search term or category after this many products. A product URL always gives one.

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

Stop the whole run after this many products. 0 means no total limit (each search term or URL still stops at its own maximum, and your spending limit always applies).

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

Return only products the site marks as on promotion (a lower price, a member price or a multi-buy deal).

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

The order the site lists products in. With a product limit, this decides which products you get.

## `regions` (type: `array`):

Prices, stock and ranging follow the stores that deliver to an address, and they differ between regions. Pick one or more cities (the city centre is used as the delivery address); every product is returned once per region. Leave empty for the site's default (no address).

## `customLocations` (type: `array`):

Any other South African delivery location as latitude,longitude, for example -33.5779,18.4967.

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

By default every request goes through South African home (residential) internet connections, as a shopper in South Africa would browse.

## `maxConcurrency` (type: `integer`):

How many requests run at the same time. Kept low to stay polite to the site.

## Actor input object example

```json
{
  "banner": "checkers",
  "searchTerms": [
    "milk",
    "coffee"
  ],
  "startUrls": [
    {
      "url": "https://www.checkers.co.za/department/bakery/bread-rolls-wraps-and-bagels-2-670437dc7a8738098af92e28"
    }
  ],
  "maxItemsPerSource": 20,
  "maxItems": 0,
  "specialsOnly": false,
  "sort": "relevance",
  "regions": [],
  "customLocations": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "ZA"
  },
  "maxConcurrency": 6
}
```

# Actor output Schema

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

Dataset with one row per product.

## `summary` (type: `string`):

Products per search term or URL, results the site reported, errors, requests and approximate traffic.

# 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 = {
    "searchTerms": [
        "milk",
        "coffee"
    ],
    "startUrls": [
        {
            "url": "https://www.checkers.co.za/department/bakery/bread-rolls-wraps-and-bagels-2-670437dc7a8738098af92e28"
        }
    ],
    "maxItemsPerSource": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "ZA"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("zaiq/checkers-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 = {
    "searchTerms": [
        "milk",
        "coffee",
    ],
    "startUrls": [{ "url": "https://www.checkers.co.za/department/bakery/bread-rolls-wraps-and-bagels-2-670437dc7a8738098af92e28" }],
    "maxItemsPerSource": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "ZA",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("zaiq/checkers-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 '{
  "searchTerms": [
    "milk",
    "coffee"
  ],
  "startUrls": [
    {
      "url": "https://www.checkers.co.za/department/bakery/bread-rolls-wraps-and-bagels-2-670437dc7a8738098af92e28"
    }
  ],
  "maxItemsPerSource": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "ZA"
  }
}' |
apify call zaiq/checkers-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zaiq/checkers-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/YZuGfy3lS7X7EFSRJ/builds/Ps7G2oj2xvx0JUl6f/openapi.json
