# Zomato Scraper — Restaurants, Phones, Menus & Reviews (`yugenox/zomato-restaurants-scraper`) Actor

Scrape Zomato restaurants by city, area, delivery address, cuisine, collection or URL — no login. Dining and delivery ratings, cost for two, phone numbers, full address, pincode, GPS, timings, amenities, offers, photos, plus optional delivery menus and reviews.

- **URL**: https://apify.com/yugenox/zomato-restaurants-scraper.md
- **Developed by:** [Yugenox Corp](https://apify.com/yugenox) (community)
- **Categories:** Lead generation, Travel, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 restaurants

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Zomato Scraper — Restaurants, Phones, Menus & Reviews

Scrape restaurants from **Zomato** (India and other Zomato countries) by **city, area, delivery address, cuisine, collection or URL**. Every restaurant comes back as one clean row: dining and delivery ratings with review counts, cost for two, **phone numbers**, full address, **pincode**, **GPS coordinates**, opening hours, amenities, payment methods, popular dishes, dining offers, photos and menu-card images. Optionally add the **delivery menu** (one row per dish) and **reviews**.

No Zomato account, cookies or login needed. Just type a city and press Start.

### What you can scrape

| Input | Example | What you get |
|---|---|---|
| **City** | `ncr`, `mumbai`, `bangalore`, `pune`, `Delhi`, `Bengaluru` | All restaurants Zomato lists for the city |
| **Listing** | Dining out / Delivery / Nightlife | The matching Zomato tab |
| **Areas or delivery addresses** | `Koramangala, Bangalore`, `Bandra West, Mumbai`, a full street address | Restaurants around that place. With **Delivery**, the restaurants that deliver to that address, with delivery time and distance |
| **Cuisines** | `North Indian`, `Biryani`, `Chinese`, `Cafe` | One search per cuisine in your city / areas |
| **Zomato URLs** | `/bangalore/indiranagar-restaurants`, `/pune/restaurants/biryani`, `/ncr/drinks-and-nightlife`, `/ncr/insta-worthy`, `/ncr/restaurants/haldirams`, a restaurant page | Any listing, collection, chain or single restaurant |

#### Go beyond 500 results per city

Zomato's own listing stops at about 500 dine-out restaurants per search, even in a city with 25,000. This scraper **automatically splits large searches** by sort order and by cuisine and removes duplicates, so you can collect thousands of restaurants from one city. Duplicates are never saved or charged twice.

#### City-wide delivery coverage

Each delivery address only sees the restaurants that deliver there. Set **Delivery grid radius** (for example 10 km, every 3 km) and the scraper searches a grid of points around the city center or around each address you give, merging everything into one de-duplicated list.

### Output

One row per restaurant (`dataType: "restaurant"`):

```json
{
  "dataType": "restaurant",
  "resId": 311057,
  "name": "My Bar Headquarters",
  "url": "https://www.zomato.com/ncr/my-bar-headquarters-connaught-place-new-delhi",
  "city": "New Delhi",
  "citySlug": "ncr",
  "country": "India",
  "locality": "Connaught Place, New Delhi",
  "address": "N-49, SF, CP, Chankya Puri, Connaught Place, New Delhi",
  "pincode": "110001",
  "latitude": 28.6306766,
  "longitude": 77.219722,
  "phones": ["+919873773747", "+917838000006"],
  "cuisines": ["North Indian", "Chinese", "Pizza", "Desserts"],
  "costForTwo": "₹3,000 for two",
  "costForTwoValue": 3000,
  "currency": "INR",
  "costNote": "₹3,000 for two people (approx.) with alcohol; ₹129 for a pint of beer (approx.) | The cost for two is computed as follows: 6 pints of beer + 2 appetizers…",
  "rating": 3.9,
  "ratingText": "Good",
  "votes": 6861,
  "diningRating": 3.9,
  "diningReviews": 6861,
  "deliveryRating": 3.1,
  "deliveryReviews": 21,
  "hasDineout": true,
  "hasDelivery": true,
  "statusText": "Open now",
  "timings": "11am – 1am (Today)",
  "openingHours": [{ "days": "Mon-Sun", "timing": "11am – 1am" }],
  "isPermClosed": false,
  "isTempClosed": false,
  "highlights": ["Lunch", "Dinner", "Takeaway available", "Full bar available", "Live music", "Smoking area"],
  "paymentMethods": ["Cash and Cards accepted", "Digital payments accepted"],
  "topDishes": ["Bloody Mary", "Pina Colada", "Lemon Chicken", "Honey Chilli Potatoes"],
  "peopleSay": ["Band Playing", "No Cover Charge", "Good Bar", "Hookahs"],
  "diningOffers": ["PRE-BOOK OFFER — Flat 10% OFF — Valid from 12:30PM to 11:55PM today Booking required"],
  "menuImages": [{ "label": "Food", "pages": 2, "thumbnailUrl": "https://b.zmtcdn.com/…" }],
  "photos": ["https://b.zmtcdn.com/data/pictures/…jpg"],
  "chainText": "See all 4 My Bar Headquarters outlets in Delhi NCR",
  "isPromoted": true,
  "distance": "1.1 km",
  "deliveryTime": null,
  "offers": [],
  "sourceSearch": "ncr · dineout",
  "detailsScraped": true,
  "scrapedAt": "2026-09-24T06:47:21.484Z"
}
```

With **Delivery menu** on, one row per dish (`dataType: "menuItem"`):

```json
{
  "dataType": "menuItem",
  "resId": 20358318,
  "restaurantName": "Jumboking Burgers",
  "restaurantUrl": "https://www.zomato.com/mumbai/jumboking-burgers-1-matunga-east",
  "itemId": "ctl_795808116",
  "name": "Mumbai Burger",
  "description": "A Mumbai-style authentic patty, layered with onions, and a creamy mayo in a toasted bun.",
  "category": "Classic Burgers",
  "isVeg": true,
  "isBestseller": false,
  "isSpicy": false,
  "dishType": null,
  "tags": [],
  "price": null,
  "priceLoginBlocked": true,
  "imageUrl": "https://b.zmtcdn.com/data/dish_photos/…png"
}
```

The restaurant row then also carries `menuItemCount`, `fssaiLicense` and `addOnGroups` (customisation / add-on options **with prices**).

With **Reviews** on, one row per review (`dataType: "review"`): `reviewId`, `rating`, `ratingType` (DINING / DELIVERY), `reviewText`, `timestamp` ("5 hours ago"), `reviewedAt` (ISO date), `likeCount`, `commentCount`, `photos`, `tags`, `ownerReplies`, `reviewUrl`, plus the restaurant's `resId`, `restaurantName` and `restaurantUrl`. Reviewer names are left out unless you turn on **Include reviewer names**.

Use the **Restaurants**, **Menu items** and **Reviews** views in the dataset, or filter on `dataType` in your export.

### Use cases

- **Lead generation** — restaurant names, phone numbers, addresses and pincodes for sales teams selling to restaurants (POS, payments, suppliers, marketing agencies).
- **Market research** — how many North Indian restaurants in Koramangala, average cost for two per area, rating distribution by cuisine.
- **Delivery coverage analysis** — which restaurants deliver to a given address, delivery times and discounts, compared across neighbourhoods.
- **Competitor tracking** — ratings, review counts and offers of chains and competitors over time (schedule the actor daily or weekly).
- **Mapping** — GPS coordinates for every outlet, ready for maps and catchment studies.
- **Menu intelligence** — dishes, categories, veg / non-veg split and bestsellers across restaurants.

### Tips

- **Faster runs:** turn off *Full restaurant details* if you only need names, ratings, cuisines, cost and locality — the listing alone is several times faster.
- **Big cities:** leave *Go beyond 500 per search* on and set *Max restaurants* to what you need. Delhi NCR alone lists over 25,000 dine-out restaurants.
- **Delivery for a whole city:** Listing = Delivery, City = `bangalore`, Delivery grid radius = `10`.
- **One area only:** put it in *Areas or delivery addresses*, e.g. `Indiranagar, Bangalore`.

### FAQ

**Do I need a Zomato account?** No. Everything is collected the way a visitor sees zomato.com.

**Is it legal to scrape Zomato?** This scraper collects only public data: the restaurant listings, restaurant pages, delivery menus and reviews that Zomato shows to any visitor who is not logged in. Collecting publicly available data is generally legal, but what you do with it matters. A restaurant's contact number can be the owner's own mobile, and with *Include reviewer names* turned on a review row also carries the reviewer's public Zomato name and profile link. Both count as personal data, so have a legitimate reason to use them and follow the privacy rules that apply to you (GDPR, PIPEDA, CCPA, India's DPDP Act or similar) as well as Zomato's terms. If you are unsure, check with a lawyer. More background: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

