Lieferando Menu Scraper - Restaurant Menus, Prices & Delivery avatar

Lieferando Menu Scraper - Restaurant Menus, Prices & Delivery

Pricing

from $0.70 / 1,000 restaurant or menu results

Go to Apify Store
Lieferando Menu Scraper - Restaurant Menus, Prices & Delivery

Lieferando Menu Scraper - Restaurant Menus, Prices & Delivery

Scrape restaurant menus and dish prices from Lieferando.de, Germany's largest food delivery platform: menu, price, delivery fee and minimum order per German postcode, 90-day price history, postcode price matrix and a run-over-run menu change digest. Unofficial, independent tool.

Pricing

from $0.70 / 1,000 restaurant or menu results

Rating

0.0

(0)

Developer

Kamer Ozkan

Kamer Ozkan

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

1

Monthly active users

6 days ago

Last modified

Share

Unofficial Actor: This Actor accesses publicly displayed data from Lieferando.de. It is not affiliated with, endorsed by, or sponsored by Lieferando or Just Eat Takeaway.com.

Lieferando menu scraper and price intelligence for the German food-delivery market: enter German postal codes (or direct menu URLs) and get every restaurant's full menu with dish prices, delivery fee, minimum order, delivery time, rating, opening hours and location as JSON rows - plus the analysis layers a pricing team actually uses: normalized comparable products, a postcode price matrix, 90-day price history and menu inflation per restaurant, and a run-over-run menu change digest (price increases and decreases, new and removed dishes, availability and delivery-term changes).

Built for restaurant chains and franchise operators, delivery-market analysts, food brands, and data teams; it observes public menu pages, never places orders.

What you can build with it

🔔 1. A competitor menu watch that tells you what changed overnight

Add a fixed competitor set as direct menu URLs (or a postcode), schedule the run daily with history and the change digest switched on. Each restaurant is compared with its previous snapshot; the digest lists price increases and decreases with percentages, new and removed dishes, availability flips, and delivery-fee or minimum-order changes, restaurant by restaurant.

{
"postalCodes": ["10115"],
"maxRestaurantsPerPostalCode": 25,
"trackPriceHistory": true,
"generateAnalytics": true,
"generateChangeDigest": true
}

🗺️ 2. A postcode price matrix for the same chain

Run several postal codes and read postcode_price_matrix rows: the same comparable product (size-, quantity- and variant-aware) across branches with min, average, max price and EUR/percent spread. Franchise pricing consistency in one table, exported to CSV.

📈 3. Menu inflation tracking per restaurant

With trackPriceHistory, every menu row carries its 90-day observations and change, and menu_inflation_summary rows report the comparable-basket change per restaurant (unavailable items excluded, not carried at stale prices).

📦 4. Clean menu data for apps, analytics, and AI agents

Menus normalized with German semantic rules (Döner Kebab, Doener Kebap, DONER map to one canonical product), explainable cuisine inference when metadata is missing, and an agent-readable schema: the Actor runs through the Apify API, Make, n8n, and MCP with the same billing.

Set generateChangeDigest: true (with trackPriceHistory on, the default). The run stores three records in its key-value store once at least one restaurant could be compared or observed for the first time:

RecordContent
MENU_CHANGE_DIGESTJSON: restaurants compared, restaurants with changes, totals (price up/down, new, removed, availability, delivery terms), per-restaurant change lists, next steps
MENU_CHANGE_DIGEST.htmlPrintable page with a table per restaurant
MENU_CHANGE_DIGEST.txtPlain-text digest for email or Slack

Restaurants with changes also get a menu_change_summary dataset row (billed as a normal result row). A restaurant's first observation creates its snapshot and is compared from the next run on; run_summary.changeDigest records whether the digest was stored and how it was billed.

Pricing and cost examples

Pay-per-event. Prices below are the FREE-tier rates effective 16 September 2026 (until 15 September 2026 the live price is $0.001 per result row with a negligible start fee). Paid Apify plans get automatic tier discounts of up to 30%. Residential proxy traffic is billed separately by Apify.

