# Currys UK Scraper - Products, Prices, Stock & Reviews (`abotapi/currys-co-uk`) Actor

Scrape Currys UK electronics by keyword or URL. Extract prices, brands, stock status, EANs, descriptions, full image galleries and customer reviews. Supports automatic forward pagination for efficient catalogue scraping.

- **URL**: https://apify.com/abotapi/currys-co-uk.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 product results

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

## Currys UK Scraper: products, prices, and reviews

Scrape currys.co.uk electronics listings with price, brand, stock state, EAN, full photo gallery, description, and customer reviews. Search by keyword or paste category and search URLs, with automatic forward pagination.

### Why This Scraper?

- **Two ways in.** Keyword search, or paste search and category URLs directly.
- **Rich product data.** Brand, current price, stock state, EAN/GTIN, category path, and the full high-resolution photo gallery.
- **Customer reviews included.** Pull each product's own customer reviews, rating, text, author, and date, as a separate toggle.
- **Client-side filters.** Narrow by price range and in-stock status without extra requests.
- **Multi-category coverage.** TVs, laptops, mobiles, appliances, and every other category the site carries, all through one actor.
- **Predictable output caps.** One clear limit on total products per run, with pagination following automatically.

### Use Cases

- **Price monitoring:** track current and historical prices across electronics categories for competitive analysis.
- **Market research:** compare brand and category coverage across a major UK electronics retailer.
- **Review analysis:** collect customer ratings and review text to gauge product sentiment.
- **Stock tracking:** monitor which products are in stock versus out of stock over time.
- **Catalog enrichment:** pull structured product data (EAN, brand, category) to enrich an existing product database.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live record.

| Field | Example |
|---|---|
| `id` | `"10000001"` |
| `sku` | `"000001"` |
| `url` | `"https://www.currys.co.uk/products/sample-product-0000000-10000001.html"` |
| `title` | `"Sample Brand 40\" Smart Full HD HDR LED TV"` |
| `brand` | `"SAMPLE BRAND"` |
| `price` | `199.99` |
| `currency` | `"GBP"` |
| `availabilityStatus` | `"InStock"` |
| `categories` | `["TV & Audio", "Televisions", "TVs"]` |
| `ean` | `"0000000000000"` |
| `rating` | `4.6` |
| `reviewCount` | `29` |
| `description` | `"Sample product description text appears here when details are fetched."` |
| `images` | `["https://media.currys.biz/i/currysprod/00000000?$l-large$"]` |
| `priceValidUntil` | `"2026-12-31"` |

When "Fetch customer reviews" is on, each product also carries a `reviews` array (one entry per review: `rating`, `review`, `author`, `authorLocation`, `date`).

### How to Use

1. Pick a mode: **Search** to type keywords, or **URL** to paste currys.co.uk search/category links.
2. Fill in the matching fields (keywords, or URLs).
3. Set **Max total products** to control run size and cost; adjust **Max pages** if needed.
4. Run the actor, then view or export results from the Dataset tab.

**Search by keyword:**

```json
{
  "mode": "search",
  "queries": ["tv", "laptop"],
  "maxListings": 40,
  "fetchDetails": true
}
```

**Search with price and stock filters:**

```json
{
  "mode": "search",
  "queries": ["washing machine"],
  "minPrice": 200,
  "maxPrice": 600,
  "inStockOnly": true,
  "maxListings": 20
}
```

**URL mode with reviews:**

```json
{
  "mode": "url",
  "urls": ["https://www.currys.co.uk/search?q=headphones"],
  "fetchDetails": true,
  "fetchReviews": true,
  "maxReviewsPerProduct": 10,
  "maxListings": 10
}
```

