# Lidl Scraper (`parsebird/lidl-scraper`) Actor

Scrape Lidl products and prices from 32 country sites: price, normal price, unit price, Lidl Plus price, discounts, stock, ratings, category and images. Full catalog or keyword search, with price-change monitoring.

- **URL**: https://apify.com/parsebird/lidl-scraper.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.49 / 1,000 products

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?

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

### Lidl Scraper

Lidl Scraper extracts product and price data from Lidl's online shops in 32 countries, from Germany, France and the UK to Poland, Italy and the US, by keyword search or as a full national catalog.

<table><tr>
<td style="border-left:4px solid #0050AA;padding:12px 16px;font-weight:600">
Get the current price, struck-through normal price, unit price, Lidl Plus app price, discount, stock, rating, category, images and product link for every Lidl product, filter by category, brand, price or offers, and output only the prices that changed since your last run.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```text
Lidl Scraper (Apify actor parsebird/lidl-scraper) scrapes products and prices from Lidl country websites via their site search: DE lidl.de, FR lidl.fr, GB lidl.co.uk, PL lidl.pl, IT lidl.it, ES lidl.es, NL lidl.nl, BE lidl.be, AT lidl.at, CH lidl.ch, CZ lidl.cz, SK lidl.sk, HU lidl.hu, PT lidl.pt, IE lidl.ie, XI lidl-ni.co.uk (Northern Ireland), SE lidl.se, DK lidl.dk, FI lidl.fi, BG lidl.bg, RO lidl.ro, HR lidl.hr, SI lidl.si, GR lidl-hellas.gr, CY lidl.com.cy, MT lidl.com.mt, LT lidl.lt, LV lidl.lv, EE lidl.ee, RS lidl.rs, LU lidl.lu, US lidl.com. Call it with the Apify API client: client.actor("parsebird/lidl-scraper").call(run_input={"countries": ["DE"], "query": "milch", "maxResults": 50}). Inputs: countries (array of country codes above, default ["DE"]); query (string keyword in the site's language, empty = whole catalog); maxResults (integer per country, default 200, 0 = no limit); category (string, category name or path in the site's language, e.g. "Essen & Trinken" or "Essen & Trinken/Wein, Bier & Spirituosen"); brands (array of brand names, OR); minPrice, maxPrice (numbers, local currency); onlyOffers, inStockOnly, newOnly (booleans); assortment ("all", "store", "online"); sortBy ("relevance", "price_asc", "price_desc", "newest", "rating", "bestseller", "discount"); language ("default", or "fr"/"nl" for BE, "de"/"fr"/"it" for CH, "en"/"el" for CY); compact (boolean, core fields only); incrementalMode (boolean), stateKey (string), emitUnchanged (boolean), emitExpired (boolean, needs empty query); proxyConfiguration (optional). Output: one row per product with country, countryName, language, productId, erpNumber, ian, ians, name, title, brand, category, categories, price, priceNormal, recommendedPrice, isOnOffer, discountPercent, discountAmount, discountText, discountFromRecommendedPrice, currency, secondaryCurrency, unitPrice, unitPriceUnit, unitPriceText, packageAmount, packageUnit, packagingText, lidlPlusPrice, lidlPlusOldPrice, lidlPlusLabel, lidlPlusDetails, priceValidFrom, priceValidUntil, isOnline, isInStore, inStoreNow, onlineAvailable, inStock, availability, availabilityText, availabilityBadges, deliveryCost, rating, ratingCount, ribbons, attributes, ageRestricted, productType, description, imageUrl, images, url, searchQuery, scrapedAt, and in incremental mode changeType (NEW, UPDATED, UNCHANGED, REAPPEARED, EXPIRED), firstSeenAt, lastSeenAt, previousPrice, expiredAt. API docs: https://apify.com/parsebird/lidl-scraper/api. Get a token: https://console.apify.com/settings/integrations
```

### What is Lidl Scraper?

