# LeroyMerlin.es Scraper: Products, Prices, Sellers & Reviews (`abotapi/leroymerlin-es-scraper`) Actor

Scrape Leroy Merlin Spain (leroymerlin.es) DIY and home-improvement products: price, strike-through original price and discount, seller identity (Leroy Merlin vs marketplace) with every competing offer, stock, rating and individual reviews. Search by keyword/category or paste product/listing links.

- **URL**: https://apify.com/abotapi/leroymerlin-es-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 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/platform/actors/running/actors-in-store#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

## Leroy Merlin Spain Product Scraper

Pull product data from Leroy Merlin Spain (leroymerlin.es), a leading DIY and home-improvement retailer. Search by keyword, a real leroymerlin.es catalog category, or paste product and listing links directly. Every record includes the current price, the strike-through original price with discount when a product is genuinely on offer, and -- with detail on -- every competing marketplace offer for that product.

### Why This Scraper?

- **Was-price and discount, structured, not scraped from a badge.** When a product is marked down, both the current and original price are captured plus the discount amount and percentage. Full-price products carry `null`, never a fabricated discount.
- **Marketplace transparency.** Leroy Merlin sells both directly and through third-party sellers on the same product page. Every record identifies the seller (Leroy Merlin vs marketplace) and, with detail on, lists every competing offer for that product -- price, stock, and delivery time per seller.
- **Reviews straight from the product page.** Overall rating, review count, and individual customer reviews (author, date, rating, body) -- not a third-party review vendor.
- **Two ways in.** Keyword or category search with real site filters (price range, rating, promotion, seller, sort), or paste any product/listing link and continue pagination automatically.
- **Optional export to your apps.** Send results into Notion, Linear, Airtable, or any Apify MCP connector alongside the dataset.

### Data You Get

| Field | Example value |
|---|---|
| productId / sku | `123456` |
| name | `Sample Cordless Drill 18V` |
| brand | `SAMPLE BRAND` |
| category / categoryPath | `Cordless drills`, `["Tools", "Power tools", "Drilling & screwing", "Drills", "Cordless drills"]` |
| url | `https://www.leroymerlin.es/productos/sample-cordless-drill-18v-123456.html` |
| price / priceExclTax / currency | `99.99`, `82.64`, `EUR` |
| originalPrice / discountAmount / discountPercent | `129.99`, `30.00`, `23.1` |
| isOnSpecial | `true` |
| rating | `4.7` |
| sellerId / sellerName / sellerType | `002`, `Sample Retailer`, `1P` |
| totalOfferCount / sellersComposition | `12`, `1P_3P` |
| sponsored | `false` |
| ean | `4000000000000` |
| description | full product description text |
| image / numberOfImages | `https://media.example.com/sample.jpg`, `5` |
| stock / stockStatus / deliveryTime | `19`, `ONSITE`, `1 OPENING_DAY` |
| otherOffers\[] | `[{"sellerName": "Sample Marketplace Seller", "sellerType": "3P", "price": 105.40, "stock": 3, "deliveryTime": "3 OPENING_DAY"}]` |
| reviews.averageRating / reviews.totalReviewCount | `4.7`, `275` |
| reviews.items\[] | `[{"rating": 5, "body": "Sample review text.", "author": "Sample Customer", "date": "2026-07-15"}]` |

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

### How to Use

**1. Keyword search, first page, with detail and reviews (default):**

```json
{
  "mode": "search",
  "searchTerm": "taladro",
  "maxItems": 20
}
```

**2. Category browse, only products on promotion, sorted by price:**

```json
{
  "mode": "search",
  "category": "herramientas/herramientas-electricas-portatiles/herramientas-electricas-para-taladrar-atornillar/taladros/taladros-de-bateria",
  "onPromotionOnly": true,
  "sortBy": "price_asc",
  "maxItems": 50,
  "maxPages": 5
}
```

**3. Only Leroy Merlin's own offers, minimum 4-star rating:**

```json
{
  "mode": "search",
  "searchTerm": "grifo cocina",
  "sellerFilter": "leroymerlin",
  "minRating": 4,
  "maxItems": 30
}
```

**4. Full detail and reviews for a pasted product link:**

```json
{
  "mode": "url",
  "urls": ["https://www.leroymerlin.es/productos/sample-cordless-drill-18v-123456.html"],
  "fetchDetails": true,
  "fetchReviews": true
}
```