**Does it access any private data?** No. The scraper never logs in and uses no account, cookie, password or saved session. It reads the same public pages anyone can open on zomato.com without signing in. It cannot see diners' profiles, orders, addresses, payment details, e-mail addresses or anything else behind Zomato's login, which is also why base dish prices are not included. Reviewer names and profile links are left out entirely unless you turn on *Include reviewer names*.

**How am I charged?** Per row saved to your dataset: one price per restaurant, and much smaller prices per menu item and per review (only when you turn those on). There is no start fee. Duplicates, restaurants that could not be found and failed requests are never charged. See the Pricing tab for current prices.

**Are dish prices included?** Zomato shows base dish prices only to signed-in users, so they are not included (`price: null`, `priceLoginBlocked: true`). Add-on and customisation prices are included in `addOnGroups`.

**How many reviews can I get per restaurant?** Up to 500 per sort order. Choose *Newest*, *Oldest*, *Highest* or *Lowest* first.

**Which cities work?** Every city on zomato.com — all Indian cities from Delhi NCR, Mumbai and Bangalore to Tier 2/3 towns, plus other Zomato countries. Use the name from the zomato.com address (e.g. `ncr` for Delhi NCR).

**Why did I get fewer restaurants than Zomato's total?** Zomato's totals include closed and inactive listings and are approximate. Turn on *Go beyond 500 per search* and raise *Max restaurants*; the scraper stops splitting once new sub-searches stop finding new restaurants.

