# Boots Product Scraper (`mrdoe/boots-product-scraper`) Actor

Extract product data from Boots.com — prices, stock, ratings, promotions and full specs. Search any category or keyword, or pull complete product details (ingredients, how-to-use, images, reviews) by URL. Fast, bot-protection-proof, no login needed. Residential proxy built in.

- **URL**: https://apify.com/mrdoe/boots-product-scraper.md
- **Developed by:** [MrDoe](https://apify.com/mrdoe) (community)
- **Categories:**
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 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?

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

![Boots Product Scraper hero](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/boots-product-scraper--hero.png)

### What it does

Boots Product Scraper turns any Boots.com search, category page, or product page into clean, structured data. Two modes, one run each:

- **Product Search** — give it a keyword (`shampoo`) or a full Boots listing URL (`https://www.boots.com/christmas/all-christmas`) and it walks every result page, returning one row per product: price, promotions, rating, stock, image, category path, and more.
- **Product Details** — give it a Boots product URL or the numeric id from the end of that URL and it returns the full product record: description, how-to-use, ingredients, hazards, country of origin, promotions, Advantage Card points, the whole image gallery, and the review summary.

No account, no login, no cookies to supply.

### Why use it

- **Both catalogue and deep detail in one Actor** — monitor prices across a category, then pull full specs for the products that matter.
- **Real pagination** — Product Search follows the catalogue to the end (capped by your `maxItems`), not just the first page.
- **Honest nulls** — a field that isn't on the page comes back `null`, never guessed.
- **Stable identifiers** — every row carries the product's URL id, its catalogue id, and its part number, so you can join runs over time.

### What makes this different

Boots renders its catalogue grid and its product pages behind bot protection and a good deal of client-side scripting. This Actor drives a real, fingerprint-clean browser to get past that, then reads Boots' own product data directly rather than scraping pixels — so the output is complete and consistent, not a best-effort guess from visible text.

### Data you get

| Group | Fields |
| --- | --- |
| Identity | `productId`, `catalogEntryId`, `urlId`, `partNumber`, `title`, `brand`, `productUrl` |
| Price | `price`, `listPrice`, `onSale`, `saving`, `currency`, `pricePerUnit`, `size` |
| Reviews | `rating`, `reviewCount`, `ratingDistribution` |
| Availability | `inStock`, `availability` |
| Marketing | `promotions`, `loyaltyPoints` |
| Content (details mode) | `description`, `howToUse`, `ingredients`, `hazards`, `importantInfo` |
| Media | `image`, `images` |
| Navigation | `breadcrumb`, `categories`, `hreflang`, `canonicalUrl` |

### How to use

![How Boots Product Scraper works](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/boots-product-scraper--how-it-works.png)

1. Pick an **Operation**: *Product Search* or *Product Details*.
2. For search, fill **Search query or Boots listing URL** (or the batch list). For details, fill **Product URL or product id** (or the batch list).
3. Set **Max items** if you want more or fewer than 20 search rows.
4. Leave the residential proxy on and run.

### Input

![Boots Product Scraper input options](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/boots-product-scraper--input.png)

| Field | Type | Notes |
| --- | --- | --- |
| `operation` | string | `search` or `productDetails`. Required. |
| `query` | string | Keyword or full Boots search/category URL. Search mode. |
| `queries` | array | Many keywords / listing URLs. Wins over `query`. |
| `productUrl` | string | Boots product URL or the trailing numeric id. Details mode. |
| `productUrls` | array | Many product URLs / ids. Wins over `productUrl`. |
| `sortBy` | string | Keyword search only. E.g. `priceLowToHigh`. Blank = Boots' default. |
| `maxItems` | integer | Total row cap for search. Default 20. Details mode returns one row per product regardless. |
| `proxyConfiguration` | object | Residential proxy strongly recommended. |

### Output

![Boots Product Scraper dataset output](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/boots-product-scraper--output.png)

![Boots Product Scraper data fields](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/boots-product-scraper--fields.png)

One example row from *Product Details*:

```json
{
    "_operation": "productDetails",
    "status": "success",
    "productId": "10356777.P",
    "catalogEntryId": "3063629",
    "urlId": "10356777",
    "partNumber": "10356777.P",
    "title": "L’Oréal Paris Elvive Hydra Hyaluronic Moisture Boosting Shampoo, for Dry & Dehydrated Hair, 400ml",
    "brand": "L'Oreal",
    "price": 8,
    "currency": "GBP",
    "pricePerUnit": "£20.00 per 1L",
    "size": "400ml",
    "inStock": true,
    "availability": "http://schema.org/InStock",
    "rating": 4.75,
    "reviewCount": 120,
    "ratingDistribution": [
        { "rating": 5, "count": 102 },
        { "rating": 4, "count": 11 },
        { "rating": 3, "count": 3 },
        { "rating": 2, "count": 3 },
        { "rating": 1, "count": 1 }
    ],
    "description": "Dehydrated hair often manifests as dry, dull, and lifeless strands...",
    "howToUse": "Apply on wet hair, massage your scalp and rinse. In case of contact with eyes, rinse immediately and thoroughly.",
    "ingredients": "AQUA / WATER • SODIUM LAURETH SULFATE • GLYCOL DISTEARATE...",
    "hazards": "In case of contact with eyes, rinse them immediately. Keep out of reach of children.",
    "importantInfo": "Country of Origin: France\nAddress: UK: L’Oreal UK, Gateway Central 187 Wood Lane, London, W12 7SA",
    "promotions": [
        "Save 1/3 when you buy 3 on selected Loreal oil",
        "Save £5 when you spend £25 on selected haircare and makeup - online only"
    ],
    "loyaltyPoints": 24,
    "breadcrumb": "Home|L’Oréal Paris Elvive Hydra Hyaluronic Moisture Boosting Shampoo, for Dry & Dehydrated Hair, 400ml",
    "image": "https://boots.scene7.com/is/image/Boots/10356777?fmt=jpg&wid=1000&hei=1000&fit=constrain,1",
    "images": [
        "https://boots.scene7.com/is/image/Boots/10356777?fmt=jpg&wid=1000&hei=1000&fit=constrain,1",
        "https://boots.scene7.com/is/image/Boots/10356777_1?fmt=jpg&wid=1000&hei=1000&fit=constrain,1"
    ],
    "hreflang": {
        "gb": "https://www.boots.com/loreal-paris-elvive-hydra-hyaluronic-moisture-boosting-shampoo-for-dry-and-dehydrated-hair-400ml-10356777",
        "ie": "https://www.boots.ie/loreal-paris-elvive-hydra-hyaluronic-moisture-boosting-shampoo-for-dry-and-dehydrated-hair-400ml-10356777"
    },
    "canonicalUrl": "https://www.boots.com/loreal-paris-elvive-hydra-hyaluronic-moisture-boosting-shampoo-for-dry-and-dehydrated-hair-400ml-10356777",
    "productUrl": "https://www.boots.com/loreal-paris-elvive-hydra-hyaluronic-moisture-boosting-shampoo-for-dry-and-dehydrated-hair-400ml-10356777"
}
```

### Usage examples

**Track a category**

```json
{ "operation": "search", "query": "https://www.boots.com/beauty-skincare/skincare/face-skincare", "maxItems": 500 }
```

**Batch price check on specific products**

```json
{ "operation": "productDetails", "productUrls": ["10356777", "https://www.boots.com/no7-25-days-of-beauty-advent-calendar-10389976"] }
```

**Cheapest shampoos first**

```json
{ "operation": "search", "query": "shampoo", "sortBy": "priceLowToHigh", "maxItems": 100 }
```

### Known limitations

- Prices, promotions, and stock are for the Boots UK site (GBP) and reflect online availability, not a specific physical store.
- The full `description`, `ingredients`, and other long-form content are only returned by *Product Details*, not by *Product Search* (search returns a shorter summary set).
- `rating` / `reviewCount` come from the review platform and can lag the product page by a short time.
- Very large categories are capped by `maxItems`; raise it to go deeper, at proportional runtime.
- Sponsored / ad placements in a category are skipped.

### FAQ

**Do I need a Boots account?** No.

**Can I pass just the number at the end of a product URL?** Yes — both `productUrl` and `productUrls` accept the bare id or the full URL.

**Does it work for boots.ie?** This Actor targets boots.com (UK). Each row includes the matching boots.ie URL under `hreflang`.

**Why a residential proxy?** Boots fronts its pages with bot protection; residential exits are far more reliable for sustained runs.

### Legal

Use this Actor for lawful purposes and in line with Boots' Terms of Use and applicable law. It collects only publicly available catalogue information and no personal data. You are responsible for how you use the data you collect.

# Actor input Schema

## `operation` (type: `string`):

Which Boots data to scrape. One operation per run.

## `query` (type: `string`):

A keyword to search Boots (e.g. "shampoo") or a full Boots search / category URL (e.g. "https://www.boots.com/christmas/all-christmas"). Used by the search operation. Defaults to a demo query if left blank.

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

Many keywords and/or Boots listing URLs in one run. Wins over "query" when filled. Duplicates and blanks are dropped.

## `productUrl` (type: `string`):

A full Boots product URL (e.g. "https://www.boots.com/....-10356777") or the numeric id that trails it (e.g. "10356777"). Used by the productDetails operation. Defaults to a demo product if left blank.

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

Many product URLs and/or numeric ids in one run. Wins over "productUrl" when filled.

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

Applies to keyword search only. Leave blank to use Boots' default ordering. Known values: mostRelevant, priceLowToHigh, priceHighToLow, aToZ, zToA, newToStore.

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

Caps total rows across the whole run for the search operation (productDetails always returns one row per requested product). The first 10 rows of any run are free. Defaults to 20 - raise it if you need more.

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

A residential proxy is strongly recommended - Boots fronts every page with bot protection.

## Actor input object example

```json
{
  "operation": "search",
  "query": "shampoo",
  "productUrl": "https://www.boots.com/loreal-paris-elvive-hydra-hyaluronic-moisture-boosting-shampoo-for-dry-and-dehydrated-hair-400ml-10356777",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "query": "shampoo",
    "productUrl": "https://www.boots.com/loreal-paris-elvive-hydra-hyaluronic-moisture-boosting-shampoo-for-dry-and-dehydrated-hair-400ml-10356777",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrdoe/boots-product-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 = {
    "query": "shampoo",
    "productUrl": "https://www.boots.com/loreal-paris-elvive-hydra-hyaluronic-moisture-boosting-shampoo-for-dry-and-dehydrated-hair-400ml-10356777",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("mrdoe/boots-product-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 '{
  "query": "shampoo",
  "productUrl": "https://www.boots.com/loreal-paris-elvive-hydra-hyaluronic-moisture-boosting-shampoo-for-dry-and-dehydrated-hair-400ml-10356777",
  "maxItems": 20
}' |
apify call mrdoe/boots-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mrdoe/boots-product-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/pRnroMZ0af733wTDj/builds/H2KeXk5RHUEEeNhQV/openapi.json
