# Tesco Scraper - UK Prices, GTINs & Clubcard Offers (`s-r/tesco-scraper`) Actor

Collect Tesco UK products by search, category URL or TPNC. Export prices, unit prices, Clubcard promotions, GTINs, availability and optional product details.

- **URL**: https://apify.com/s-r/tesco-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (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 products

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Tesco Scraper — UK Prices, GTINs and Clubcard Offers

Tesco scraper collects Tesco UK products by search term, category URL, product URL or TPNC. Export regular prices, unit prices, Clubcard offers, availability and GTIN barcodes in one dataset.

Use the results for price comparisons, FMCG assortment research, product matching and recurring shelf checks. Every row includes the Tesco product identifier and a retrieval timestamp. GTINs let you join Tesco products to other retailers or food catalogues without relying only on product names. Coverage is the public UK catalogue in GBP; this Actor does not provide Ireland prices or postcode-specific store pricing.

### What the Tesco scraper returns

Each dataset row describes one product in an input group. The row contains its title, brand when published, Tesco TPNC and TPNB, GTIN, image, URL, regular price, unit price, availability and shelf hierarchy. The four hierarchy fields are `super_department`, `department`, `aisle` and `shelf`, so you can compare brands across a department or isolate one shelf without splitting a combined breadcrumb string.

`gtin14` preserves the barcode exactly as Tesco supplies it. `gtin` removes a single leading zero from a 14-digit barcode, making ordinary GTIN-13 joins easier while retaining the original value for audit. Keep these identifiers as strings when exporting to spreadsheets.

The standard price and `clubcard_price` are separate numeric GBP fields. A single-unit offer such as “£1.95 Clubcard Price” becomes `1.95`. Multibuy promotions such as “Any 2 for £4” and meal deals remain in `promotions`; they do not become an invented single-unit loyalty price. Promotion records include their description, attributes, dates and unit-selling information when published. A null Clubcard price means there is no recognised single-unit Clubcard offer, rather than a zero price.

### Input

Provide at least one of `queries`, `urls` or `tpncs`. You can combine them in a run. Search terms are trimmed and duplicate entries removed. URLs must point to Tesco UK search, category or product pages. Legacy `groceries/en-GB` URLs are accepted alongside current `shop/en-GB` URLs. Product identifiers must contain 6 to 10 digits.

URLs preserve the search term and starting page. URL filters, including `facetsArgs`, and URL `sortBy` and `count` parameters are ignored with a warning. Set `sort`, `max_items` and `include_marketplace` in the Actor input to control these options.

This small search uses an input exercised against the saved Tesco search response:

```json
{"queries": ["milk"], "max_items": 2}
```

`max_items` defaults to 100 and accepts 1 to 5,000 products per search term or category. Products are deduplicated by TPNC within each group. The same product can legitimately appear once for each of two different search terms. Positions restart for each group and continue across pages within it.

Set `sort` to `relevance`, `price-ascending` or `price-descending`. Tesco controls the ordering, including sponsored placements, so price ordering may not be strictly monotonic. The `is_sponsored` field identifies source placements where Tesco provides that signal.

### Product details and marketplace options

`include_details` fetches each product page for description, pack size, ingredients, allergens, nutrition, storage and food suitability labels when Tesco publishes them. Product URLs and TPNCs request details automatically. Empty fields remain null or empty lists; an absent ingredient list is not a claim that a food contains no ingredients or allergens.

`details_fetched` records whether the product page was successfully read and matched to the requested product. If an optional detail request fails, the available shelf row remains useful and the run reports a warning. That failed detail phase is not counted as a successful product detail.

Marketplace products are excluded by default. Set `include_marketplace` to true to include them. `is_marketplace` and `seller_id` distinguish third-party products from Tesco sales. A marketplace list row may not include its brand or seller name; request details to retrieve those fields when available. Marketplace delivery options are source information, not a promise of a delivery slot or a basket shipping price.

### Output and exports

Example row from the search above (shortened to the main fields, taken from a real saved result):

```json
{
  "tpnc": "305965589",
  "gtin14": "05060337221085",
  "gtin": "5060337221085",
  "title": "Biotiful Gut Health Kefir Milk Drink Original 1 Litre",
  "brand": "Biotiful",
  "super_department": "Groceries & Essentials",
  "department": "Fresh Food",
  "aisle": "Milk, Butter & Eggs",
  "shelf": "Milk",
  "price": 3.5,
  "unit_price": 3.5,
  "unit_of_measure": "litre",
  "clubcard_price": null,
  "promotions": [],
  "status": "AvailableForSale",
  "availability": "InStock",
  "url": "https://www.tesco.com/shop/en-GB/products/305965589",
  "currency": "GBP",
  "fetched_at": "2026-10-28T21:13:00.000Z"
}
```

The default dataset contains the product rows. Download it as JSON, CSV or Excel, or read it through the Apify API. `source`, `country`, `currency` and `fetched_at` make the result easier to combine with other datasets. The product's `price` is the source selling price; it excludes delivery costs and does not substitute the Clubcard price.

