# Zomato Scraper \[Only $1.9💰] | Restaurants | Menus | Ratings (`ahmed_jasarevic/zomato-scraper`) Actor

Scrape Zomato restaurants, full menus and delivery data for lead generation and market research: ratings, cuisines, cost for two, phone, address, coordinates and priced menu items.

- **URL**: https://apify.com/ahmed_jasarevic/zomato-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

Scrape Zomato restaurant listings, details and menus for restaurant lead generation, POS and fintech sales, and food-market research: restaurant name, phone, address and locality, cuisines, dining and delivery ratings, cost for two, coordinates and priced menu items.

The actor drives Zomato's own internal JSON routes with a plain HTTP crawler (no browser), so pages come back small and fast, and it can expand a single city into its cuisine and locality listings automatically.

### Main Use Cases

- Restaurant lead generation and POS or payments sales prospecting
- Food-market research and city-level restaurant supply mapping
- Building structured restaurant databases with phone, address and coordinates
- Menu and price monitoring for delivery and dine-in offerings
- Competitor analysis of ratings, cuisines and cost for two
- Aggregator and delivery-ops intelligence (open listings, localities, ratings)

### How It Works

Zomato's frontend calls a small internal JSON API for every page. The actor drives that API directly with a Cheerio crawler, no browser:

| Data | Request |
| --- | --- |
| Listing and search pages (city, cuisine, locality, delivery) | `GET https://www.zomato.com/webroutes/getPage?page_url=/mumbai/restaurants` |
| Extra result pages | `POST` on the search endpoint, which paginates about 12 restaurants per call and is the fastest way to reach volume. |
| Restaurant detail | Detail page JSON for phone, full address, coordinates, city and country. |
| Delivery menu | Delivery menu JSON for item names and prices. |

Zomato blocks datacenter IPs, so the default proxy is Apify residential (India). Listing pages, search pages and detail requests run in parallel, and each restaurant detail and menu adds its own billed event.

### Scrape Zomato Restaurants And Menus Without An Official API

The old public Zomato API (the `developers.zomato.com` v2.1 endpoints used with a `user-key`) was shut down, and Zomato's current developer platform is a POS and merchant integration program for restaurants operating on Zomato, not a general restaurant-data API. That leaves no self-serve endpoint for restaurant discovery, ratings or menus. This actor reads the same public routes the website calls:

- Start from city slugs (`cities`), which expand into the main dining and delivery listings, or from any listing or restaurant URL in `startUrls`.
- Auto-expand a city listing into its cuisine and locality pages (`expandListings`), bounded by `maxListings`.
- Pull result pages quickly through the search route (`maxSearchPages`), about 12 restaurants per page.
- Enrich each restaurant with details (`includeDetails`) and its priced delivery menu (`includeMenu`).

### Input Parameters

| Field | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `cities` | array | No | `["mumbai"]` | Zomato city slugs (for example mumbai, delhi-ncr, bangalore, pune, hyderabad, dubai). Each expands into its main dining and delivery listings. |
| `startUrls` | array | No | Mumbai restaurants | Zomato listing or restaurant URLs to scrape. Listing pages yield all restaurants on them; restaurant URLs yield a single restaurant. |
| `maxRestaurants` | integer | No | `100` | Maximum restaurants to output per run. Free users are capped at 10. |
| `maxListings` | integer | No | `20` | Maximum listing pages crawled when auto-expanding a city into cuisine and locality pages. |
| `maxSearchPages` | integer | No | `10` | Result pages pulled per listing through the search route (about 12 restaurants per page). |
| `includeDetails` | boolean | No | `true` | Fetch each restaurant's detail page for phone, full address, coordinates, city and country. |
| `includeMenu` | boolean | No | `true` | Fetch each restaurant's delivery menu with item names and prices. |
| `expandListings` | boolean | No | `true` | Discover and crawl cuisine and locality listing pages linked from each city listing. |
| `maxConcurrency` | integer | No | `30` | Parallel requests; the session pool matches it so each request gets its own sticky residential exit IP. |
| `proxy` | object | No | Apify residential (India) | Zomato blocks datacenter IPs. Turn it off with useApifyProxy false only if you run from a residential IP. |

### Output Fields

One item per restaurant in the default dataset:

- `resId`, `name`, `url`, `listingUrl`: Zomato restaurant ID, name, restaurant URL and the listing page it was found on.
- `cuisines`: array of cuisines.
- `diningRating`, `diningReviews`, `deliveryRating`, `deliveryReviews`: dining and delivery ratings with their review counts.
- `rating`, `votes`: overall rating and vote count.
- `costForTwo`, `costForOne`: cost for two and cost for one.
- `address`, `locality`: full address and locality.
- `phone`: phone number (when details are enabled).
- `latitude`, `longitude`: coordinates (when details are enabled).
- `menu`: array of menu items with names and prices (when menus are enabled).
- `menuItemsCount`: number of menu items.