EventPriceNotes
📄 Result row (result-emitted)$0.003 ($3 per 1,000)Menu items, restaurant rows, matrices, inflation summaries, change summaries, run summary
🔔 Menu change digest (menu-change-digest)$0.10Once per run when requested; priced from 16 September 2026, included free until then
▶️ Actor start$0.005 per GBOnce per run

Worked examples at the 16 September prices (before proxy usage):

  • One postcode, 2 restaurants, full menus (~80 rows with analytics): ≈ $0.25
  • Daily competitor watch, 10 restaurants, ~400 rows, with the change digest: ≈ $1.30 per run → ≈ $39 per month
  • Weekly city scan, 3 postcodes x 25 restaurants, ~3,000 rows: ≈ $9 per run → ≈ $39 per month

A failed run produces no result charges; the Actor stops before your maximum charge per run is exceeded.

Included intelligence

  • complete menu rows with product name, description, category, price, availability, image, and source ID
  • delivery fee, minimum order, delivery time, rating, offer, address, coordinates, and opening hours
  • published cuisine labels plus explainable menu-based cuisine inference when metadata is missing
  • stable chain identity for comparing the same restaurant group across branches
  • semantic product normalization that maps spelling variants such as Döner Kebab, Doener Kebap, and DONER
  • optional custom alias mappings for market- or brand-specific product language
  • size-, quantity-, dietary-, and variant-aware comparable product IDs to avoid false matches
  • postcode price matrix with min/average/max price, branches, EUR spread, and percentage spread
  • per-item rolling 90-day observations, EUR change, and percentage change
  • restaurant-level 90-day menu-basket inflation summaries
  • HTML intelligence dashboard plus CSV and JSON exports
  • session rotation, blocked-request recovery, run-quality scoring, optional HTTPS alerts, and optional failure on degraded data

Outputs

The default dataset contains six record types:

recordTypePurpose
menu_itemOne current menu product with branch, location, normalization, and 90-day history
restaurantRestaurant-level fallback row when menus are disabled or empty
postcode_price_matrixSame chain and comparable product summarized across postal codes
menu_inflation_summaryCurrent versus first retained comparable menu basket
menu_change_summaryWhat changed for one restaurant since its previous snapshot: price moves, new and removed items, availability, delivery terms (only when something changed)
run_summaryCoverage, failure rates, quality metrics, issues, and final status

The default key-value store also contains:

  • REPORT.html - visual executive report
  • POSTCODE_PRICE_MATRIX.csv - spreadsheet-ready postcode comparison
  • ANALYTICS.json - matrix and inflation data
  • RUN_SUMMARY.json - monitoring payload
  • SCHEDULE_RECOMMENDATION.json - daily production schedule template
  • MENU_CHANGE_DIGEST / .html / .txt - run-over-run change digest (when generateChangeDigest is on)

Example output

All records below are unedited output from live runs on 2026-07-28. The Actor emits four record types into one dataset: menu_item, postcode_price_matrix, menu_inflation_summary, and run_summary.

1. A restaurant listing with its live offer (menu_item)

A real Berlin listing: parsed delivery economics (fee, minimum, time window), structured address and coordinates, cuisine classification with confidence and source, and the running promotion exactly as the platform shows it. Fields the source does not publish stay null.

2. Every run audits itself (run_summary and menu_inflation_summary)

The run reports its own quality instead of asking to be trusted: request failure and retry rates, the share of items with missing prices, cuisine classification coverage, and exactly how many results were charged. A run that fails its quality thresholds says so in issues rather than shipping silently bad data.

{
"recordType": "run_summary",
"observedAt": "2026-07-28T12:27:40.624Z",
"completedAt": "2026-07-28T12:29:09.422Z",
"status": "healthy",
"expectedPostalCodes": [
"10115"
],
"resolvedPostalCodes": [
"10115"
],
"requestedRestaurantLimit": 2,
"discoveredRestaurantCount": 2,
"scrapedRestaurantCount": 2,
"menuItemCount": 79,
"unavailableItemCount": 7,
"matrixRowCount": 72,
"crossPostcodeMatrixRowCount": 0,
"inflationSummaryCount": 2,
"failedRequestCount": 0,
"failedRequestRate": 0,
"retriedRequestCount": 0,
"totalRetryCount": 0,
"retryRate": 0,
"nullPriceRate": 0,
"cuisineCoverage": 1,
"averageMenuItemsPerRestaurant": 39.5,
"smallMenuRestaurantCount": 0,
"issues": [],
"failures": [],
"chargedResultCount": 79,
"stoppedBySpendingLimit": false
}

