Lieferando Menu Scraper - Restaurant Menus, Prices & Delivery
Pricing
from $2.10 / 1,000 restaurant or menu results
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 $2.10 / 1,000 restaurant or menu results
Rating
0.0
(0)
Developer
Kamer Ozkan
Maintained by CommunityActor stats
0
Bookmarked
5
Total users
1
Monthly active users
4 days ago
Last modified
Categories
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 collect public restaurant and menu observations within your configured limits, with available dish prices, delivery fees, minimum orders, delivery times, ratings, opening hours and locations 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.
Menu change digest
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:
| Record | Content |
|---|---|
MENU_CHANGE_DIGEST | JSON: restaurants compared, restaurants with changes, totals (price up/down, new, removed, availability, delivery terms), per-restaurant change lists, next steps |
MENU_CHANGE_DIGEST.html | Printable page with a table per restaurant |
MENU_CHANGE_DIGEST.txt | Plain-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. These are the active Free-tier event prices checked on October 6, 2026. Paid plans receive the discounts shown on the Pricing tab. The current Pricing tab shows platform costs included, including the Actor's Apify proxy usage.
| Event or output | Free-tier price | Notes |
|---|---|---|
Result row (result-emitted) | $0.003 ($3 per 1,000) | Delivered menu items, restaurant fallback rows and menu-change summary rows |
| Analytics and run summaries | No separate event charge | Postcode matrices, inflation summaries and the run summary are stored without a result event |
| Requested menu change digest | No separate event charge | The active pricing has no menu-change-digest event; a stored digest is marked UNPRICED_FREE |
Actor start (apify-actor-start) | $0.005 per GB | Minimum one event; default 2 GB memory adds $0.01 |
Event-charge examples at the checked Free rate and default 2 GB memory:
- 80 delivered billable rows:
$0.01 + (80 x $0.003) = $0.25. - 400 billable rows per run:
$1.21, or$36.30for 30 such runs. Free analytics rows and the currently unpriced digest do not add events. - 3,000 billable rows per run:
$9.01; four such runs cost$36.04.
These calculations use billable rows, not the total dataset count, restaurant count or
claimed complete menus. Actual row counts and source coverage vary. A run that later
fails or is aborted can retain earlier delivered and charged rows; a failure does not
promise a refund. Inspect RUN_SUMMARY.json.chargedResultCount and the run's charged events.
The Actor checks the remaining event allowance before another billable result. The run
charge limit controls user event charges; it does not guarantee a cap on the developer's
compute or proxy costs.
Related Actors
- HolidayCheck Reviews Scraper - German Hotel Ratings & Trends - German hospitality reviews with aspect trends and competitor sets
- Trusted Shops & ProvenExpert Reviews Scraper - German Ratings - ratings of German businesses, including restaurants and delivery services
- Walmart Product Scraper - Price Tracker & Stock Checker by ZIP - the same change-detection approach for US retail prices
Included intelligence
- observed 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, andDONER - 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:
recordType | Purpose |
|---|---|
menu_item | One current menu product with branch, location, normalization, and 90-day history |
restaurant | Restaurant-level fallback row when menus are disabled or empty |
postcode_price_matrix | Same chain and comparable product summarized across postal codes |
menu_inflation_summary | Current versus first retained comparable menu basket |
menu_change_summary | What changed for one restaurant since its previous snapshot: price moves, new and removed items, availability, delivery terms (only when something changed) |
run_summary | Coverage, failure rates, quality metrics, issues, and final status |
The default key-value store also contains:
REPORT.html- visual executive reportPOSTCODE_PRICE_MATRIX.csv- spreadsheet-ready postcode comparisonANALYTICS.json- matrix and inflation dataRUN_SUMMARY.json- monitoring payloadSCHEDULE_RECOMMENDATION.json- daily production schedule templateMENU_CHANGE_DIGEST/.html/.txt- run-over-run change digest (whengenerateChangeDigestis 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" above: result-emitted charges apply to delivered menu items, restaurant fallback rows and menu-change summary rows. Postcode matrices, inflation summaries and the run summary have no result event. The currently configured digest has no separate event charge. The memory-based Actor start is separate, and a later failure can retain earlier delivered and charged rows.
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 installnpm run typechecknpm testnpm run buildnpm 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. The current Pricing tab shows platform costs included in the hosted Actor price; the publisher still incurs proxy usage costs. The proxy settings remain visible and editable in the Actor input.
Run time and timeouts
A full restaurant menu takes about 45 seconds to load through the German residential proxy (measured on 2026-10-15: 2 restaurants with menus in Berlin 10115, 111 rows). With maxConcurrency: 2 that is roughly 25 restaurants per 10 minutes. The default run timeout is 3,600 seconds, which fits about 150 restaurants. For larger inputs, raise the timeout in the run options (or in your schedule or API call) to about restaurants x 25 seconds, or split postcodes across several runs. A run that hits the timeout keeps the rows it already delivered, but the postcode matrix and run summary are only written at the end.
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.
Resource controls and direct menu requests
For API calls with restaurantUrls and no postalCodes field, only the supplied menus are requested. Calls with neither field retain the default Berlin postcode. In the Console, set postalCodes to [] for a direct-only run because the form may include its default postcode. Explicitly supplied postcodes still add their requested postcode searches.
The browser blocks image, font and media URL patterns to reduce residential-proxy traffic. Documents, CSS, JavaScript and API responses remain available for menu hydration. Published image URLs still come from the page; matching image resources are not downloaded. This is an optimization, not a guarantee of source access or a publisher cost cap.
Initial browser navigation waits for domcontentloaded, then the existing visible heading, menu-list or restaurant-card checks and menu stabilization determine extraction readiness. A slow remaining page asset cannot by itself hold navigation until the full load event. Missing required content still fails the request; this does not bypass a block or prove current source access.
Restaurant chain identity prefers the parsed JSON-LD image. When that value is already available, the Actor skips the unused DOM image fallback lookup. When it is absent, the same DOM fallback still runs. This avoids an unnecessary locator wait without removing menu extraction, readiness checks or identity fields. It does not establish a fixed runtime or cost saving for every source page.
When no result event fits the remaining charge limit, the Actor skips browser crawling. If the limit is reached during collection, it stops dispatching new requests while already running requests can finish. No extra result event is added. The run summary includes stoppedBySpendingLimit: true, the SPENDING_LIMIT_REACHED warning, and an incomplete-coverage warning instead of presenting a capped run as healthy. Previously delivered rows and the automatic memory-based startup charge can remain charged.
The history precheck prevents writes after a known exhausted result limit. It does not make concurrent history and result delivery atomic; in-flight work and a failure can retain earlier history or delivered rows. Publisher profitability depends on actual runtime, residential-proxy traffic, delivered charge events and the user pricing tier. These controls do not guarantee a nonnegative margin.