Dataset view: `overview`.

### Example Input And Output

Example input:

```json
{
  "cities": ["mumbai", "bangalore"],
  "maxRestaurants": 200,
  "maxListings": 20,
  "maxSearchPages": 10,
  "includeDetails": true,
  "includeMenu": true,
  "expandListings": true
}
```

Example output row:

```json
{
  "resId": "18987654",
  "name": "Example Kitchen",
  "url": "https://www.zomato.com/mumbai/example-kitchen-bandra-west",
  "listingUrl": "https://www.zomato.com/mumbai/restaurants",
  "cuisines": ["North Indian", "Chinese"],
  "diningRating": "4.2",
  "diningReviews": 1204,
  "deliveryRating": "4.0",
  "deliveryReviews": 860,
  "rating": "4.1",
  "votes": 2064,
  "costForTwo": "800",
  "costForOne": "400",
  "address": "Shop 4, Linking Road, Bandra West, Mumbai",
  "locality": "Bandra West",
  "phone": "+91 22 4000 0000",
  "latitude": 19.0607,
  "longitude": 72.8362,
  "menu": [
    { "name": "Paneer Butter Masala", "price": "320" },
    { "name": "Garlic Naan", "price": "60" }
  ],
  "menuItemsCount": 42
}
```

### Integrations & Automation

Export results as JSON, CSV or Excel, read them through the Apify API, or push them to a CRM or database with webhooks, Zapier or Make. For lead generation, a weekly schedule keeps a territory fresh; for rating and cost-for-two monitoring, run daily or weekly and keep the same `cities` so runs are comparable. Recurring runs also help the actor surface better in the Apify Store.

### Related Actors