The inflation basket is honest about its composition: unavailable items are excluded from the tracked basket instead of being carried at stale prices, and the record shows that accounting (41 items on the menu, 6 unavailable, 35 tracked).

{
"recordType": "menu_inflation_summary",
"observedAt": "2026-07-28T12:27:40.624Z",
"searchPostalCode": "10115",
"chainKey": "lieferando:burgermeister",
"chainName": "Burgermeister",
"restaurantName": "Burgermeister Eberswalder",
"restaurantUrl": "https://www.lieferando.de/en/menu/burgermeister-5?c_id=019f37d0-05cc-7243-9430-de2821818e9a",
"menuItemCount": 41,
"unavailableItemCount": 6,
"trackedItemCount": 35,
"changedItemCount": 0,
"increasedItemCount": 0,
"decreasedItemCount": 0,
"unchangedItemCount": 35,
"currentComparableBasket": 267.84,
"firstComparableBasket": 267.84,
"menuInflation90d": 0,
"medianItemChangePercent90d": 0,
"maxItemIncreasePercent90d": null,
"maxItemDecreasePercent90d": null
}

3. Cross-postcode price comparison (postcode_price_matrix)

The same comparable product is matched across postcodes with per-postcode min, average, and max plus the contributing branches. In this real observation both areas were served at identical prices, so the spread is reported as exactly zero: the matrix reports no difference when there is none, which is what makes a nonzero spread trustworthy.

Pricing

See "Pricing and cost examples" at the top of this page: one result-emitted event per delivered row (menu items, matrices, summaries and change summaries alike), a small Actor start fee, and the optional menu-change-digest event once per run when requested. A failed run produces no result charges.

This Actor is also exposed to AI agents through Apify's MCP server (mcp.apify.com): an agent can discover it by search and run it with the same pay-per-event billing, with no separate integration.

Run locally

npm install
npm run typecheck
npm test
npm run build
npm start

Copy examples/production-input.json to storage/key_value_stores/default/INPUT.json before npm start. For a short smoke test, reduce postalCodes to one value and maxRestaurantsPerPostalCode to 1.

Production use

Use the input in examples/production-input.json, keep the same named key-value store between runs, and create a daily Apify schedule. Full scheduling, alerting, output, and retention guidance is in docs/production.md.

For a fixed competitor set, add Lieferando menu URLs to restaurantUrls. Direct URLs can be collected without a search-postcode context, but postcode matrices require postcode-routed discovery.

Lieferando blocks data-center and direct Apify cloud IPs. The Actor therefore defaults to a German residential Apify Proxy profile, which is billed separately by Apify. The proxy settings remain visible and editable in the Actor input.

Comparison behavior

canonicalProductId represents the normalized semantic product. comparableProductId adds size, quantity, dietary, and variant attributes, so a 0.33 L cola is not compared with a 1 L cola.

Matrix rows are keyed by chain plus comparableProductId. A cross-postcode match therefore requires at least two input postal codes and an overlapping chain/product combination. Every source branch remains listed in the matrix cell for auditability.

Price history is keyed by postal code, branch, and Lieferando source product ID in the named store lieferando-price-history-v1. Repeated runs retain 90 days and append at most one unchanged observation per day. A first run has no earlier baseline, so change fields remain null until a later run supplies one.

customProductAliases can extend the built-in German rules without a code change. Aliases are applied safely as normalized phrases; size and quantity safeguards remain part of comparableProductId.

Publish

The Actor definition, Store README, deterministic Docker build, input/output schemas, dataset view, resource limits, and changelog are included. Deploy the folder with apify push or connect it as the Actor source in Apify Console, complete the account-owned Store display fields, and click Publish to Store.

Responsible operation

Use conservative concurrency, respect applicable law and platform terms, and avoid collecting personal or account data. The Actor only reads publicly displayed restaurant and menu information.