Zomato Restaurants Scraper
Pricing
Pay per event
Zomato Restaurants Scraper
Scrape Zomato (zomato.com) restaurant listings by city+cuisine or city+locality listing pages — name, rating, votes, locality, cuisines, and price for two, one row per restaurant. Covers India/APAC's leading restaurant-discovery platform for site-selection and dining competitive intel.
Pricing
Pay per event
Rating
0.0
(0)
Developer
DevilScrapes
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 hours ago
Last modified
Categories
Share
🎯 What this scrapes
Point this Actor at one or more Zomato city+cuisine or city+locality listing URLs (e.g. zomato.com/bangalore/pizza) and it returns one clean row per restaurant — name, canonical URL, aggregate rating, vote count, locality, cuisines, and price for two. Ratings and vote counts arrive parsed as real numbers (not raw "4.3" / "2,664" strings), and every row is stamped with the listing URL it came from plus an ISO-8601 scrape timestamp, so scheduled runs diff cleanly. Built on curl-cffi with browser TLS impersonation against Zomato's own embedded page data — no fragile CSS-selector scraping.
🔥 What we handle for you
- 🧭 Fault-isolated multi-URL crawling — one bad listing URL never aborts the batch; each city+cuisine or city+locality page is fetched and parsed independently.
- 🧮 Numbers you can compute on — vote counts and ratings arrive as clean
int/float, not"2,664"strings scraped raw off the page. - 🛡️ Browser fingerprint rotation —
curl-cffiimpersonates real Chrome/Firefox TLS handshakes on every request, so the crawl holds up if Zomato ever tightens its defenses. - 🔁 Retries with backoff on
408/429/5xx— up to 5 attempts per page,Retry-Afterhonoured. - 🧊 Clean, typed dataset rows — Pydantic-validated, ISO-8601 timestamps, stable restaurant URLs, JSON/CSV/Excel export straight from the Apify Console.
- 💰 Pay-Per-Event pricing — you only pay for restaurants that actually land in your dataset.
💡 Use cases
- Franchise and site-selection research — compare restaurant density, ratings, and price tier across neighborhoods before picking a location.
- Competitive intel for food-delivery and hospitality platforms — track how rivals are rated and priced, city by city.
- Local-market research — build a structured dataset of restaurants, cuisines, and price points for a city or cuisine segment.
- Scheduled monitoring — diff rating and vote-count changes across repeat runs.
⚙️ How to use it
- Click Try for free at the top of the page.
- Fill in the input form — most fields have sensible defaults.
- Click Start. Output streams into the run's dataset.
- Export from Storage → Dataset as JSON, CSV, or Excel — or fetch via the API.
📥 Input
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
listingUrls | array | yes | ['https://www.zomato.com/bangalore/pizza', 'https://www.zomato.com/mumbai/andheri-west-restaurants'] | Zomato city+cuisine or city+locality listing page URLs to scrape, e.g.… |
maxResultsPerUrl | integer | no | 30 | Cap on the number of restaurants emitted per input listing URL. |
proxyConfiguration | object | no | {'useApifyProxy': True} | Apify Proxy spec. Standard (datacenter-tier) default — RESIDENTIAL not required given confirmed clean reach to… |
Example input
{"listingUrls": ["https://www.zomato.com/bangalore/pizza","https://www.zomato.com/mumbai/andheri-west-restaurants"],"maxResultsPerUrl": 5,"proxyConfiguration": {"useApifyProxy": true}}
📤 Output
Every row is one dataset item.
| Field | Type | Notes |
|---|---|---|
name | string | Restaurant name from the embedded state blob. |
url | string | Canonical restaurant detail-page URL (blob or JSON-LD fallback). |
restaurant_id | ['string', 'null'] | Internal ID/slug if present in the blob. |
aggregate_rating | ['number', 'null'] | Parsed rating, e.g. 4.3 (blob ships it as a string). |
votes | ['integer', 'null'] | Parsed vote count, thousands separators stripped (e.g. '2,664' -> 2664). |
locality | ['string', 'null'] | locality.text from the blob, e.g. 'Brigade Road, Bangalore'. |
city | string | Parsed from the input listingUrls path segment. |
cuisines | array | Cuisine tags, only if present in the blob for that record. Empty list is valid. |
price_for_two | ['integer', 'null'] | Only if present in the blob. |
source_listing_url | string | Which listingUrls entry produced this row. |
scraped_at | string | ISO 8601 UTC timestamp at row creation. |
Example output
{"name": "Jamie Oliver's Pizzeria","url": "https://www.zomato.com/bangalore/jamie-olivers-pizzeria-whitefield-bangalore","restaurant_id": "jamie-olivers-pizzeria-whitefield-bangalore","aggregate_rating": 4.3,"votes": 2664,"locality": "Brigade Road, Bangalore","city": "Bangalore","cuisines": ["Pizza","Italian"],"price_for_two": 1200,"source_listing_url": "https://www.zomato.com/bangalore/pizza","scraped_at": "2026-09-15T12:00:00+00:00"}
💰 Pricing
Pay-Per-Event — you pay only when these events fire:
| Event | USD | What it is |
|---|---|---|
actor-start | $0.2 | One-off warm-up charge per run |
restaurant-scraped | $0.004 | PPE event |
Example: 1 000 restaurants at the rates above ≈ $4.20. No subscription, no minimum, no card to start — Apify gives every new account $5 of free credit.
🚧 Limitations
- v1 parses only the first page load's embedded data per input listing URL — no infinite-scroll pagination follow. Add more
listingUrls(more cities, cuisines, or localities) to scale coverage. - Restaurant detail-page fields (menus, photos, review text) are out of scope in v1 — only listing-page fields ship.
- Order/delivery-flow data, table-booking availability, and any authenticated/logged-in view are out of scope.
❓ FAQ
Does this follow pagination beyond the first page load?
No — v1 parses the restaurants embedded in a listing page's first load only (Zomato's listing pages are JS-paginated/infinite-scroll). Point the Actor at more listingUrls — more cities, cuisines, or localities — to scale coverage instead.
What listing URLs are supported?
Any zomato.com city+cuisine or city+locality listing page, e.g. https://www.zomato.com/bangalore/pizza or https://www.zomato.com/mumbai/andheri-west-restaurants. Individual restaurant detail-page URLs are not supported in v1.
Why are some fields null?
restaurant_id, aggregate_rating, votes, locality, and price_for_two are only populated when Zomato's page includes them for that restaurant. A missing value is reported as null, never guessed.
Is this legal?
We only fetch content Zomato makes publicly available on its listing pages. Respect Zomato's own terms of service before using output commercially.
💬 Your feedback
Spotted a bug, hit a weird edge case, or need a new field? Open an issue on the Actor's Issues tab on Apify Console — we ship fixes weekly and we read every report.