**Will I be charged for duplicates?** No. Restaurants are de-duplicated before they are saved.

**Proxy?** The default Apify datacenter proxy works. If it is ever blocked, the run switches to residential proxies automatically.

**What if Zomato is slow, blocks me, or the run hits its time limit?** The run still finishes successfully with everything collected so far. Blocked requests are retried on fresh IPs (with an automatic residential fallback); near the time limit the scraper stops on its own, saves the restaurants it already found (those still waiting for their detail page are saved with the listing data and `detailsScraped: false`), and says so in the status message. You are only charged for rows that were actually saved.

**Can I paste a zoma.to share link?** Yes — short links from the Zomato app are followed to the full zomato.com page.

# Actor input Schema

## `city` (type: `string`):

Zomato city, as in the zomato.com address: ncr (Delhi NCR — Delhi, Gurgaon, Noida), mumbai, bangalore, pune, hyderabad, chennai, kolkata, ahmedabad, jaipur, chandigarh, lucknow, goa, kochi, indore… Common names like Delhi, Bengaluru or Gurugram work too. Separate several cities with commas.

## `mode` (type: `string`):

Which Zomato tab to scrape for the city / areas: Dining out, Delivery, or Nightlife (bars, pubs, clubs).

## `locations` (type: `array`):

Search around specific places instead of (or as well as) a whole city, e.g. "Koramangala, Bangalore", "Bandra West, Mumbai", "Cyber Hub Gurgaon", or a full street address. With Listing = Delivery you get the restaurants that deliver to that address.

