{
  "openapi": "3.0.1",
  "info": {
    "title": "LeroyMerlin.es Scraper: Products, Prices, Sellers & Reviews",
    "description": "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.",
    "version": "1.0",
    "x-build-id": "ON9e5kqHz6ej3QBKg"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~leroymerlin-es-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-leroymerlin-es-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/abotapi~leroymerlin-es-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-leroymerlin-es-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/abotapi~leroymerlin-es-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-leroymerlin-es-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "mode"
        ],
        "properties": {
          "mode": {
            "title": "Mode",
            "enum": [
              "search",
              "url"
            ],
            "type": "string",
            "description": "'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.",
            "default": "search"
          },
          "searchTerm": {
            "title": "Search keyword",
            "type": "string",
            "description": "Free-text keyword, e.g. 'taladro' or 'grifo cocina'. Leave empty and use Category only below to browse a category without a keyword."
          },
          "category": {
            "title": "Category path",
            "type": "string",
            "description": "A leroymerlin.es catalog category path (copy it from the site's own breadcrumb links or a category URL), a plain category name such as 'Taladros de batería' also works but only if it matches the site's own slug; a name that matches no listing logs a warning. Example path: '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": {
            "title": "Sort order",
            "enum": [
              "relevance",
              "price_asc",
              "price_desc"
            ],
            "type": "string",
            "description": "leroymerlin.es's own sort, applied whether you run a keyword/category search or paste a listing URL. The site keeps one sponsored slot pinned regardless of sort; every other item comes back correctly ordered by your chosen sort.",
            "default": "relevance"
          },
          "minPrice": {
            "title": "Minimum price (EUR)",
            "type": "number",
            "description": "Only return products priced at or above this amount, in euros."
          },
          "maxPrice": {
            "title": "Maximum price (EUR)",
            "type": "number",
            "description": "Only return products priced at or below this amount, in euros."
          },
          "minRating": {
            "title": "Minimum rating",
            "minimum": 0,
            "maximum": 5,
            "type": "number",
            "description": "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": {
            "title": "Only products on promotion",
            "type": "boolean",
            "description": "Keep only products currently showing the site's own strike-through original price and discount.",
            "default": false
          },
          "sellerFilter": {
            "title": "Seller",
            "enum": [
              "any",
              "leroymerlin",
              "marketplace"
            ],
            "type": "string",
            "description": "Narrow to products sold directly by Leroy Merlin, or only marketplace (third-party) offers. 'Any' keeps both.",
            "default": "any"
          },
          "urls": {
            "title": "leroymerlin.es links",
            "uniqueItems": true,
            "type": "array",
            "description": "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. Left untouched, this field scrapes one example of each shape (a keyword search, a category listing and a product page).",
            "default": [
              "https://www.leroymerlin.es/search?q=taladro",
              "https://www.leroymerlin.es/productos/herramientas/herramientas-electricas-portatiles/herramientas-electricas-para-taladrar-atornillar/taladros/taladros-de-bateria/",
              "https://www.leroymerlin.es/productos/taladro-percutor-a-bateria-bosch-18v-2-baterias-easyimpact-18v-40-83518470.html"
            ],
            "items": {
              "type": "string"
            }
          },
          "fetchDetails": {
            "title": "Fetch product detail",
            "type": "boolean",
            "description": "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.",
            "default": true
          },
          "fetchReviews": {
            "title": "Fetch reviews",
            "type": "boolean",
            "description": "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.",
            "default": true
          },
          "maxReviewsPerProduct": {
            "title": "Max reviews per product",
            "minimum": 0,
            "maximum": 1000,
            "type": "integer",
            "description": "Cap on reviews returned per product when 'Fetch reviews' is on, up to the site's own page limit (the product page embeds only its most recent ~8 reviews; no paginated review endpoint is exposed).",
            "default": 20
          },
          "maxPages": {
            "title": "Max pages per search/category/URL",
            "minimum": 0,
            "type": "integer",
            "description": "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": {
            "title": "Max products",
            "minimum": 0,
            "type": "integer",
            "description": "Hard cap on products returned across the whole run. With incremental mode on it caps products scanned: unchanged products that are not returned still count toward it. 0 = unlimited (still bounded by Max pages).",
            "default": 20
          },
          "proxy": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Apify Proxy is required. leroymerlin.es answers only on a Spanish residential connection, so the run uses a residential exit in Spain by default.",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ],
              "apifyProxyCountry": "ES"
            }
          },
          "resumeFromRunId": {
            "title": "Resume from a previous run",
            "type": "string",
            "description": "Paste a previous run ID or dataset ID to continue an interrupted pull without returning or charging for products already collected there. For recurring monitoring of the same search, use Incremental changes below instead."
          },
          "incrementalMode": {
            "title": "Incremental changes for scheduled runs",
            "type": "boolean",
            "description": "Turn this on for daily or recurring monitoring. The first run returns every matching product as NEW. Later runs return only NEW, UPDATED and REAPPEARED products (a price cut, a stock change, a new seller offer). Each row gets changeType, changedFields, firstSeenAt and lastSeenAt. Compared are all returned fields except the scrape timestamp, the review texts (a new review still moves the rating and review count) and the live stock and delivery-time counters. State is kept separately for each search, filter and detail setup; use State key to name or share a campaign. Turn on Emit unchanged or Emit expired only if you also want those rows returned (and billed).",
            "default": false
          },
          "stateKey": {
            "title": "State key (optional, incremental mode only)",
            "type": "string",
            "description": "Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently configured runs. Leave empty to derive a key automatically from the search, filters and detail settings."
          },
          "emitUnchanged": {
            "title": "Emit unchanged products (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return products that have not changed since the last run, marked UNCHANGED. This returns, and bills, rows you already have.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit expired products (incremental mode only)",
            "type": "boolean",
            "description": "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 after a run fully scanned the tracked search, so never when Max products or Max pages cut it short, or when Resume was used. This returns, and bills, synthetic rows.",
            "default": false
          },
          "ignoreFieldsForChanges": {
            "title": "Ignore fields when detecting changes (incremental mode only)",
            "type": "array",
            "description": "Field names (for example sponsored) that must not make a product count as UPDATED. They are still returned in the row. Dotted paths such as otherOffers.stock are allowed.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "mcpConnectors": {
            "title": "Pipe results into your apps (optional)",
            "type": "array",
            "description": "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": {
            "title": "Notion parent page (Notion connector only)",
            "type": "string",
            "description": "URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors."
          },
          "maxNotifyListings": {
            "title": "Max items to export per connector",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Cap on items written to each connector per run. Does not affect the dataset.",
            "default": 50
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}