# UK Grocery Prices: Tesco, Sainsbury's, Asda, Aldi (`parsebird/uk-grocery-price-scraper`) Actor

Compare UK supermarket prices from Tesco, Sainsbury's, Asda, Aldi and Morrisons in one dataset.

- **URL**: https://apify.com/parsebird/uk-grocery-price-scraper.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Security:** Limited permissions
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.39 / 1,000 products

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

### UK Grocery Prices: Tesco, Sainsbury's, Asda, Aldi

UK Grocery Prices compares supermarket prices from **Tesco, Sainsbury's, Asda, Aldi and Morrisons** in one dataset. Every product comes back in the same format: price, was-price, loyalty card price, unit price, offer text and end date, pack size, stock, category, rating, and a match key for lining up the same product across shops.

<table><tr>
<td style="border-left:4px solid #1C1917;padding:12px 16px;font-weight:600">
Search five UK supermarkets at once, read whole categories or whole shops, or price a shopping list at every shop and get the cheapest basket. Clubcard, Nectar and More Card prices come back as their own field, separate from the shelf price.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```text
Apify Actor parsebird/uk-grocery-price-scraper compares UK supermarket prices from Tesco, Sainsbury's, Asda, Aldi and Morrisons in one row format. Call it with the apify-client package: client.actor("parsebird/uk-grocery-price-scraper").call(run_input={"mode": "search", "retailers": ["tesco", "sainsburys", "asda", "aldi", "morrisons"], "queries": ["semi skimmed milk"], "maxItems": 50}). Inputs: mode ("search" default, "category", "product", "catalogue", "basket"), retailers (array of "tesco","sainsburys","asda","aldi","morrisons"; default ["aldi","sainsburys"]; used in search, catalogue and basket mode), queries (array, max 50, default ["milk"]), categoryUrls (array, max 250, shop taken from each URL), productUrls (array, max 500), maxItems (int, default 100, 0 = no limit, split equally between shops), includeDetails (bool, adds ingredients and nutrition), priceHistory (bool, keeps weekly prices in a key-value store named uk-grocery-price-history and adds priceHistory once 2+ weeks exist), basket (array of lines like "2 x semi skimmed milk"), basketPricing ("live" or "snapshot"), basketPick ("cheapest" or "relevance"), useLoyaltyPrices (bool), asdaStoreId (string), outputDataset (named dataset to append rows to), datasetName (rename this run's dataset; placeholders {isoWeek}, {date}, {retailer}). Output: one dataset item per product with retailer, retailerProductId, ean[], matchKey, name, brand, packSize, price, wasPrice, unitPrice {value, measure}, loyaltyPrice, promotionText, promotionEndsAt, inStock, categoryPath[], url, imageUrl, rating {value, count}, scrapedAt, plus query/position or categoryUrl, and ingredients/nutrition/priceHistory when requested. Basket mode saves one row per basket line per shop (type "basketLine") and the totals plus cheapestRetailer in the key-value store record OUTPUT. Prices are in GBP. API docs: https://apify.com/parsebird/uk-grocery-price-scraper/api. Get a token: https://console.apify.com/settings/integrations
```

### What is UK Grocery Prices?