## `cuisines` (type: `array`):

Only restaurants serving these cuisines (one search per cuisine), for the City and Areas above. Use Zomato's names, e.g. North Indian, Chinese, Biryani, South Indian, Pizza, Cafe, Desserts.

## `startUrls` (type: `array`):

Any zomato.com page: a city or area listing (/ncr/restaurants, /mumbai/delivery, /bangalore/indiranagar-restaurants), a cuisine page (/pune/restaurants/biryani), nightlife (/ncr/drinks-and-nightlife), a collection (/ncr/insta-worthy), a chain (/ncr/restaurants/haldirams), or a single restaurant page.

## `maxItems` (type: `integer`):

Maximum number of restaurants for the whole run (menu items and reviews are extra rows on top). Set a large number, e.g. 100000, to get everything Zomato lists.

## `maxItemsPerSearch` (type: `integer`):

Optional cap for each individual city, area or URL.

## `splitLargeSearches` (type: `boolean`):

Zomato lists at most ~500 dine-out restaurants per search. When you ask for more, the scraper automatically re-runs the search in other sort orders and per cuisine, and removes duplicates, to reach thousands of restaurants in big cities. Duplicates are never charged.

## `deliveryGridRadiusKm` (type: `integer`):

Delivery only. Each address sees the restaurants that deliver there. Set a radius to also search a grid of points around the city center / each address and cover a whole city. 0 = off.

## `deliveryGridStepKm` (type: `integer`):

Distance between grid points. 3 km is a good balance; smaller = more points, more requests.

## `includeDetails` (type: `boolean`):

Open each restaurant page for phone numbers, full address, pincode, GPS, opening hours, amenities, payment methods, popular dishes, dining offers, photos and menu-card images. Turn off for a faster listing-only run.

## `includeMenu` (type: `boolean`):

Add one row per dish from each restaurant's online-ordering menu: name, description, category, veg / non-veg, bestseller, tags, photo. Zomato shows base dish prices only to signed-in users, so dish prices are not included; add-on / customisation prices and the FSSAI licence number are added to the restaurant row.

## `includeReviews` (type: `boolean`):

Add review rows for each restaurant: rating, dining / delivery, text, date, likes, photos, owner replies.

## `maxReviewsPerRestaurant` (type: `integer`):

Up to 500 per restaurant per sort order.

## `reviewsSort` (type: `string`):

Which reviews to collect first.

## `reviewsType` (type: `string`):

All reviews, or only dining / only delivery reviews.

## `includeReviewerNames` (type: `boolean`):

Add the reviewer's public display name, profile link and review / follower counts to each review.

## `maxConcurrency` (type: `integer`):

How many requests run at once. The default is fast and safe.

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

Apify datacenter proxy works well and is the default. Blocked IPs are rotated automatically, with an automatic residential fallback.

## Actor input object example

```json
{
  "city": "ncr",
  "mode": "dineout",
  "maxItems": 30,
  "splitLargeSearches": true,
  "deliveryGridRadiusKm": 0,
  "deliveryGridStepKm": 3,
  "includeDetails": true,
  "includeMenu": false,
  "includeReviews": false,
  "maxReviewsPerRestaurant": 20,
  "reviewsSort": "newest",
  "reviewsType": "all",
  "includeReviewerNames": false,
  "maxConcurrency": 8,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped restaurants (and menu items / reviews if enabled).

## `run` (type: `string`):

Status and statistics for this run.

# 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 = {
    "city": "ncr",
    "maxItems": 30,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/zomato-restaurants-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 = {
    "city": "ncr",
    "maxItems": 30,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/zomato-restaurants-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 '{
  "city": "ncr",
  "maxItems": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yugenox/zomato-restaurants-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yugenox/zomato-restaurants-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/ftKYLlF8SusEOVV20/builds/bNI9cf7OpjEoEKqhm/openapi.json