### Input Parameters

| Parameter | Type | Description |
|---|---|---|
| `mode` | string | `search` or `url`. |
| `searchTerm` | string | Keyword (search mode only). |
| `category` | string | A real leroymerlin.es catalog category path (search mode only). Ignored when `searchTerm` is set. |
| `sortBy` | string | `relevance`, `price_asc`, or `price_desc` (search mode only). |
| `minPrice` / `maxPrice` | number | EUR price band to keep. |
| `minRating` | number | Minimum average rating (0-5) to keep. |
| `onPromotionOnly` | boolean | Keep only products currently on promotion. |
| `sellerFilter` | string | `any`, `leroymerlin`, or `marketplace`. |
| `urls` | array | Product or listing (search/category) URLs to scrape (url mode only). |
| `fetchDetails` | boolean | Fetch EAN, description, image, breadcrumb category path, stock/delivery, and every competing marketplace offer. |
| `fetchReviews` | boolean | Fetch the product's own reviews. Shares the same page fetch as `fetchDetails`. |
| `maxReviewsPerProduct` | integer | Cap on reviews per product; the product page itself only ever surfaces its most recent reviews. |
| `maxPages` | integer | Cap on result pages per search/category/URL entry; empty = unlimited. |
| `maxItems` | integer | Cap on total products returned; `0` = unlimited. |
| `proxy` | object | Apify proxy configuration. A residential connection in Spain is required (see below). |
| `mcpConnectors` | array | Optional MCP connectors to export results into (Notion, Linear, Airtable, Apify). |
| `notionParentPageUrl` | string | Notion connector only: page under which item pages are created. |
| `maxNotifyListings` | integer | Cap on items exported to each connector per run. Does not affect the dataset. |

### Output Example

```json
{
  "productId": "123456",
  "sku": "123456",
  "name": "Sample Cordless Drill 18V",
  "brand": "SAMPLE BRAND",
  "url": "https://www.leroymerlin.es/productos/sample-cordless-drill-18v-123456.html",
  "price": 99.99,
  "priceExclTax": 82.64,
  "currency": "EUR",
  "originalPrice": 129.99,
  "discountAmount": 30.0,
  "discountPercent": 23.1,
  "isOnSpecial": true,
  "rating": 4.7,
  "sellerId": "002",
  "sellerName": "Sample Retailer",
  "sellerType": "1P",
  "totalOfferCount": 12,
  "sellersComposition": "1P_3P",
  "sponsored": false,
  "offerType": "NEW",
  "ean": "4000000000000",
  "description": "Sample product description as shown on the site.",
  "image": "https://media.example.com/sample.jpg",
  "numberOfImages": 5,
  "categoryPath": ["Tools", "Power tools", "Drilling & screwing", "Drills", "Cordless drills"],
  "category": "Cordless drills",
  "stock": 19,
  "stockStatus": "ONSITE",
  "deliveryTime": "1 OPENING_DAY",
  "otherOffers": [
    { "sellerName": "Sample Marketplace Seller", "sellerType": "3P", "price": 105.40, "stock": 3, "deliveryTime": "3 OPENING_DAY" }
  ],
  "numberOfReviews": 275,
  "reviews": {
    "averageRating": 4.7,
    "totalReviewCount": 275,
    "items": [
      { "rating": 5, "body": "Sample review text.", "author": "Sample Customer", "date": "2026-07-15" }
    ]
  },
  "searchMode": "search"
}
```

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

### A note on reviews and marketplace offers

Reviews come directly from the product page itself, not a third-party review vendor -- the page only ever surfaces its most recent reviews, while the overall rating and review count reflect the full history. `otherOffers` lists every competing offer visible on the product page at fetch time (price, stock, delivery); products sold exclusively by Leroy Merlin with no marketplace competition simply omit the field rather than returning an empty placeholder.

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

Optionally pipe results into the apps you already use through Model Context Protocol (MCP) connectors. Authorize a connector once under Apify, Settings, Integrations, then select it in the `mcpConnectors` field. Each connector receives a condensed, human-readable summary per product (name plus key fields), while the complete record always stays in the Apify dataset. For Notion, set `notionParentPageUrl` to the page the item pages should be created under, and use `maxNotifyListings` to cap how many items are exported per connector per run. Supported connectors: Notion, Linear, Airtable, and Apify. Leave the field empty to skip; it never changes the dataset output.

