# Leroy Merlin Romania Scraper: Products, Prices & Sellers (`axlymxp/leroymerlin-product-scraper`) Actor

Scrape Leroy Merlin Romania (leroymerlin.ro) by keyword or category: price in RON, discounts, brand, seller, rating, images, plus optional GTIN, description and stock status. Structured JSON for price monitoring and market research. No login needed.

- **URL**: https://apify.com/axlymxp/leroymerlin-product-scraper.md
- **Developed by:** [axly](https://apify.com/axlymxp) (community)
- **Categories:** E-commerce, Lead generation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 dataset items

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Leroy Merlin Romania Product Scraper

Export products from Leroy Merlin Romania (`www.leroymerlin.ro`), the home-improvement, construction, garden and DIY retailer, as structured JSON. Search by keyword or list a whole category. No login and no cookies needed.

Each row has the current price in RON (VAT included), the original price and discount when a product is on offer, the brand, the seller (Leroy Merlin itself or a marketplace seller), the customer rating and the product image. Turn on `includeDetail` to also get the GTIN/EAN barcode, the product description and the stock status from each product page.

### Who this is for

- **Retailers and resellers** tracking competitor prices for tools, lighting, flooring and building materials in Romania.
- **Price-comparison sites and procurement tools** that need a clean catalog feed with SKUs and barcodes.
- **Contractors, agencies and analysts** comparing material prices and marketplace-seller share across categories.
- **Researchers** studying regional retail pricing and assortment.

### Output fields

| Field | Type | Description |
|---|---|---|
| `sku` | string | Leroy Merlin product code |
| `title` | string | Product name |
| `brand` | string | null | Brand name (not shown for every product) |
| `price` | number | Current price in RON, VAT included |
| `originalPrice` | number | null | Price before the discount, when on offer |
| `discountPercent` | number | null | Discount shown on the product card, when on offer |
| `currency` | string | Always `RON` |
| `seller` | string | `Leroy Merlin` or the marketplace seller's name |
| `sellerType` | string | `1P` (Leroy Merlin) or `3P` (marketplace seller) |
| `rating` | number | null | Average customer rating (0-5); null if unrated |
| `url` | string | Product page URL |
| `images` | array of strings | Product image URL (listing image, or the product-page image with `includeDetail`) |
| `categoryId` | integer | null | Category ID, in category mode |
| `availability` | string | null | `InStock` / `OutOfStock` schema.org URL; only with `includeDetail` |
| `gtin` | string | null | GTIN/EAN barcode; only with `includeDetail` |
| `description` | string | null | Product description; only with `includeDetail` |
| `scrapedAt` | string | ISO 8601 UTC timestamp |

### Use cases

1. **Price monitoring:** schedule a daily run per keyword or category and diff the `price` column.
2. **Competitor benchmarking:** compare Leroy Merlin RO prices with other Romanian DIY retailers using the barcode (`gtin`).
3. **Marketplace analysis:** see which brands and third-party sellers (`sellerType = 3P`) dominate a category.
4. **Catalog feeds:** push structured rows into a procurement tool, spreadsheet or database via the Apify API.

### Input

| Parameter | Type | Default | Description |
|---|---|---|---|
| `keywords` | string | none | Search term, for example `lustra` or `parchet`. Takes priority over the category fields. A search returns at most 10 pages (about 480 products); use categories or narrower keywords for more. |
| `categorySlug` | string | none | Category slug from the site URL, for example `profile-gips-carton` from `/produse/profile-gips-carton/479` |
| `categoryId` | integer | none | Category ID from the same URL, for example `479` |
| `maxItems` | integer | `100` | Stop after this many products |
| `includeDetail` | boolean | `false` | Open each product page for description, GTIN, availability and the page image. One extra request per product, so slower |
| `proxyConfiguration` | object | none | Optional. The site is reachable without a proxy; set one if requests get blocked |

Provide either `keywords` or both `categorySlug` and `categoryId`. A category must be a leaf category (the product list page), as in the example above.

#### Example input

```json
{
  "keywords": "lustra",
  "maxItems": 20,
  "includeDetail": false
}
```

#### Example output row

```json
{
  "sku": "72101761",
  "title": "Lustra tip sfoara cu un bec E27, lungime 1m Z-TOOLS / ZTS 8405",
  "brand": "Z-TOOLS",
  "price": 9.87,
  "originalPrice": null,
  "discountPercent": null,
  "currency": "RON",
  "seller": "Z-Tools - Scule si Unelte Design",
  "sellerType": "3P",
  "rating": null,
  "url": "https://www.leroymerlin.ro/produse/lustra-tip-sfoara-cu-un-bec-e27-lungime-1m-z-tools-zts-8405-72101761.html",
  "availability": null,
  "images": ["https://media.adeo.com/media/5125835/media.jpg"],
  "categoryId": null,
  "gtin": null,
  "description": null,
  "scrapedAt": "2026-10-11T03:03:52+00:00"
}
```

### Scheduling and integrations

Use the Apify Scheduler for recurring price tracking, or trigger a webhook after each run to sync rows to Google Sheets, Make, Zapier or S3. Results are available through the Apify API as JSON, CSV or Excel.

### FAQ

**Is there a result limit?** `maxItems` goes up to 10,000, but a keyword search returns at most 10 pages (about 480 products) because that is how deep the site paginates. Category listings continue until the category ends.

**How are pages and retries handled?** The Actor pages through the listing (48 products per page) and retries temporary errors (429/502/503) with backoff. Progress is checkpointed, so a restarted run resumes instead of starting over.

**Why are some `brand` or `rating` values empty?** The site does not show a brand or rating for every product; those fields are null when the site has none.

**Does it need a proxy?** In our test runs on the Apify platform it worked without one. If your runs get blocked, add `proxyConfiguration`.

**What happens when the search finds nothing?** The run finishes with zero rows.

**What if the site layout changes?** The Actor stops with an error instead of returning empty results, and the developer is notified.

# Actor input Schema

## `keywords` (type: `string`):

Search term for the Leroy Merlin Romania catalog (e.g. "lustra", "parchet"). If set, it takes priority over the category fields. A search returns at most 10 pages (about 480 products).

## `categorySlug` (type: `string`):

Leaf category slug from the site URL, e.g. "profile-gips-carton" from /produse/profile-gips-carton/479. Must be paired with categoryId.

## `categoryId` (type: `integer`):

Leaf category numeric ID from the site URL, e.g. 479 from /produse/profile-gips-carton/479. Must be paired with categorySlug.

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

Stop after this many product rows have been pushed to the dataset.

## `includeDetail` (type: `boolean`):

Open every product page to add description, GTIN/EAN, availability and the main image. Slower: one extra request per product.

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

Optional. The site is reachable without a proxy; enable one if requests are blocked.

## Actor input object example

```json
{
  "keywords": "lustra",
  "maxItems": 20,
  "includeDetail": false,
  "proxyConfiguration": {}
}
```

# Actor output Schema

## `results` (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 = {
    "keywords": "lustra",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("axlymxp/leroymerlin-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 = {
    "keywords": "lustra",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("axlymxp/leroymerlin-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 '{
  "keywords": "lustra",
  "maxItems": 20
}' |
apify call axlymxp/leroymerlin-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axlymxp/leroymerlin-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/lHLLvELmqacViIRsO/builds/PNxjiSYXbAt4wtAJq/openapi.json
