How to Scrape Deliveroo Restaurant Menus UK + EU (2026)

Deliveroo’s restaurant menu data is some of the most commercially valuable food delivery intelligence in Europe, covering 50,000+ restaurants across the UK, Ireland, France, Belgium, Italy, and the Netherlands — and scraping it in 2026 requires navigating Cloudflare, aggressive fingerprinting, and a GraphQL API that changes without notice.

What Deliveroo’s Stack Looks Like in 2026

Deliveroo serves its consumer frontend as a Next.js SSR app. The page HTML contains a __NEXT_DATA__ JSON blob on first load, which includes partial restaurant and menu data — but it’s incomplete for pricing and item modifiers. The real payload comes from their internal GraphQL endpoint at https://consumer-ow-api.deliveroo.com/orderapp/v1/graphql, authenticated via x-roo-country and x-roo-guid headers.

Cloudflare sits in front of every request. As of Q1 2026, they’ve enabled Cloudflare Turnstile on the checkout flow and Bot Fight Mode on the API routes. Residential IPs in the restaurant’s target country (UK for UK listings) are the minimum viable proxy type. Datacenter IPs get challenged or silently blocked within 3-5 requests.

Unlike scraping Just Eat / Takeaway menu data, which exposes a cleaner REST API, Deliveroo requires you to send well-formed GraphQL payloads with the right operation names — malformed queries return 200 OK with null data fields, not error codes, which makes debugging slow.

Two Extraction Approaches

GraphQL API (Preferred)

The fastest path is hitting the GraphQL endpoint directly after capturing a valid session. Here’s a minimal Python example using httpx:

import httpx, json

HEADERS = {
    "x-roo-country": "uk",
    "x-roo-guid": "YOUR_GUID_HERE",
    "x-roo-client": "consumer-web",
    "content-type": "application/json",
    "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
}

QUERY = """
query GetMenu($restaurantId: ID!) {
  restaurant(id: $restaurantId) {
    name
    menuCategories {
      name
      menuItems {
        name
        price { amount currency }
        description
      }
    }
  }
}
"""

def fetch_menu(restaurant_id: str, proxy: str):
    resp = httpx.post(
        "https://consumer-ow-api.deliveroo.com/orderapp/v1/graphql",
        headers=HEADERS,
        json={"query": QUERY, "variables": {"restaurantId": restaurant_id}},
        proxies={"https://": proxy},
        timeout=15
    )
    return resp.json()["data"]["restaurant"]

The x-roo-guid is a per-session UUID that Deliveroo assigns on first page load. You need a fresh one per scraping session — hardcoding a single GUID across thousands of requests is the fastest way to get soft-blocked.

Browser Automation (Fallback)

For pages behind Turnstile or when the API returns 403s consistently, Playwright with persistent browser profiles is the fallback. Set --disable-blink-features=AutomationControlled and load a real Chrome profile. Headless mode alone is insufficient — Deliveroo’s JS fingerprints navigator.webdriver and checks WebGL renderer strings.

Proxy and IP Strategy by Country

Country targeting matters because Deliveroo’s GraphQL endpoint returns different restaurant sets based on x-roo-country + the IP’s geolocation. These must match.

CountryDeliveroo Active?Recommended IP TypeNotes
UKYes (primary market)UK residential or mobileHighest bot scrutiny
IrelandYesIE residentialLighter blocking than UK
FranceYesFR residentialFR cookie consent wall
BelgiumYesBE residentialLow volume, easier
ItalyYesIT residentialModerate Cloudflare
NetherlandsYesNL residentialSimilar to BE
GermanyNoDeliveroo exited 2022
SpainNoExited 2021

Mobile IPs outperform residential on UK routes specifically — Deliveroo has tightened ASN-level blocking of ISP residential blocks that appear in proxy provider ranges. A Singapore mobile proxy farm routes UK traffic poorly; use a UK-based 4G provider for best results.

The Foodpanda data scraping guide covers a different geofencing model (Asia-first) but the same principle applies: country IP and country header must match, or you get restaurant listings for the wrong city.

Restaurant Discovery: Building Your ID List

Deliveroo doesn’t expose a public sitemap for restaurant IDs. Your discovery options:

  1. Scrape the search and browse pages (/restaurants/) for your target postcode, paginating through the lazy-loaded restaurant grid.
  2. Use the autocomplete API (/api/fulfilment-metadata/lookup) with a grid of UK postcodes to get restaurant slugs and IDs.
  3. Seed from a third-party postcode list (Code-Point Open from Ordnance Survey covers all UK postcodes, free).
  4. Monitor the sitemap at https://deliveroo.co.uk/sitemap.xml — it exists but is incomplete.

Option 2 is the most systematic for bulk collection. UK has roughly 1.7 million postcodes; sampling every 500m with a grid of representative postcodes gives you ~95% restaurant coverage without hitting every single one.

For EU coverage, scraping Foodpanda menu data across Asia and EU overlaps with Deliveroo in Belgium and the Netherlands — cross-referencing both datasets is useful for competitive pricing analysis.

Common Errors and What They Mean

  • 200 OK with "data": {"restaurant": null} — restaurant ID invalid, or your GUID is flagged. Rotate the GUID and retry once before discarding the ID.
  • 403 Forbidden — Cloudflare hard block. Rotate IP + generate fresh headers. If persistent, drop to browser automation.
  • 429 Too Many Requests — respect the rate limit. 1 req/sec per IP is a safe starting point; push to 3 req/sec with residential and monitor the 429 rate.
  • CAPTCHA redirect — Turnstile triggered. Switch to Playwright with a real browser profile.

If you’re running parallel scrapers across UK and EU, the session management pattern used for Uber Eats restaurant listings at scale applies directly — pool sessions per country, recycle after 50-100 requests, and don’t share GUIDs across workers.

Data Schema and Storage

A minimal menu record looks like this:

{
  "restaurant_id": "abc123",
  "restaurant_name": "Dishoom",
  "postcode": "WC2H 9JQ",
  "scraped_at": "2026-05-07T10:23:00Z",
  "menu_items": [
    {
      "category": "Small Plates",
      "name": "Pau Bhaji",
      "price_gbp": 8.50,
      "description": "Mumbai's favourite street food"
    }
  ]
}

Store raw JSON per scrape run and normalize into a relational schema only after validation. Prices change frequently — Deliveroo allows restaurants to update pricing in real time, so timestamps on each scrape run are mandatory if you’re doing longitudinal price tracking.

For multi-platform analysis, you’ll likely combine this with Grubhub menu data for the US side, since several restaurant chains operate on both continents with different pricing strategies worth measuring.

Bottom Line

For UK scraping, use a genuine UK 4G residential IP, rotate GUIDs per session, and hit the GraphQL endpoint directly — browser automation is a fallback, not a first choice. EU routes are materially easier than UK. Rates above 3 req/sec per IP are where blocks accelerate, so horizontal scaling across IPs beats vertical. DRT covers the full food delivery scraping stack — from discovery to anti-bot bypass to schema design — if you’re building out this pipeline across multiple platforms.

Related guides on dataresearchtools.com

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top

Resources

Proxy Signals Podcast
Operator-level insights on mobile proxies and access infrastructure.

Multi-Account Proxies: Setup, Types, Tools & Mistakes (2026)