**Lidl Scraper** turns [Lidl](https://www.lidl.com/)'s country websites into structured product data. Pick one or more countries, type a keyword such as `milch`, `kaffee` or `parkside`, or leave the search empty to get **the whole national assortment**. Each product comes back with its **current price, normal price, unit price (per kg or litre), Lidl Plus price, discount, stock status, rating, category path, images and product page link**.

It works as a **Lidl API** alternative: no account, no login, no browser. To try it, keep the example input (Germany, `milch`, 50 products), click **Start**, and download your Lidl product data as JSON, CSV or Excel a few seconds later.

### What can Lidl Scraper do?

- 🌍 **32 Lidl country sites in one actor.** Germany, France, Poland, Spain, the Netherlands, Belgium, Czechia and Slovakia run full online shops. The other sites list their in-store weekly offers and store assortment.
- 🔎 **Search by keyword or scrape whole catalogs.** An empty search returns every product a country lists. Lidl's site search stops at 10,000 products, so bigger catalogs (Germany, Czechia, Slovakia) are split into price ranges automatically and you still get all of them.
- 🏷️ **Filter like the shop.** Category (by name, in the site's language), brand, price range, offers only, in stock only, new products only, and sold in stores or sold online.
- 💶 **All the prices Lidl shows.** Current price, struck-through normal price, recommended retail price, discount, unit price, pack size, and the **Lidl Plus** app price with its conditions.
- 🔔 **Price monitoring.** Incremental mode compares with your previous run and outputs only products that are new, changed price, offer or stock, or came back. Products that disappeared can be reported as expired.
- 🗣️ **Languages.** Belgium in Dutch or French, Switzerland in German, French or Italian, Cyprus in English or Greek.
- 🤖 **Compact output** with only the shopping essentials, for AI agents, spreadsheets and dashboards.

As an Apify Actor it also gives you [scheduling](https://docs.apify.com/platform/schedules) for daily or weekly price tracking, a [REST API](https://docs.apify.com/api/v2), [integrations](https://apify.com/integrations) with Google Sheets, Zapier, Make, Slack and webhooks, and exports to JSON, CSV, Excel, XML and HTML.

### Which Lidl countries can you scrape?

Product counts are what each site listed when we tested on 28 October 2026. Lidl changes its range every week.

| Code | Site | Type | Products |
|------|------|------|----------|
| `DE` | [lidl.de](https://www.lidl.de/) | Online shop + stores | ~12,800 |
| `CZ` | [lidl.cz](https://www.lidl.cz/) | Online shop + stores | over 10,000 |
| `SK` | [lidl.sk](https://www.lidl.sk/) | Online shop + stores | over 10,000 |
| `NL` | [lidl.nl](https://www.lidl.nl/) | Online shop + stores | ~9,600 |
| `FR` | [lidl.fr](https://www.lidl.fr/) | Online shop + stores | ~9,500 |
| `BE` | [lidl.be](https://www.lidl.be/) | Online shop + stores | ~8,800 |
| `PL` | [lidl.pl](https://www.lidl.pl/) | Online shop + stores | ~8,600 |
| `ES` | [lidl.es](https://www.lidl.es/) | Online shop + stores | ~6,200 |
| `US` | [lidl.com](https://www.lidl.com/) | Store products | ~4,200 |
| `HU` | [lidl.hu](https://www.lidl.hu/) | Store products | ~980 |
| `CH` | [lidl.ch](https://www.lidl.ch/) | Store products | ~890 |
| `RS` | [lidl.rs](https://www.lidl.rs/) | Store products | ~780 |
| `BG` | [lidl.bg](https://www.lidl.bg/) | Store products | ~660 |
| `GB` | [lidl.co.uk](https://www.lidl.co.uk/) | Store products | ~570 |
| `SI` | [lidl.si](https://www.lidl.si/) | Store products | ~500 |
| `CY` | [lidl.com.cy](https://www.lidl.com.cy/) | Store products | ~460 |
| `IT` | [lidl.it](https://www.lidl.it/) | Store products | ~410 |
| `SE` | [lidl.se](https://www.lidl.se/) | Store products | ~380 |
| `RO` | [lidl.ro](https://www.lidl.ro/) | Store products | ~370 |
| `GR` | [lidl-hellas.gr](https://www.lidl-hellas.gr/) | Store products | ~370 |
| `AT` | [lidl.at](https://www.lidl.at/) | Store products | ~350 |
| `FI` | [lidl.fi](https://www.lidl.fi/) | Store products | ~340 |
| `HR` | [lidl.hr](https://www.lidl.hr/) | Store products | ~320 |
| `MT` | [lidl.com.mt](https://www.lidl.com.mt/) | Store products | ~320 |
| `IE` | [lidl.ie](https://www.lidl.ie/) | Store products | ~310 |
| `XI` | [lidl-ni.co.uk](https://www.lidl-ni.co.uk/) (Northern Ireland) | Store products | ~280 |
| `PT` | [lidl.pt](https://www.lidl.pt/) | Store products | ~210 |
| `DK` | [lidl.dk](https://www.lidl.dk/) | Store products | ~160 |
| `LT` | [lidl.lt](https://www.lidl.lt/) | Store products | ~50 |
| `LU` | [lidl.lu](https://www.lidl.lu/) | Store products | ~40 |
| `LV` | [lidl.lv](https://www.lidl.lv/) | Store products | ~40 |
| `EE` | [lidl.ee](https://www.lidl.ee/) | Store products | ~30 |

You can also type `UK` for Great Britain and `NI` for Northern Ireland.

### What data can you extract from Lidl?

In standard mode every row has all the fields below. A value Lidl doesn't show for that product is `null`, never left out.

| Field | Description |
|-------|-------------|
| `country`, `countryName`, `language` | Lidl site the row comes from and the language of its texts |
| `productId`, `erpNumber`, `ian`, `ians` | Lidl product number (the `p…` number in product URLs) and Lidl's IAN article numbers |
| `name`, `title`, `brand` | Full product name, name without brand, and brand |
| `category`, `categories` | Category path, as text and as a list |
| `price`, `priceNormal`, `recommendedPrice` | Current price, normal (struck-through) price, and recommended retail price when Lidl shows one |
| `isOnOffer`, `discountPercent`, `discountAmount`, `discountText` | Whether the product is discounted, and by how much |
| `unitPrice`, `unitPriceUnit`, `unitPriceText` | Price per kg, litre or piece, e.g. `1 l = 7.99` |
| `packageAmount`, `packageUnit`, `packagingText` | Pack size, e.g. `0.75` `l` or `2 l/опаковка` |
| `lidlPlusPrice`, `lidlPlusLabel`, `lidlPlusDetails` | Lidl Plus app price, its label (e.g. `SAVE £0.50`) and conditions (e.g. `Regular price £1.29`) |
| `priceValidFrom`, `priceValidUntil` | Start and end of the current price, when the site gives them |
| `isOnline`, `isInStore`, `inStoreNow`, `onlineAvailable`, `inStock` | Sales channel and stock status |
| `availability`, `availabilityText`, `availabilityBadges` | Lidl's availability labels with dates, e.g. `In store from 29.10` |
| `deliveryCost` | Standard delivery charge for online-shop products |
| `rating`, `ratingCount` | Average customer rating and number of ratings |
| `ribbons`, `attributes`, `ageRestricted` | Badges like "Top Kundenbewertungen", product attributes, age-restricted flag |
| `description` | Product highlights as plain text |
| `imageUrl`, `images`, `url` | Main image, all images, and product page link |
| `changeType`, `firstSeenAt`, `lastSeenAt`, `previousPrice`, `expiredAt` | Incremental mode only |

### How to scrape Lidl

1. Open [Lidl Scraper](https://apify.com/parsebird/lidl-scraper) in Apify Console and sign in (or create a free Apify account).
2. Pick one or more **Countries**, for example Germany.
3. Type a **Search keyword** in the site's language, such as `kaffee`, or leave it empty to scrape the whole catalog.
4. Optionally set a **Category**, **Brands**, a price range, or turn on **Offers only**.
5. Set **Max products per country** (`0` = no limit) and click **Start**.
6. When the run finishes, open the **Output** tab and export the data as JSON, CSV, Excel, XML or HTML, or fetch it through the API.

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `countries` | array | No | `["DE"]` | Lidl country codes, see the table above |
| `query` | string | No | — | Keyword in the site's language; empty = whole catalog |
| `maxResults` | integer | No | 200 | Products per country; `0` = no limit. In incremental mode: changed products per run |
| `category` | string | No | — | Category name or path in the site's language, e.g. `Food & Drink` or `Essen & Trinken/Wein, Bier & Spirituosen` |
| `brands` | array | No | — | Brand names, combined with OR |
| `minPrice`, `maxPrice` | number | No | — | Price range in local currency |
| `onlyOffers` | boolean | No | false | Only discounted products |
| `inStockOnly` | boolean | No | false | Leave out products sold out online |
| `newOnly` | boolean | No | false | Only products Lidl marks as new |
| `assortment` | string | No | `all` | `all`, `store` (sold in stores) or `online` (sold online) |
| `sortBy` | string | No | `relevance` | `relevance`, `price_asc`, `price_desc`, `newest`, `rating`, `bestseller`, `discount` |
| `language` | string | No | `default` | `fr`/`nl` for Belgium, `de`/`fr`/`it` for Switzerland, `en`/`el` for Cyprus |
| `compact` | boolean | No | false | Core fields only, same price |
| `incrementalMode` | boolean | No | false | Output only changes since the previous run |
| `stateKey` | string | No | auto | Name of the saved state, one per monitor |
| `emitUnchanged` | boolean | No | false | Also output unchanged products |
| `emitExpired` | boolean | No | false | Output products that disappeared (needs an empty keyword) |
| `proxyConfiguration` | object | No | none | Optional; the actor switches to Apify Proxy by itself if Lidl refuses requests |

**Examples**

Search a keyword in Germany:

```json
{ "countries": ["DE"], "query": "milch", "maxResults": 50 }
```

Full French catalog:

```json
{ "countries": ["FR"], "maxResults": 0 }
```

This week's discounted food in the UK and Ireland:

```json
{ "countries": ["GB", "IE"], "category": "Food & Drink", "onlyOffers": true, "maxResults": 0 }
```

Daily price monitor for Germany:

```json
{ "countries": ["DE"], "maxResults": 0, "incrementalMode": true, "stateKey": "lidl-de-tracker", "emitExpired": true }
```

### Output example

A discounted wine from lidl.de:

```json
{
  "country": "DE",
  "countryName": "Germany",
  "language": "de_DE",
  "productId": "100360529",
  "erpNumber": "100360529",
  "ian": "182721",
  "name": "ALMA MORA Select Reserve Malbec Argentinien trocken, Rotwein 2024",
  "brand": "ALMA MORA",
  "category": "Kategorien/Weinwelt/Weinart/Rotwein",
  "price": 5.99,
  "priceNormal": 9.99,
  "recommendedPrice": null,
  "isOnOffer": true,
  "discountPercent": 40.0,
  "discountAmount": 4.0,
  "currency": "EUR",
  "unitPrice": 7.99,
  "unitPriceUnit": "l",
  "unitPriceText": "1 l = 7.99",
  "packageAmount": 0.75,
  "packageUnit": "l",
  "lidlPlusPrice": null,
  "priceValidFrom": "2026-09-30T22:00Z",
  "priceValidUntil": "2026-10-31T22:59:59Z",
  "isOnline": true,
  "isInStore": false,
  "inStock": true,
  "availability": "AVAILABLE_ONLINE",
  "availabilityText": "lieferbar",
  "deliveryCost": 5.95,
  "rating": 4.7,
  "ratingCount": 3,
  "description": "Alma Mora Select Reserve Malbec — Kräftiger argentinischer Rotwein für Grillgerichte und deftige Speisen\n- Kräftige Fruchtaromen von Pflaume und Blaubeere\n- ...",
  "imageUrl": "https://www.lidl.de/assets/gcpdcffa2951620462cb69bc62d22d6815c.jpg",
  "url": "https://www.lidl.de/p/alma-mora-select-reserve-malbec-argentinien-trocken-rotwein-2024/p100360529",
  "scrapedAt": "2026-10-28T11:43:49.674Z"
}
```

An in-store product with a Lidl Plus price from lidl.co.uk:

```json
{
  "country": "GB",
  "productId": "11031007",
  "name": "Breadsticks",
  "category": "Food",
  "price": 0.99,
  "priceNormal": 0.99,
  "isOnOffer": false,
  "currency": "GBP",
  "lidlPlusPrice": 0.79,
  "lidlPlusLabel": "SAVE £0.50",
  "lidlPlusDetails": ["Regular price £1.29 (£7.37/kg)", "175 g | £3.95/kg"],
  "isOnline": false,
  "isInStore": true,
  "availability": "IN_STORE_FROM_DATE_FUTURE",
  "availabilityText": "In store from 29.10",
  "url": "https://www.lidl.co.uk/p/breadsticks/p11031007"
}
```

Rows are shortened here; the full row has every field from the data table.

### How to monitor Lidl prices with incremental mode

Turn on **Incremental mode** and give the monitor a **State key** such as `lidl-de-tracker`. Then schedule the run daily or weekly.

- The first run outputs every product as `NEW` and saves its state.
- Later runs read the same selection again and output only products that are `NEW`, `UPDATED` (price, normal price, offer, discount, unit price, Lidl Plus price, offer end date or stock changed) or `REAPPEARED`. `UPDATED` rows include `previousPrice`.
- With an empty keyword and **Output expired products** on, products that are gone are output once as `EXPIRED`.
- **Max products per country** caps how many changed products one run outputs. The rest come out in the next runs.
- State is saved per country and per state key, so one key can track several countries.

### Use cases

- **Grocery price monitoring.** Track Lidl's prices and offers in one or several countries every day.
- **Competitor analysis for retailers.** Compare your prices with Lidl's on the same brands and categories.
- **Weekly offers tracking.** Collect each week's in-store offers and Lidl Plus deals from the UK, Ireland, Italy or any other country.
- **Price-per-unit research.** Use unit prices to compare products and pack sizes across countries.
- **Market and inflation research.** Build a history of shelf prices across 32 European and US markets.
- **Product catalogs and feeds.** Get names, images, descriptions and categories for comparison sites and apps.

### How does Lidl Scraper work?

1. For each country it calls the Lidl site's own product search, the one behind the search box on lidl.de, lidl.fr and the other sites, and reads 60 products per request.
2. Categories, brands, price ranges and "new" are passed to the site's search filters, so only matching products are downloaded.
3. When a selection has more than 10,000 products, the most Lidl's search will page through, it is split into price ranges that each fit, and the parts are joined without duplicates.
4. Each product is converted into one flat row with the same fields in every country.
5. In incremental mode, each product's prices and stock are compared with the saved state from the previous run.

On the Apify platform a full German catalog (about 12,800 products) takes about 6 minutes, the French catalog about 3 minutes, and a keyword search a few seconds.

### How much does it cost to scrape Lidl?

Lidl Scraper uses pay-per-event pricing. You pay for each product row saved to your dataset, and compute and proxy costs are included in the event price.

| Event | Free plan | Bronze | Silver | Gold |
|-------|-----------|--------|--------|------|
| Product (per 1,000) | **$1.99** | **$1.79** | **$1.59** | **$1.49** |

What that means in practice, on the free plan:

- 50 products for a keyword: about **$0.10**
- All UK store products listed on lidl.co.uk (~570): about **$1.13**
- The whole German catalog (~12,800 products): about **$25.47**
- Incremental mode: you pay only for the changed products a run outputs, not for every product it checks.

Compact mode has the same price. You can set a maximum cost per run in Apify Console; the actor stops when it is reached. Apify's free plan comes with monthly platform credit you can spend on this actor.

### How to use the Lidl API with Python and JavaScript

Use the [Apify API](https://docs.apify.com/api/v2) with the official clients. Get your token in [Console → Settings → Integrations](https://console.apify.com/settings/integrations).

**Python** ([apify-client](https://docs.apify.com/api/client/python/)):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("parsebird/lidl-scraper").call(run_input={
    "countries": ["DE", "FR"],
    "query": "kaffee",
    "maxResults": 100,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["country"], item["name"], item["price"], item["unitPriceText"])
```

**JavaScript** ([apify-client](https://docs.apify.com/api/client/js/)):

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('parsebird/lidl-scraper').call({
    countries: ['GB'],
    onlyOffers: true,
    maxResults: 0,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((p) => console.log(p.name, p.price, p.lidlPlusPrice));
```

The full API reference for this actor is on the [API tab](https://apify.com/parsebird/lidl-scraper/api). Results can also go straight to [Google Sheets](https://apify.com/integrations), Zapier, Make, Slack or your own webhook after each run.

### Is it legal to scrape Lidl?

Lidl Scraper only collects public product information that anyone can see on Lidl's websites without logging in: product names, prices, availability and images. It does not collect personal data. Web scraping of publicly available data is generally legal, but you should check the website's terms of use and the laws that apply to you, especially if you plan to republish the data. Read more in Apify's article [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

### Other grocery and retail scrapers

| Actor | What it scrapes |
|-------|-----------------|
| [Tesco UK & Ireland Scraper](https://apify.com/parsebird/tesco-scraper) | Tesco grocery products and Clubcard prices |
| [ALDI Australia Scraper](https://apify.com/parsebird/aldi-australia-scraper) | ALDI Australia products and prices |
| [Carrefour MAF Scraper](https://apify.com/parsebird/carrefour-maf-scraper) | Carrefour and HyperMax stores in the Middle East, Africa and Asia |
| [Walmart Product Scraper](https://apify.com/parsebird/walmart-product-scraper) | Walmart products and prices |
| [Target Product Scraper](https://apify.com/parsebird/target-product-scraper) | Target products and prices |
| [BAUHAUS Product Scraper](https://apify.com/parsebird/bauhaus-product-scraper) | BAUHAUS DIY products and prices |

### FAQ

**Do I need a Lidl account or the Lidl Plus app?**
No. The actor reads the public websites. Lidl Plus prices are shown on the sites, so they are included without an account.

**Why does my country return only a few hundred products?**
Outside Germany, France, Poland, Spain, the Netherlands, Belgium, Czechia and Slovakia, Lidl's websites don't run an online shop. They show the current and upcoming in-store offers and part of the store range, so that's what the actor returns.

**What language should my keyword and category be in?**
The site's language: `milch` on lidl.de, `lait` on lidl.fr, `milk` on lidl.co.uk. If a category name isn't found, the log lists that site's main categories. Lidl's search also matches related products, the same way the site's search box does.

**What's the difference between `price`, `priceNormal` and `lidlPlusPrice`?**
`price` is what everyone pays today. `priceNormal` is the struck-through price when the product is discounted, otherwise the same as `price`. `lidlPlusPrice` is the price with the Lidl Plus app. Some in-store offers (for example in the UK, Italy and Poland) only have a Lidl Plus price, so `price` is `null` and the regular price, when the site shows it, is in `lidlPlusDetails`.

**Is `ian` the product's EAN barcode?**
No. `ian` is Lidl's own article number (IAN), which Lidl prints on products and in recall notices. The product search doesn't include EAN/GTIN barcodes, so the actor doesn't output them.

**Can I scrape several countries in one run?**
Yes. Add several codes to **Countries**. **Max products per country** applies to each one, and every row has its `country`.

**Why is the order slightly different from the website?**
Within a sort order, Lidl sorts product groups and bundles by its own reference price. For catalogs over 10,000 products the actor reads one price range at a time, so `relevance` order applies within each range.

**Can I run it on a schedule?**
Yes. Create a [schedule](https://docs.apify.com/platform/schedules) in Apify Console, for example every morning, and combine it with incremental mode to get only the changes.

**Something doesn't work or a field is missing. What should I do?**
Open an issue on the [Issues tab](https://apify.com/parsebird/lidl-scraper/issues) with the input you used. We read every report.

# Changelog

This Actor's version history is a separate document: https://apify.com/parsebird/lidl-scraper/changelog.md

# Actor input Schema

## `countries` (type: `array`):

Pick one or more Lidl country sites. Each product row is tagged with its country code. Germany, France, Poland, Spain, the Netherlands, Belgium, Czechia and Slovakia run full online shops; the other sites list their in-store weekly offers and assortment.

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

Search product names and brands, in the site's language, such as <code>milch</code>, <code>kaffee</code> or <code>parkside</code>. Leave empty to scrape the whole catalog of each country.

## `maxResults` (type: `integer`):

Maximum products to save from each country. Use <code>0</code> for no limit (a full catalog is a few hundred to about 13,000 products). In incremental mode this limits how many changed products one run outputs per country; the rest follow in the next runs.

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

Only return products from this category, in the site's language, such as <code>Essen & Trinken</code> on lidl.de or <code>Food & Drink</code> on lidl.co.uk. A main category or one level below works by name; use a path like <code>Essen & Trinken/Wein, Bier & Spirituosen</code> to go deeper. Unknown names are reported in the log with the main categories of that site.

## `brands` (type: `array`):

Only return products from these brands, such as <code>PARKSIDE</code> or <code>SILVERCREST</code>. Several brands are combined with OR.

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

Only return products at or above this price, in the country's currency.

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

Only return products at or below this price, in the country's currency.

## `onlyOffers` (type: `boolean`):

Only return products with a current discount (a struck-through normal price or recommended retail price).

## `inStockOnly` (type: `boolean`):

Leave out products flagged as sold out online.

## `newOnly` (type: `boolean`):

Only return products the site marks as new. Sites that don't flag new products (lidl.com in the US) are skipped when this is on.

## `assortment` (type: `string`):

Keep only products sold in Lidl stores (now or in an announced in-store week), or only products orderable in the online shop. Most country sites outside DE, FR, PL, ES, NL, BE, CZ and SK list store products only.

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

Order in which products are read. It decides which products you get when Max products cuts the list short.

## `language` (type: `string`):

Language of names, categories and descriptions for multilingual sites: Belgium (Dutch or French), Switzerland (German, French or Italian) and Cyprus (English or Greek). Other countries always use their own language.

## `compact` (type: `boolean`):

Keep only the shopping essentials: country, product ID, name, brand, price, normal price, unit price, currency, offer flag, discount, Lidl Plus price, stock, image and product link. Same number of rows, same price.

## `incrementalMode` (type: `boolean`):

Read the whole selection and output only products that are NEW, UPDATED (price, offer, stock or unit price changed) or REAPPEARED since the previous run with the same state key. With an empty search keyword, products that disappeared can also be reported as EXPIRED. State is kept per country.

## `stateKey` (type: `string`):

Name of the saved state to compare against, such as <code>lidl-de-tracker</code>. Use a different key for each monitor. Leave empty to derive one from your search and filters.

## `emitUnchanged` (type: `boolean`):

Also output products that did not change, with changeType UNCHANGED.

## `emitExpired` (type: `boolean`):

Output products that were in the previous run but are gone now, with changeType EXPIRED. Only works when the search keyword is empty.

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

Optional. The actor works without a proxy and switches to Apify Proxy by itself if Lidl starts refusing requests.

## Actor input object example

```json
{
  "countries": [
    "DE"
  ],
  "query": "milch",
  "maxResults": 50,
  "onlyOffers": false,
  "inStockOnly": false,
  "newOnly": false,
  "assortment": "all",
  "sortBy": "relevance",
  "language": "default",
  "compact": false,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "countries": [
        "DE"
    ],
    "query": "milch",
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/lidl-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 = {
    "countries": ["DE"],
    "query": "milch",
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/lidl-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 '{
  "countries": [
    "DE"
  ],
  "query": "milch",
  "maxResults": 50
}' |
apify call parsebird/lidl-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parsebird/lidl-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/3pVOgOs5fJAhV9FNa/builds/GcoY8XLVOhhhUpAc1/openapi.json
