{
  "openapi": "3.0.1",
  "info": {
    "title": "Lidl.es Products, Weekly Offers, Prices & Reviews Scraper",
    "description": "Scrape Lidl.es grocery and non-food products across weekly offers, tools, home, garden, kitchen, fashion, kids, sport and more. Search by keyword, department or URL. Extract prices, was-prices, discounts, package formats, images, ratings and full shopper reviews.",
    "version": "1.0",
    "x-build-id": "4k79HqIWGs6kw7P9f"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~lidl-es-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-lidl-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~lidl-es-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-lidl-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~lidl-es-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-lidl-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' browses the Lidl.es catalogue (grocery weekly offers + the bazaar/non-food range) by keyword, department, brand and filters. 'url' scrapes any product, search/specials, or category link you paste.",
            "default": "search"
          },
          "searchTerm": {
            "title": "Search keyword",
            "type": "string",
            "description": "Free-text keyword against Lidl's own search index, e.g. 'bateria' or 'sandia'. Leave empty (with a Department set) to browse a whole department."
          },
          "category": {
            "title": "Department",
            "enum": [
              "",
              "bricolaje-jardin",
              "cocina-hogar",
              "hogar-decoracion",
              "deporte-tiempo-libre",
              "moda-accesorios",
              "bebe-infantil-juguetes",
              "alimentacion"
            ],
            "type": "string",
            "description": "Narrow to one of Lidl.es's real top-level departments, spanning both the bazaar/non-food weekly range and grocery. Leave as 'Any' to search across the whole catalogue.",
            "default": ""
          },
          "brand": {
            "title": "Brand",
            "type": "string",
            "description": "Only return products from this brand, exactly as Lidl shows it (e.g. 'PARKSIDE', 'SILVERCREST', 'CRIVIT'). Leave empty for all brands."
          },
          "specialsOnly": {
            "title": "Weekly offers only",
            "type": "boolean",
            "description": "Narrows to Lidl's own genuine weekly-offer markdowns (real strike-through was-price + discount %) -- the same set as the site's own 'Descuentos' page.",
            "default": false
          },
          "inStockOnly": {
            "title": "In stock only",
            "type": "boolean",
            "description": "Drop products that are not currently orderable online (sold out or in-store only). Applied to the rows returned, so Max products counts only in-stock rows.",
            "default": false
          },
          "strictMatch": {
            "title": "Strict keyword match",
            "type": "boolean",
            "description": "Search mode only: keep a product only when every word of the search keyword appears in its title, brand or category, dropping loose relevance matches from Lidl's own search.",
            "default": false
          },
          "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 (1-5)",
            "type": "number",
            "description": "Only return products with a shopper rating at or above this value."
          },
          "sortBy": {
            "title": "Sort order",
            "enum": [
              "RELEVANCE",
              "PRICE_ASC",
              "PRICE_DESC",
              "NEWEST",
              "TOP_RATED",
              "BESTSELLERS",
              "BIGGEST_DISCOUNT"
            ],
            "type": "string",
            "description": "Sort order for the results, using Lidl's own real sort options.",
            "default": "RELEVANCE"
          },
          "urls": {
            "title": "URLs to scrape",
            "uniqueItems": true,
            "type": "array",
            "description": "Paste one or more Lidl.es links. Supported: product pages (lidl.es/p/<slug>/p<id>, also the short or slug-less lidl.es/p/p<id> form and the bare lidl.es host), search and specials pages (lidl.es/q/query/<term> or lidl.es/q/search?q=<term>, with category, brand, discountFlag, sort, price, ratingAverage and offset taken from the link), department pages (lidl.es/h/<slug>/h<id>, optionally ?offset=48), department hubs (lidl.es/c/<slug>/s<id>) and campaign pages (lidl.es/c/<slug>/a<id>). Leaving this field untouched scrapes one example of each distinct link target (the alternate search form returns the same products as the search link, so it is listed in the examples but not in the default). Filter fields above are ignored in this mode.",
            "default": [
              "https://www.lidl.es/p/parkside-bateria-de-20-v-4-ah-pap-204-a1/p100398189",
              "https://www.lidl.es/q/query/bateria",
              "https://www.lidl.es/q/query/bateria?category=Bricolaje%20y%20jard%C3%ADn&brand=PARKSIDE&offset=36",
              "https://www.lidl.es/q/query/descuentos?discountFlag=1",
              "https://www.lidl.es/h/aspiradoras/h10084470",
              "https://www.lidl.es/h/aspiradoras/h10084470?offset=48",
              "https://www.lidl.es/c/bricolaje-y-jardin/s10067761",
              "https://www.lidl.es/c/aprender-jugando-vale-la-pena/a10106306"
            ],
            "items": {
              "type": "string"
            }
          },
          "maxPages": {
            "title": "Max search pages",
            "minimum": 0,
            "type": "integer",
            "description": "Stop after fetching this many result pages. Leave empty for no limit -- the run stops at Max products total."
          },
          "maxItems": {
            "title": "Max products total",
            "minimum": 0,
            "maximum": 1000000,
            "type": "integer",
            "description": "Hard cap on total products returned across the run (maximum 1,000,000; 0 is read as that maximum). Also bounded by Max search pages.",
            "default": 20
          },
          "fetchDetails": {
            "title": "Fetch shopper reviews",
            "type": "boolean",
            "description": "Adds the site's own full review feed (rating breakdown, star histogram, per-review text/author/votes) for each product. Current price, was-price, unit price, images, description and the rating summary are already included without this toggle. Always on for a pasted product URL.",
            "default": false
          },
          "maxReviewsPerProduct": {
            "title": "Max reviews per product",
            "minimum": 1,
            "maximum": 100,
            "type": "integer",
            "description": "How many shopper reviews to return per product when reviews are fetched (highest-rated first). Between 1 and 100.",
            "default": 20
          },
          "proxy": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Apify Proxy configuration used to route requests. The default works out of the box.",
            "default": {
              "useApifyProxy": true
            }
          },
          "resumeFromRunId": {
            "title": "Resume from a previous run (delta)",
            "type": "string",
            "description": "Optional. ID of a previous run of this actor (or a dataset ID). Products already in that dataset are skipped, so this run returns only NEW products (a delta); skipped products are not charged. Combine both runs' datasets for the full set. Max products then counts only the new products. A resumed run never marks products as expired. For recurring monitoring of the same search, use Incremental mode below instead."
          },
          "incrementalMode": {
            "title": "Incremental mode (recurring monitoring)",
            "type": "boolean",
            "description": "Turn this on for daily or recurring monitoring. The first run returns all matching products as NEW. Later runs compare every product against the last run (price, was price and discount, offer flag, online availability and stock status, title, brand, category, package format, description, badges and product link) and return only NEW, UPDATED and REAPPEARED products, with an UPDATED row's changedFields naming exactly what moved. Shopper ratings, review counts, the review feed and the image list are never compared, since those change on their own with no real product change; they stay in the rows you receive. Turn on \"Emit unchanged\" or \"Emit expired\" only when you also want those products returned (and billed). Max products counts returned rows only, so a recurring run walks the whole search to find changes. State is kept separately for each search/URL/filter setup; use State key to name or deliberately share a campaign.",
            "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 let the actor derive a key automatically from the search/URL and filter settings; different setups then never mix state with each other."
          },
          "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 extra rows you already have, so leave it off unless you specifically want the full snapshot every run.",
            "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 listed, marked EXPIRED. Only produced after a complete scan of the tracked search or URLs: never when Max products or Max search pages stopped it early, for a pasted department listing page, or when the state key was last used with different filters. EXPIRED means the product dropped out of the listing; without a detail check a listing drop and a delisting look the same, so read stock status from onlineAvailable and stockAvailability. This returns and bills extra rows, so leave it off unless you need expiry tracking.",
            "default": false
          },
          "changeScope": {
            "title": "What counts as a change (incremental mode only)",
            "enum": [
              "all",
              "priceAndStock"
            ],
            "type": "string",
            "description": "All fields (default): any change to the product record, except the always-ignored rating, review and image fields, returns an UPDATED row. Price and availability only: only a change to price, was price, discount, offer flag, online availability or stock status returns an UPDATED row; descriptions, titles, badges and other details never do. Changing this on a search with no State key starts a new automatic baseline (first run returns every product as NEW), so set a State key to keep your baseline.",
            "default": "all"
          },
          "compactUpdates": {
            "title": "Compact update rows (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. When on, UPDATED (and EXPIRED) rows are short: product id, title, link, current price and availability, plus priceChanges showing the old and new value of each moved price or availability field. NEW rows always carry the complete product record. Shopper reviews are not included in compact rows and are not billed for them.",
            "default": false
          },
          "expireAfterMissedScans": {
            "title": "Expire after N missed full scans (incremental mode only)",
            "minimum": 1,
            "maximum": 30,
            "type": "integer",
            "description": "Only used with Emit expired products. A product is marked EXPIRED only after it has been missing from this many complete scans in a row (default 1). Raise it (e.g. 3) so a product that briefly drops out of the listing is not reported as gone. A product that comes back resets the count.",
            "default": 1
          },
          "ignoreFieldsForChanges": {
            "title": "Ignore fields when detecting changes (incremental mode only)",
            "type": "array",
            "description": "Optional. Field names to exclude from UPDATED change detection, in addition to the built-in handling (ratings, review counts, the review feed and the image list never trigger an UPDATED). Use this if another field in your setup turns out to be noisy, e.g. promoLabel or badges. Changing this on a search with no State key starts a new automatic baseline.",
            "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}