**UK Grocery Prices** is a **UK supermarket price comparison scraper** for [Tesco](https://www.tesco.com/groceries/), [Sainsbury's](https://www.sainsburys.co.uk/gol-ui/groceries), [Asda](https://www.asda.com/groceries), [Aldi](https://www.aldi.co.uk/) and [Morrisons](https://groceries.morrisons.com/). It reads the product data each supermarket shows on its own website and returns all five shops in **one row format**, so a Tesco row and an Asda row have the same fields and can sit in the same spreadsheet. It works as a **UK grocery price API** alternative: you send search terms, category links, product links or a shopping list, and you get clean JSON back.

The easiest way to try it: open the **Input** tab, keep the prefilled search `semi skimmed milk` with all five shops, and click **Start**. You get 20 products, 4 from each shop, in about 5 seconds.

### What can UK Grocery Prices do?

- 🔍 **Search five supermarkets at once**: each search term runs in every shop you pick, and every row keeps its `query` and `position`.
- 🗂️ **Read category pages**: paste category links from any of the five shops; the Actor works out the shop from each link.
- 🏬 **Read whole shops**: Catalogue mode walks every grocery category of Tesco, Asda, Aldi or Morrisons.
- 🔗 **Refresh known products**: paste product links to re-price a fixed list, for example the products you track.
- 🛒 **Price a shopping list**: Basket mode matches each item in every shop, adds up the totals, and names the cheapest complete basket.
- 💷 **Get every price**: the shelf price, the was-price, the Clubcard, Nectar or More Card price, the unit price, and the offer text with its end date.
- 🥗 **Add ingredients and nutrition**: one switch adds the ingredients list and the nutrition table.
- 📈 **Keep weekly price history**: the Actor can store this week's prices in your account and add a `priceHistory` list once a product has two or more weeks.

On the Apify platform you also get [scheduled runs](https://docs.apify.com/platform/schedules), a full [REST API](https://docs.apify.com/api/v2), [integrations](https://apify.com/integrations) with Make, Zapier, n8n, Google Sheets, Slack, and webhooks, and export to JSON, CSV, Excel, XML, or HTML.

### What data can you extract from UK supermarkets?

| Field | Description |
|-------|-------------|
| `retailer` | `tesco`, `sainsburys`, `asda`, `aldi` or `morrisons` |
| `retailerProductId` | The shop's own product ID |
| `name` / `brand` | Product name and brand. Own-label products carry the shop's name as brand |
| `packSize` | Pack size, for example `2.272L`, `4x415g`, `2 pints` |
| `price` | The price you pay without a loyalty card, in GBP |
| `wasPrice` | The earlier price when the shop shows one (Rollback, "Was £", price drops) |
| `loyaltyPrice` | Tesco Clubcard, Sainsbury's Nectar or Morrisons More Card price |
| `unitPrice` | `{value, measure}`, for example `{"value": 1.06, "measure": "l"}` |
| `promotionText` / `promotionEndsAt` | Offer text, such as "Rollback", "Buy 3 for £10" or "£1.40 Clubcard Price", and the offer's end date when the shop gives one |
| `inStock` | Whether the product can be ordered now |
| `categoryPath` | Where the product sits in the shop, for example `["Chilled Food", "Milk, Butter, Cream & Eggs", "Fresh Milk"]` |
| `ean` | EAN barcodes (Tesco and Sainsbury's) |
| `rating` | `{value, count}` average rating and number of reviews |
| `matchKey` | Lower-case name plus the pack size in g or ml, for lining up the same product across shops |
| `url` / `imageUrl` | Product page and the largest product image |
| `ingredients` / `nutrition` | With **Include ingredients and nutrition** on: ingredients text and rows of `{nutrient, per100, perServing}` |
| `priceHistory` | With **Keep weekly price history** on: `[{week, price, loyaltyPrice}]` once two or more weeks exist |

### How to compare UK supermarket prices

1. Open [UK Grocery Prices](https://apify.com/parsebird/uk-grocery-price-scraper) and click **Try for free**.
2. Pick a **Mode**: Search, Category URLs, Product URLs, Catalogue or Basket.
3. Pick the **Shops**, and add your search terms, links or shopping list.
4. Set **Max items**. It is shared equally between the shops, so 100 items across five shops gives up to 20 from each.
5. Turn on **Include ingredients and nutrition** or **Keep weekly price history** if you need them.
6. Click **Start**, then download the results from the **Output** tab as JSON, CSV, Excel, XML, or HTML, or fetch them through the API.

To track prices every week, add the run to a [schedule](https://docs.apify.com/platform/schedules) with **Keep weekly price history** on, and optionally set **Name this run's dataset** to `snapshot-{retailer}-{isoWeek}` so each week's dataset is kept under its own name.

### Input examples

Search all five shops:

```json
{
    "mode": "search",
    "retailers": ["tesco", "sainsburys", "asda", "aldi", "morrisons"],
    "queries": ["semi skimmed milk", "baked beans"],
    "maxItems": 100
}
```

Read category pages (the shop comes from each link):

```json
{
    "mode": "category",
    "categoryUrls": [
        "https://www.tesco.com/shop/en-GB/browse/groceries-and-essentials/fresh-food/milk-butter-and-eggs/milk/all",
        "https://www.asda.com/groceries/food-cupboard/cereals-cereal-bars",
        "https://www.aldi.co.uk/products/chilled-food/milk/k/1588161416978051001",
        "https://groceries.morrisons.com/categories/fresh-foods/milk/177268",
        "https://www.sainsburys.co.uk/gol-ui/groceries/food-cupboard/canned-and-tinned-food/pulses-and-beans/c:1019516"
    ],
    "maxItems": 500
}
```

Price a shopping list and find the cheapest shop:

```json
{
    "mode": "basket",
    "retailers": ["tesco", "sainsburys", "asda", "aldi", "morrisons"],
    "basket": ["2 x semi skimmed milk", "baked beans", "6 free range eggs", "sourdough bread", "bananas", "cheddar"],
    "useLoyaltyPrices": true
}
```

All input parameters:

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| mode | string | `search` | `search`, `category`, `product`, `catalogue` or `basket` |
| retailers | array | `["aldi", "sainsburys"]` | Shops for search, catalogue and basket mode |
| queries | array | `["milk"]` | Search terms, up to 50 |
| categoryUrls | array | — | Category links from any of the five shops, up to 250 |
| productUrls | array | — | Product links from any of the five shops, up to 500 |
| maxItems | integer | `100` | Most product rows to save, split equally between shops. `0` = no limit |
| includeDetails | boolean | `false` | Add ingredients and the nutrition table |
| priceHistory | boolean | `false` | Store weekly prices and add `priceHistory` once 2+ weeks exist |
| basket | array | — | Shopping list, one item per line, optional `2 x` quantity |
| basketPricing | string | `live` | `live` searches now; `snapshot` uses the latest weekly prices your runs saved |
| basketPick | string | `cheapest` | `cheapest` (lowest unit price) or `relevance` (the shop's top match) |
| useLoyaltyPrices | boolean | `false` | Use Clubcard, Nectar and More Card prices in basket totals |
| asdaStoreId | string | — | Asda store number for the in-stock flag |
| outputDataset | string | — | Also append every row to this named dataset |
| datasetName | string | — | Name this run's dataset; placeholders `{isoWeek}`, `{date}`, `{retailer}` |
| proxyConfiguration | object | no proxy | Optional. The Actor switches to Apify Proxy by itself if a shop refuses direct requests |

### Output example

```json
[
    {
        "retailer": "tesco",
        "retailerProductId": "254656543",
        "ean": ["05000436589457"],
        "matchKey": "tesco british semi skimmed milk 2.272l 4 pints 2272ml",
        "name": "Tesco British Semi Skimmed Milk 2.272L, 4 Pints",
        "brand": "TESCO",
        "packSize": "2.272L",
        "price": 1.75,
        "wasPrice": null,
        "unitPrice": { "value": 0.77, "measure": "l" },
        "loyaltyPrice": null,
        "promotionText": null,
        "promotionEndsAt": null,
        "inStock": true,
        "categoryPath": ["Groceries & Essentials", "Fresh Food", "Milk, Butter & Eggs", "Milk"],
        "url": "https://www.tesco.com/groceries/en-GB/products/254656543",
        "imageUrl": "https://digitalcontent.api.tesco.com/v2/media/ghs/07531d6d-8bf2-41b5-a5ad-e2ae0a71f2b3/17233543-2c5b-4a06-a0ab-cfdbddcd488e_2028878860.jpeg",
        "rating": { "value": 4, "count": 710 },
        "query": "semi skimmed milk",
        "position": 1,
        "scrapedAt": "2026-11-03T23:22:48Z"
    },
    {
        "retailer": "asda",
        "retailerProductId": "2041527",
        "ean": [],
        "matchKey": "cravendale arla filtered fresh semi skimmed milk 1l fresher for longer 1000ml",
        "name": "Cravendale Arla Filtered Fresh Semi Skimmed Milk 1L Fresher for Longer",
        "brand": "Cravendale",
        "packSize": "1L",
        "price": 1.4,
        "wasPrice": 1.64,
        "unitPrice": { "value": 1.4, "measure": "l" },
        "loyaltyPrice": null,
        "promotionText": "Rollback",
        "promotionEndsAt": null,
        "inStock": true,
        "categoryPath": ["Chilled Food", "Milk, Butter, Cream & Eggs", "Fresh Milk", "Semi Skimmed Milk"],
        "url": "https://www.asda.com/groceries/product/semi-skimmed-milk/cravendale-arla-filtered-fresh-semi-skimmed-milk-1l-fresher-for-longer/2041527",
        "imageUrl": "https://asdagroceries.scene7.com/is/image/asdagroceries/5000181024029",
        "rating": { "value": 4.68, "count": 296 },
        "query": "semi skimmed milk",
        "position": 2,
        "scrapedAt": "2026-11-03T23:22:48Z"
    }
]
```

In Basket mode each shop's line is saved as a row with `type: "basketLine"`, and the key-value store record `OUTPUT` holds every shop's total, the matched and missing lines, and `cheapestRetailer`.

### Basket API (Standby)

The Actor also runs as an always-on HTTP endpoint through [Apify Standby](https://docs.apify.com/platform/actors/running/standby). Send a shopping list and get the totals back in the same request, without starting a run:

```bash
curl -X POST "https://parsebird--uk-grocery-price-scraper.apify.actor/basket" \
  -H "Authorization: Bearer <YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"items": ["2 x semi skimmed milk", "baked beans"], "retailers": ["tesco", "asda", "aldi"], "pricing": "live"}'
```

The body takes `items` (strings or `{query, quantity}`), `retailers`, `pricing` (`live` or `snapshot`), `pick` (`cheapest` or `relevance`) and `useLoyaltyPrices`. Each matched line at each shop is charged as a basket line.

### How much does it cost to compare UK grocery prices?

UK Grocery Prices uses pay-per-event pricing. You pay for what is saved; compute and proxy traffic are included in the event prices and not billed separately.

| Event | When it is charged | Free | Bronze | Silver | Gold |
|-------|--------------------|------|--------|--------|------|
| Product | One product row saved | $1.99 / 1,000 | $1.79 / 1,000 | $1.59 / 1,000 | $1.39 / 1,000 |
| Product details | A product row that carries ingredients or a nutrition table, on top of Product | $4.99 / 1,000 | $4.49 / 1,000 | $3.99 / 1,000 | $3.49 / 1,000 |
| Price history | A `priceHistory` list added to a row (only when two or more weekly prices exist) | $3.99 / 1,000 | $3.79 / 1,000 | $3.59 / 1,000 | $3.39 / 1,000 |
| Basket line (live) | One matched basket line at one shop, priced live | $1.99 / 1,000 | $1.79 / 1,000 | $1.59 / 1,000 | $1.59 / 1,000 |
| Basket line (snapshot) | One matched basket line at one shop, priced from the weekly snapshot | $1.99 / 1,000 | $1.79 / 1,000 | $1.59 / 1,000 | $1.59 / 1,000 |

A small platform **Actor start** fee also applies per run. Examples on the Free plan:

- 100 products from a search: about **$0.20**.
- 100 products with ingredients and nutrition, all with details found: about **$0.70**.
- A 20-item shopping list priced at all five shops (100 matched lines): about **$0.20**.

Items a shop doesn't match are not charged. Apify's free plan includes monthly platform credit you can use for this Actor.

### Python and JavaScript API examples

Python ([apify-client](https://docs.apify.com/api/client/python)):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("parsebird/uk-grocery-price-scraper").call(run_input={
    "mode": "search",
    "retailers": ["tesco", "sainsburys", "asda", "aldi", "morrisons"],
    "queries": ["semi skimmed milk"],
    "maxItems": 50,
})
for p in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(p["retailer"], "|", p["name"], "|", p["price"], "|", p.get("loyaltyPrice"), "|", p.get("unitPrice"))
```

JavaScript ([apify-client](https://docs.apify.com/api/client/js)):

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('parsebird/uk-grocery-price-scraper').call({
    mode: 'basket',
    retailers: ['tesco', 'sainsburys', 'asda', 'aldi', 'morrisons'],
    basket: ['2 x semi skimmed milk', 'baked beans', '6 free range eggs'],
});
const output = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('OUTPUT');
console.log(output.value.cheapestRetailer, output.value.totals);
```

Find all endpoints on the [API tab](https://apify.com/parsebird/uk-grocery-price-scraper/api).

### FAQ

**Which shop data is available for each supermarket?**
All five shops return price, was-price where shown, unit price, offer text, pack size, category and image. Tesco and Sainsbury's also return EAN barcodes. Tesco, Sainsbury's and Morrisons return loyalty card prices (Clubcard, Nectar, More Card). Aldi's UK site marks its products as not sold online and shows no ratings or barcodes, so Aldi rows have `inStock`, `rating` and `ean` empty.

**Why are Asda ingredients and nutrition empty?**
Asda serves ingredients and nutrition only on its product pages, and those pages refuse requests from Apify's servers. Asda prices, offers, stock, ratings and categories come from Asda's product search and work normally. Asda rows without details are not charged the Product details event.

**What is the difference between price, wasPrice and loyaltyPrice?**
`price` is what you pay without a loyalty card. `wasPrice` is the earlier price the shop shows next to an offer, such as an Asda Rollback or a Morrisons "Was £3.90". `loyaltyPrice` is the Clubcard, Nectar or More Card price. Morrisons gives the regular price and the offer as text ("Now £3, Was £3.90", "Half price"), and the Actor works out the price you pay from that text.

**How does Basket mode pick a product for each item?**
A product counts as a match only if its name contains every word of the item (plural forms count, and "6" matches "6 pack" or "x6"). With **Cheapest by unit price**, the Actor stays on the shelf of the shop's own best match and takes the lowest unit price there, so "bananas" is not matched with banana yogurt. With **Top search result**, it takes the shop's first match. A shop missing any item is not counted as the cheapest complete basket.

**How does price history work?**
With **Keep weekly price history** on, each product's price for the current ISO week is stored in a key-value store named `uk-grocery-price-history` in your Apify account. A product gets a `priceHistory` list once it has prices from two or more weeks, so the history starts filling up from your second weekly run. Up to 104 weeks are kept per product.

**How many products can I get?**
Search and category results go as deep as each shop's own results. In our tests, Catalogue mode returned the whole Asda grocery range, 34,373 products, in about 25 minutes, and 3,000 Morrisons products in about 2 minutes. Asda's catalogue leaves out its Home & Entertainment (George) range. Asda's search returns at most 1,000 results per query, so large Asda categories are read through their sub-categories. Products Asda hides from its online shop are left out, as on asda.com.

**Are prices the same in every store?**
The Actor returns the online grocery prices each shop's website shows. Asda prices come from its online price list for England. Prices in physical stores can differ.

**Can I schedule the scraper and connect it to other tools?**
Yes. Use [Apify schedules](https://docs.apify.com/platform/schedules) to run it daily or weekly, and connect the results to Google Sheets, Slack, Make, Zapier, n8n, or your own system through [integrations](https://apify.com/integrations), webhooks, or the API.

**Something does not work or a field is missing.**
Open an issue on the **Issues** tab with your input and run ID, and we will look into it.

### Is it legal to scrape UK supermarket prices?

The Actor collects only public product and price information that the supermarkets show to every visitor of their websites. It does not collect personal data. Check that your use of the data complies with each shop's terms and the laws that apply to you. For more background, read Apify's article [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/) and consult a lawyer if you are unsure about your use case.

### Other grocery and retail scrapers from ParseBird

| Actor | What it scrapes |
|-------|-----------------|
| [Tesco UK & Ireland Scraper](https://apify.com/parsebird/tesco-scraper) | Tesco.com and Tesco.ie products, Clubcard prices, nutrition, and reviews |
| [Sainsbury's UK Grocery Scraper](https://apify.com/parsebird/sainsburys-scraper) | Sainsbury's products with Nectar prices, offers and descriptions |
| [Lidl Scraper](https://apify.com/parsebird/lidl-scraper) | Lidl online shop products across European countries |
| [ALDI Australia Scraper](https://apify.com/parsebird/aldi-australia-scraper) | ALDI Australia products and prices |
| [Carrefour MAF Scraper](https://apify.com/parsebird/carrefour-maf-scraper) | Carrefour products in the Middle East |
| [Walmart Product Scraper](https://apify.com/parsebird/walmart-product-scraper) | Walmart product data |

# Changelog

This Actor's version history is a separate document: https://apify.com/parsebird/uk-grocery-price-scraper/changelog.md

# Actor input Schema

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

What the run does. Search: look up each query in the selected shops. Category / Product: read the URLs you paste (the shop comes from each URL). Catalogue: read whole shops (every grocery category). Basket: price a shopping list at each shop and find the cheapest.

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

Shops to run in Search, Catalogue and Basket mode. Default is Aldi and Sainsbury's. Category and Product mode ignore this and use the shop of each URL.

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

Search mode: words to search for, such as semi skimmed milk. Each query runs in every selected shop. Up to 50 queries.

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

Category mode: category page links from tesco.com, sainsburys.co.uk (ending in /c:<number>), asda.com (/groceries/<category>/...), aldi.co.uk (containing /k/<number>) or groceries.morrisons.com. Up to 250 URLs.

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

Product mode: product page links from tesco.com, sainsburys.co.uk, asda.com, aldi.co.uk or groceries.morrisons.com. Up to 500 URLs.

## `basket` (type: `array`):

Basket mode: one item per line, with an optional quantity like '2 x semi skimmed milk'. Each item is matched in every selected shop and the run reports each shop's total and the cheapest shop.

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

The most product rows the run saves; every row is charged, so start small. 0 means no limit. The limit is split equally between the shops that run, so 100 across five shops gives up to 20 each. Not used in Basket mode.

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

Add ingredients and the nutrition table to each product (one extra request per product). Rows that get ingredients or nutrition are charged the Product details event on top of the product.

## `priceHistory` (type: `boolean`):

Save this week's price of every product to a key-value store named 'uk-grocery-price-history' in your Apify account. Once a product has prices from two or more weeks, its row gets a priceHistory list (charged as Price history). The history fills up as you run the Actor in later weeks, for example on a weekly schedule.

## `basketPricing` (type: `string`):

Basket mode: Live searches each shop now. Snapshot uses the latest weekly prices saved by your runs with 'Keep weekly price history' and falls back to live for items not in the snapshot.

## `basketPick` (type: `string`):

Which product stands in for each item. Cheapest: the lowest unit price among results containing every word of the item. Top result: the shop's first result containing every word.

## `useLoyaltyPrices` (type: `boolean`):

Basket mode: use Clubcard, Nectar and More Card prices where a product has one.

## `asdaStoreId` (type: `string`):

Optional. Asda store number used for the in-stock flag. With a store ID, products that store does not sell are left out. Empty uses the store asda.com shows before a postcode is entered (4565). Prices come from Asda's online price list for England either way.

## `outputDataset` (type: `string`):

Optional. Name of a dataset in your account that also receives every row the run saves, created on first use, so repeated runs add up in one place. Letters, digits and hyphens only, e.g. my-uk-grocery-prices.

## `datasetName` (type: `string`):

Optional. Names this run's dataset when the run finishes, so it is kept until you delete it. Placeholders: {isoWeek} (2026-W45), {date} (2026-11-03) and {retailer} (the shop, or multi). Letters, digits and hyphens only, e.g. snapshot-{retailer}-{isoWeek}.

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

Not needed in most cases. The Actor switches to Apify Proxy by itself if a shop refuses direct requests.

## Actor input object example

```json
{
  "mode": "search",
  "retailers": [
    "tesco",
    "sainsburys",
    "asda",
    "aldi",
    "morrisons"
  ],
  "queries": [
    "semi skimmed milk"
  ],
  "categoryUrls": [
    "https://www.asda.com/groceries/food-cupboard/cereals-cereal-bars"
  ],
  "basket": [
    "2 x semi skimmed milk",
    "baked beans",
    "6 free range eggs"
  ],
  "maxItems": 20,
  "includeDetails": false,
  "priceHistory": false,
  "basketPricing": "live",
  "basketPick": "cheapest",
  "useLoyaltyPrices": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `basket` (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 = {
    "retailers": [
        "tesco",
        "sainsburys",
        "asda",
        "aldi",
        "morrisons"
    ],
    "queries": [
        "semi skimmed milk"
    ],
    "categoryUrls": [
        "https://www.asda.com/groceries/food-cupboard/cereals-cereal-bars"
    ],
    "basket": [
        "2 x semi skimmed milk",
        "baked beans",
        "6 free range eggs"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/uk-grocery-price-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 = {
    "retailers": [
        "tesco",
        "sainsburys",
        "asda",
        "aldi",
        "morrisons",
    ],
    "queries": ["semi skimmed milk"],
    "categoryUrls": ["https://www.asda.com/groceries/food-cupboard/cereals-cereal-bars"],
    "basket": [
        "2 x semi skimmed milk",
        "baked beans",
        "6 free range eggs",
    ],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/uk-grocery-price-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 '{
  "retailers": [
    "tesco",
    "sainsburys",
    "asda",
    "aldi",
    "morrisons"
  ],
  "queries": [
    "semi skimmed milk"
  ],
  "categoryUrls": [
    "https://www.asda.com/groceries/food-cupboard/cereals-cereal-bars"
  ],
  "basket": [
    "2 x semi skimmed milk",
    "baked beans",
    "6 free range eggs"
  ],
  "maxItems": 20
}' |
apify call parsebird/uk-grocery-price-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parsebird/uk-grocery-price-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/vIOM3RLKfe70edjeK/builds/E5arFC7izSUTGV3d8/openapi.json