- [easyapi/zomato-restaurant-reviews-scraper](https://apify.com/easyapi/zomato-restaurant-reviews-scraper)
- [stealth_mode/zomato-restaurants-search-scraper](https://apify.com/stealth_mode/zomato-restaurants-search-scraper)
- [thirdwatch/zomato-scraper](https://apify.com/thirdwatch/zomato-scraper)
- [fatihtahta/zomato-scraper](https://apify.com/fatihtahta/zomato-scraper)
- [memo23/zomato-scraper](https://apify.com/memo23/zomato-scraper)

### FAQ

#### Is there an official Zomato API?

No general-purpose one. The old public API (the `developers.zomato.com` v2.1 endpoints with a `user-key`) was discontinued and no longer issues keys. Zomato's current developer platform is a POS and merchant integration API for restaurants selling on Zomato, not a data API for restaurant discovery, ratings or menus. For discovery data, reading the public site routes is the practical route.

#### What are the alternatives to this actor for Zomato data?

Alternatives include other Apify Store actors that focus on Zomato reviews or Zomato search, and general place-data APIs such as Google Places, Yelp Fusion or Foursquare, which give broad place data but not Zomato menus or Zomato cost-for-two. This actor returns restaurant details and priced menus from one run.

#### Do I need residential proxies?

Yes, in practice. Zomato blocks datacenter IPs, so the default configuration uses the Apify residential proxy with an India exit. If you run from a residential IP (for example, locally), you can turn the proxy off.

#### Why is my restaurant count lower than `maxRestaurants`?

Two reasons. First, free users are capped at 10 restaurants per run regardless of `maxRestaurants`. Second, the count is also bounded by how many listing and search pages the run crawls through `maxListings` and `maxSearchPages`.

#### Can I scrape a single restaurant or a specific listing?

Yes. Put the restaurant or listing URL in `startUrls`. A restaurant URL yields that single restaurant; a listing URL yields every restaurant on the listing.

#### Does it return menus with prices?

Yes, when `includeMenu` is true. Menu items are returned in the `menu` array with names and prices, and the total is in `menuItemsCount`.

### SEO Keywords

zomato scraper, zomato restaurant scraper, scrape zomato, zomato api, zomato menu scraper, zomato menus with prices, zomato data, zomato restaurants, restaurant lead generation, restaurant data india, food delivery data, zomato ratings scraper, restaurant market research, cost for two data, restaurant database india, zomato dubai, zomato location data, restaurant phone number scraper, zomato csv export, restaurant competitor analysis, zomato without api, food delivery aggregator data, zomato listing scraper, restaurant pos lead generation

### For AI Agents & LLM Apps

Purpose: return Zomato restaurant rows (ratings, cost for two, address, coordinates) and, optionally, priced delivery menus, for a set of cities or URLs.

Minimal working input:

```json
{ "cities": ["mumbai"] }
```

Variant for a single listing, details only, no menus:

```json
{ "startUrls": [{ "url": "https://www.zomato.com/mumbai/restaurants/biryani" }], "includeMenu": false }
```

Output fields: `resId`, `name`, `url`, `listingUrl`, `cuisines`, `diningRating`, `diningReviews`, `deliveryRating`, `deliveryReviews`, `rating`, `votes`, `costForTwo`, `costForOne`, `address`, `locality`, `phone`, `latitude`, `longitude`, `menu`, `menuItemsCount`.

Behaviors an agent should know:

- `cities` and `startUrls` are both honoured; each city expands into its dining and delivery listings unless `expandListings` is false.
- `maxRestaurants` is capped by the free limit of 10 for non-paying users; set it higher only on a paid account.
- `includeDetails` and `includeMenu` each add billed events (`restaurant-details`, `restaurant-menu`) and extra requests; set them false for a cheap listing-only run.
- `maxSearchPages` controls how many result pages are pulled per listing through the fast search route (about 12 restaurants per page); it is the main volume lever.
- The default proxy is required in practice because Zomato blocks datacenter IPs.

Billing: pay-per-event. `apify-actor-start` (about $0.00005), one `restaurant` event per base result (about $0.0019), one `restaurant-details` per enriched restaurant (about $0.004) and one `restaurant-menu` per menu (about $0.008), lower at higher loyalty tiers.

### Legal & Compliance Disclaimer

This actor is independent and is not affiliated with, endorsed by or sponsored by Zomato Ltd. or Eternal Ltd. It reads only publicly available pages and the public JSON routes the site itself calls: it does not log in, does not bypass authentication, does not solve CAPTCHAs and does not place orders.

Users are responsible for complying with Zomato's Terms of Service and with applicable data-protection law (for example GDPR or CCPA) in their own jurisdiction. Where the output contains restaurant phone numbers or other contact data, that data must not be used for unsolicited commercial outreach in violation of applicable law.

# Actor input Schema

## `cities` (type: `array`):

Zomato city slugs to scrape (e.g. "mumbai", "delhi-ncr", "bangalore", "pune", "hyderabad", "dubai"). Each city expands into its main dining listing and delivery listing.

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

Zomato listing or restaurant URLs to scrape, e.g. https://www.zomato.com/mumbai/restaurants/biryani, https://www.zomato.com/mumbai/dadar-east-restaurants, https://www.zomato.com/mumbai/rasoi-dadar-east. Listing pages yield all restaurants on them; restaurant URLs yield that single restaurant.

## `maxRestaurants` (type: `integer`):

Maximum number of restaurants to output (per run). Free users are capped at 10.

## `maxListings` (type: `integer`):

Maximum listing pages crawled when auto-expanding a city into its cuisine and locality pages.

## `maxSearchPages` (type: `integer`):

Result pages pulled per start listing through Zomato's search API (about 12 restaurants per page, chained automatically). This is the fastest way to get volume — one cheap ~1-2s POST per 12 restaurants instead of slow listing-page crawls.

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

Fetch each restaurant's detail page for phone number, full address, coordinates, city and country.

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

Fetch each restaurant's delivery menu with item names and prices.

## `expandListings` (type: `boolean`):

Automatically discover and crawl cuisine and locality listing pages linked from each city listing page (bounded by Max listing pages).

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

How many requests run in parallel — pinned at this value (no autoscaler ramp-up). The session pool matches it, so each in-flight request gets its own sticky residential exit IP and its own bandwidth.

## `proxy` (type: `object`):

Zomato blocks datacenter IPs, so the default is the Apify RESIDENTIAL proxy (India). Turn it off with useApifyProxy=false if you run from a residential IP (e.g. locally).

## Actor input object example

```json
{
  "cities": [
    "mumbai"
  ],
  "startUrls": [
    {
      "url": "https://www.zomato.com/mumbai/restaurants"
    }
  ],
  "maxRestaurants": 100,
  "maxListings": 20,
  "maxSearchPages": 10,
  "includeDetails": true,
  "includeMenu": true,
  "expandListings": true,
  "maxConcurrency": 30,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "IN"
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "cities": [
        "mumbai"
    ],
    "startUrls": [
        {
            "url": "https://www.zomato.com/mumbai/restaurants"
        }
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "IN"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/zomato-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 = {
    "cities": ["mumbai"],
    "startUrls": [{ "url": "https://www.zomato.com/mumbai/restaurants" }],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "IN",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/zomato-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 '{
  "cities": [
    "mumbai"
  ],
  "startUrls": [
    {
      "url": "https://www.zomato.com/mumbai/restaurants"
    }
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "IN"
  }
}' |
apify call ahmed_jasarevic/zomato-scraper --silent --output-dataset

```

## MCP server setup

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