Availability preserves both Tesco's raw `status` and a normalised `availability`: available products become `InStock`, temporarily unavailable products become `OutOfStock`, and excluded products become `Discontinued`. Unknown source statuses remain visible as their original text. Check the retrieval timestamp before using a row for a current purchasing decision.

Larger collections continue automatically. Direct API integrations can pass `next_cursor` back as `cursor` together with the unchanged original input. `partial` and `warnings` explain outstanding work or an unavailable requested phase. A missing TPNC is reported without discarding successfully retrieved products from the same run.

Unavailable products with no published price are skipped with a warning, including direct product requests. Isolated rows with invalid product fields are also skipped. They do not use a result position or incur a product or product-detail event. Collection continues to later pages and input groups; every delivered row retains a numeric price and unit price.

### Use cases

- **Supermarket price comparison:** track Tesco prices and unit prices next to other UK retailers and join them on GTIN.
- **FMCG brand monitoring:** see where your brand sits on the shelf, at what price, and whether Clubcard promotions apply.
- **Assortment and availability checks:** schedule runs over a category URL and watch products go in and out of stock.
- **Product matching:** enrich barcode lists or food catalogues with Tesco titles, pack data and shelf hierarchy.
- **Retail analysis:** export department, aisle and shelf data to a spreadsheet or BI tool.

### Tesco scraper compared with other options

Tesco does not offer a public product API for third parties. Generic supermarket scrapers often return a title and a price only. This Tesco scraper adds the GTIN barcode, the TPNC, a split shelf hierarchy, a numeric Clubcard price kept apart from the regular price, and resumable large collections. Unlike a manual export, it can be scheduled and called through the Apify API.

### Pricing

The intended event model has a run-start event, one product event per delivered row and an additional product-detail event for each delivered row whose product page was successfully read. TPNC and product-URL inputs therefore include the detail phase. The current Apify pricing panel is the authority for event rates; check it before starting a large run.

A search with no results has no product or product-detail events. The run-start event may still apply. Sponsored duplicates removed within an input group are not extra delivered rows. Non-paying accounts receive at most ten dataset rows per run; that delivery limit does not mean the rows are free. Detail counts are recalculated from the rows actually delivered after that limit.

### FAQ

#### Can I search directly by GTIN or EAN?

Tesco's measured search did not resolve numeric GTIN searches. Supply a product title, a category URL or a Tesco TPNC instead. The output GTIN is designed for joining the resulting products to other sources.

#### Does this collect local prices by postcode?

No. This version collects the public Tesco UK catalogue. It accepts no postcode, store identifier, delivery slot or customer account. Do not interpret a returned price as a personalised basket quote.

#### Are Clubcard multibuys converted to a unit price?

No. Multibuys and meal deals retain their full promotion text. Only recognised single-unit Clubcard offers populate the numeric Clubcard-price field, preserving the conditions Tesco publishes.

#### Are third-party sellers included automatically?

No. Enable `include_marketplace` explicitly. Product details can add a published seller name; without them, a marketplace listing may carry only the seller identifier.

# Actor input Schema

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

Search terms. Trimmed and deduplicated. Provide queries, urls or tpncs.

## `urls` (type: `array`):

Tesco UK search, browse/category or product URLs. Both shop/en-GB and legacy groceries/en-GB URLs are accepted. URL query and page are preserved; URL filters (including facetsArgs), sortBy and count are ignored with a warning. Use sort, max_items and include_marketplace to control results.

## `tpncs` (type: `array`):

Numeric Tesco product identifiers (TPNC), each 6 to 10 digits. Product details are fetched automatically.

## `max_items` (type: `integer`):

Maximum unique products per search term or category, across all pages and cursor continuations.

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

Sorting requested from Tesco. The source may place sponsored products separately.

## `include_marketplace` (type: `boolean`):

Include third-party marketplace products. Disabled by default. Marketplace seller names require product details.

## `include_details` (type: `boolean`):

Fetch each product page for description, pack size, ingredients, allergens, nutrition and seller information when published. Details are an additional billable phase.

## `cursor` (type: `string`):

Opaque continuation token. Send the original input unchanged plus next_cursor. The Apify Actor follows it automatically.

## Actor input object example

```json
{
  "queries": [
    "milk"
  ],
  "max_items": 100,
  "sort": "relevance",
  "include_marketplace": false,
  "include_details": false
}
```

# Actor output Schema

## `results` (type: `string`):

One row per delivered Tesco product.

## `output` (type: `string`):

Counts, warnings and completion status.

# 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": [
        "milk"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/tesco-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": ["milk"] }

# Run the Actor and wait for it to finish
run = client.actor("s-r/tesco-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 '{
  "queries": [
    "milk"
  ]
}' |
apify call s-r/tesco-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/tesco-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/Z9dotF2gOWRONP3QX/builds/gca4AzZa1rZwP8W0Z/openapi.json