#### Run it from your code

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("abotapi/currys-co-uk").call(run_input={
    "mode": "search",
    "queries": ["tv"],
    "maxListings": 20,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('abotapi/currys-co-uk').call({
    mode: 'search',
    queries: ['tv'],
    maxListings: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

You can also trigger runs and pipe results into Make, Zapier, n8n, Google Sheets, or a webhook from the actor's Integrations tab.

**Tips:**

- **Max total products** is the one cap that matters; **Max pages** defaults wide open so it never silently cuts you off before the cap is reached.
- Reviews are fetched per product only when "Fetch customer reviews" is on, since each product costs an extra request.
- For a daily or weekly schedule, turn on **Incremental changes for scheduled runs** instead of re-paying for the same products every time.

#### Resume and recurring updates

Two different features for two different needs:

- **Resume from a previous run**: paste a run ID or dataset ID to continue a large, interrupted walk across separate runs. Products already saved there are skipped, so you only pay for the new ones.
- **Incremental changes for scheduled runs**: turn this on when you run the *same* search on a schedule (daily, weekly). The first run returns everything as `NEW`. Every later run returns only `NEW`, `UPDATED`, and `REAPPEARED` products by default, each tagged with a `changeType` and (for `UPDATED`) a `changedFields` list. Turn on "Emit unchanged products" or "Emit expired products" if you also want those rows (both are billed, since they're still rows you receive). Minor fields that change on their own (review count, rating, the rolling price-valid-until date, the review list itself) are excluded from change detection by default, so a product isn't flagged `UPDATED` just because one more review came in.

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

Optionally pipe results straight into Notion, Linear, Airtable, or another MCP-compatible app as the run finishes. Authorize a connector once under Apify, Settings, Integrations, then select it in the "Export to your apps" section of the input. For Notion, also set the parent page. The connector receives a condensed, human-readable summary per item (title, price, availability, a few key fields), not the full JSON; the complete record always stays in the dataset. Leave this empty to skip it entirely; it never changes the dataset output either way.

### Input Parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `mode` | String | `search` | `search` to use keywords, `url` to paste links. |
| `queries` | Array | `["tv"]` | Keywords to search for (Search mode). |
| `minPrice` | Integer | - | Only keep products at or above this price. |
| `maxPrice` | Integer | - | Only keep products at or below this price. |
| `inStockOnly` | Boolean | `false` | Only keep in-stock products. |
| `sortBy` | String | `Relevance` | `Relevance`, `PriceAsc`, or `PriceDesc`. |
| `urls` | Array | - | currys.co.uk search/category URLs (URL mode). |
| `fetchDetails` | Boolean | `true` | Visit each product's detail page for description, EAN, and full photo gallery. |
| `fetchReviews` | Boolean | `false` | Fetch each product's customer reviews. |
| `maxReviewsPerProduct` | Integer | `20` | Cap on reviews fetched per product. |
| `maxPages` | Integer | `500` | Max result pages to walk per search/URL. |
| `maxListings` | Integer | `20` | Hard cap on total products for the run. `0` = unlimited. |
| `resumeFromRunId` | String | - | A previous run ID or dataset ID to continue a large walk across separate runs. |
| `incrementalMode` | Boolean | `false` | Turn on for recurring runs of the same search; only returns what changed. |
| `stateKey` | String | - | Optional name for the incremental-mode monitoring campaign. |
| `emitUnchanged` | Boolean | `false` | Also return unchanged products (incremental mode). |
| `emitExpired` | Boolean | `false` | Also return products no longer found (incremental mode). |
| `ignoreFieldsForChanges` | Array | - | Extra field names to exclude from change detection (incremental mode). |
| `proxy` | Object | Residential, GB | Connection settings; the actor manages its own connection tiers internally. |
| `mcpConnectors` | Array | - | MCP connector IDs to export results to (optional). |
| `notionParentPageUrl` | String | - | Notion parent page for the Notion connector. |
| `maxNotifyListings` | Integer | `50` | Cap on items exported per connector. |

### Output Example

> Sample shape: values are illustrative placeholders, not from a live record.

```json
{
  "id": "10000001",
  "sku": "000001",
  "url": "https://www.currys.co.uk/products/sample-product-0000000-10000001.html",
  "title": "Sample Brand 40\" Smart Full HD HDR LED TV",
  "brand": "SAMPLE BRAND",
  "price": 199.99,
  "currency": "GBP",
  "availabilityStatus": "InStock",
  "categories": ["TV & Audio", "Televisions", "TVs"],
  "ean": "0000000000000",
  "rating": 4.6,
  "reviewCount": 29,
  "description": "Sample product description text appears here when details are fetched.",
  "images": ["https://media.currys.biz/i/currysprod/00000000?$l-large$"],
  "priceValidUntil": "2026-12-31",
  "reviews": [
    {
      "rating": 5,
      "review": "Sample review text goes here.",
      "author": "Sample Author",
      "authorLocation": "GBR",
      "date": "2026-01-01T00:00:00.000Z"
    }
  ]
}
```

### Plan Requirement

This actor runs on any Apify plan. Results and run time scale with how many products you request.

### FAQ

#### How much does it cost?

You pay per result; check the Pricing tab on this actor's Store page for the current rate. Use **Max total products** to control run size and cost.

#### Is it legal to scrape currys.co.uk?

This actor collects publicly available data. You are responsible for using the output in line with currys.co.uk's terms, applicable privacy law (such as GDPR or CCPA), and any other regulations that apply to your use case. Avoid collecting personal data unless you have a lawful basis to do so.

#### Why did a run return fewer results than I expected?

Some searches return fewer than **Max total products** if the search itself has fewer matching products, or if your price/stock filters removed some results after fetching. Try widening the filters or raising **Max pages**.

#### Can I get only new or changed products on a schedule?

Yes. Turn on **Incremental changes for scheduled runs** and schedule the actor (e.g. daily). The first run returns everything as `NEW`; every later run returns only `NEW`, `UPDATED`, and `REAPPEARED` products by default, so you're not billed again for products that haven't changed.

#### Why did my run fail instead of returning an empty dataset?

A failed run usually means the upstream site rejected the connection for that attempt. Run again shortly; most failures are transient.

#### Can I use it with AI agents or MCP?

Yes. You can call this actor from any MCP-compatible client or agent framework via the Apify API, as shown in "Run it from your code" above.

### 🔗 Want more electronics data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>🔌 <a href="https://apify.com/abotapi/appliancesonline-com-au-scraper"><b>Appliances Online Scraper</b></a><br>Scrape appliancesonline.com.au by category, keyword, or URL. Extract title, brand, AUD...</td><td>🏷️ <a href="https://apify.com/abotapi/avito-ru-scraper"><b>Avito.ru Scraper</b></a><br>From $1/1K. Scrape structured listings from Avito.ru by region, category, filters, or...</td></tr>
<tr><td>🔌 <a href="https://apify.com/abotapi/biccamera-com-scraper"><b>Bic Camera Scraper</b></a><br>Scrape Bic Camera (biccamera.com) products: JPY price, list price and discount, Bic Point...</td><td>🔌 <a href="https://apify.com/abotapi/boulanger-com-scraper"><b>Boulanger.com</b></a><br>Scrape Boulanger (boulanger.com) electronics and home-appliance products: current price...</td></tr>
<tr><td>🔌 <a href="https://apify.com/abotapi/casasbahia-com-br-scraper"><b>Casas Bahia Brazil Electronics &amp; Home Goods Scraper</b></a><br>Scrape products from Casas Bahia Brazil by keyword, department, or URL. Filter by brand...</td><td>🔌 <a href="https://apify.com/abotapi/darty-com-scraper"><b>Darty Scraper</b></a><br>Scrape Darty (darty.com) products: current price plus strike-through reference price and...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support & custom scrapers

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/currys-co-uk/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com> or message [Telegram @abotapi](https://t.me/abotapi).
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

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

Search mode = type keywords to search for. URL mode = paste one or more currys.co.uk search/category URLs already refined in a browser.

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

One or more keywords to search for, e.g. "tv", "laptop", "washing machine". Each keyword runs as its own search.

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

Optional. Only keep products priced at or above this amount. Applied to the already-fetched results (does not reduce the number of pages fetched).

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

Optional. Only keep products priced at or below this amount.

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

Only keep products currently marked in stock.

## `sortBy` (type: `string`):

How to order results within each search.

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

One or more full currys.co.uk search URLs. Multi-URL supported. Pagination starts at the page in the URL and walks forward.

## `fetchDetails` (type: `boolean`):

Adds the full description, GTIN/EAN, full high-res photo gallery, and precise stock state. Turn off for a faster run with just the search-result fields (title, brand, price, rating).

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

Fetch each product's Currys customer reviews (rating, text, author, date) from the reviews provider. Billed per review fetched, see the Pricing tab.

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

Cap on reviews fetched per product when "Fetch customer reviews" is on.

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

How many result pages to walk per search/URL (20 products per page). Leave empty to walk until Max total products is reached or the search runs out of pages.

## `maxListings` (type: `integer`):

Hard cap across the whole run. 0 = unlimited (bounded only by Max pages).

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

Paste a previous run ID or dataset ID to continue a full-catalogue walk across separate runs. Products already collected there (matched by product id) are skipped, so this run only saves the new ones. Leave empty for a normal fresh run. For recurring monitoring of the same search instead, use Incremental mode below.

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

Turn this on for daily/weekly recurring monitoring of the same search. The first run returns all matching products as NEW. Later runs return only NEW, UPDATED, and REAPPEARED products by default. Turn on "Emit unchanged products" or "Emit expired products" only when you also want those rows returned (and billed). State is kept separately per search (keywords/URLs, filters, detail/review settings); use State key below to name or deliberately share a monitoring campaign.

## `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 search inputs above.

## `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 pages/Max products capped it, a block stopped it early, or Resume was used.

## `ignoreFieldsForChanges` (type: `array`):

Optional. Field names to exclude from change detection in addition to the defaults (rating, reviewCount, reviews, priceValidUntil, which are already ignored because they change independently of the product itself). Use this if another field in your setup turns out to be noisy.

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

The actor manages its own connection tiers internally to reach currys.co.uk reliably. This field only lets you pin a country for the fallback residential tier if needed.

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

Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write/digest. Leave empty to skip, never changes the dataset output. 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": [
    "tv"
  ],
  "inStockOnly": false,
  "sortBy": "Relevance",
  "urls": [
    "https://www.currys.co.uk/search?q=tv"
  ],
  "fetchDetails": true,
  "fetchReviews": false,
  "maxReviewsPerProduct": 20,
  "maxListings": 20,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  },
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `reviews` (type: `string`):

No description

## `changes` (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": [
        "tv"
    ],
    "urls": [
        "https://www.currys.co.uk/search?q=tv"
    ],
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "GB"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/currys-co-uk").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": ["tv"],
    "urls": ["https://www.currys.co.uk/search?q=tv"],
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "GB",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/currys-co-uk").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": [
    "tv"
  ],
  "urls": [
    "https://www.currys.co.uk/search?q=tv"
  ],
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  }
}' |
apify call abotapi/currys-co-uk --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/currys-co-uk"
        }
    }
}
```

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/Qn2CpzhQyGTHr2ebm/builds/LatGd3JuInX8ZE5Jk/openapi.json