### A note on plans

leroymerlin.es answers only on a Spanish residential connection -- a datacenter connection is refused and returns no results. Use Apify Proxy with residential access (country Spain), which this actor selects by default.

# Actor input Schema

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

'search' finds products by keyword and/or a leroymerlin.es category path, with price/rating/promotion/seller filters and the site's own sort. 'url' scrapes any product or listing (search/category) page URL you paste, walking pagination forward automatically.

## `searchTerm` (type: `string`):

Free-text keyword, e.g. 'taladro' or 'grifo cocina'. Leave empty and use Category only below to browse a category without a keyword.

## `category` (type: `string`):

A leroymerlin.es catalog category path (copy it from the site's own breadcrumb links or a category URL), e.g. 'herramientas/herramientas-electricas-portatiles/herramientas-electricas-para-taladrar-atornillar/taladros/taladros-de-bateria'. Ignored when Search keyword is set -- fill in exactly one of the two.

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

leroymerlin.es's own sort. The site pins one sponsored slot regardless of sort, so price ordering is additionally re-applied over the collected products to stay strictly correct.

## `minPrice` (type: `number`):

Only return products priced at or above this amount, in euros.

## `maxPrice` (type: `number`):

Only return products priced at or below this amount, in euros.

## `minRating` (type: `number`):

Only return products whose average rating is at least this many stars (0-5). Rating is already present on every listing card, no detail fetch required.

## `onPromotionOnly` (type: `boolean`):

Keep only products currently showing the site's own strike-through original price and discount.

## `sellerFilter` (type: `string`):

Narrow to products sold directly by Leroy Merlin, or only marketplace (third-party) offers. 'Any' keeps both.

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

Only used when mode = url -- ignored in every other mode. Paste one or more product pages (under /productos/\*-<id>.html), category listing pages (under /productos/<path>/), or search result pages (/search?q=...). Pagination continues forward automatically from any ?p= already present.

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

Adds EAN, description, hero image, breadcrumb category path, stock/delivery, and every competing marketplace offer (price, stock, delivery per seller) from the product page. Current price, was-price/discount, rating and seller identity are already included without this toggle.

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

Fetch the product's own reviews (not a third-party vendor): overall rating, total review count, and the page's most recent individual reviews (rating, body, author, date). leroymerlin.es itself only ever surfaces its most recent ~8 reviews per product; the rating and total count reflect the full history. Shares the same page fetch as 'Fetch product detail' -- turning both on costs no extra request. Products with no reviews return an empty list.

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

Cap on reviews returned per product when 'Fetch reviews' is on, up to the site's own page limit.

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

Stop after this many result pages per search, category, or pasted listing URL. Leave empty for no page limit -- the run stops at Max products.

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

Hard cap on total products returned across the whole run. 0 = unlimited (still bounded by Max pages).

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

Apify Proxy is required. leroymerlin.es answers only on a Spanish residential connection, so the run uses a residential exit in Spain by default.

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

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify -> Settings -> Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON; the complete record stays in the dataset. Leave empty to skip. 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",
  "searchTerm": "taladro",
  "sortBy": "relevance",
  "onPromotionOnly": false,
  "sellerFilter": "any",
  "urls": [
    "https://www.leroymerlin.es/search?q=taladro"
  ],
  "fetchDetails": true,
  "fetchReviews": true,
  "maxReviewsPerProduct": 8,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "ES"
  },
  "maxNotifyListings": 50
}
```

# 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 = {
    "mode": "search",
    "searchTerm": "taladro",
    "urls": [
        "https://www.leroymerlin.es/search?q=taladro"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "ES"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/leroymerlin-es-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 = {
    "mode": "search",
    "searchTerm": "taladro",
    "urls": ["https://www.leroymerlin.es/search?q=taladro"],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "ES",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/leroymerlin-es-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "search",
  "searchTerm": "taladro",
  "urls": [
    "https://www.leroymerlin.es/search?q=taladro"
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "ES"
  }
}' |
apify call abotapi/leroymerlin-es-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=abotapi/leroymerlin-es-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/yCTdRzS38fHaCJY9N/builds/Jho0lUUUfqheaZBtb/openapi.json
