# District Dining Scraper: Zomato Restaurants & Offers (`yugenox/district-dining-scraper`) Actor

Restaurants from District (by Zomato) across India: live table-booking discounts, ratings with food/service/ambience scores, cost for two, cuisines, phone, address, GPS, hours, menus and reviews. Browse with filters, search dishes, look up links or list a whole city. No login.

- **URL**: https://apify.com/yugenox/district-dining-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 $2.00 / 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

## District Dining Scraper: Zomato Restaurants & Offers

Scrape restaurants from **District by Zomato**, the app that replaced Zomato's dining-out tab across India. For every restaurant you get the **live table-booking discounts**, the rating with its **food, service and ambience** scores, cost for two, cuisines, **phone number**, full address, **GPS coordinates**, opening hours, facilities, photos, menus and recent reviews.

No login and no cookies are needed. Restaurant ids are the same as Zomato's, so the output joins cleanly with any Zomato dataset you already have.

### What you can scrape

| Mode | You give | You get |
|---|---|---|
| **Browse a location** | a city, neighbourhood or coordinates | restaurants in District's order, or sorted by rating, offer, cost or distance, with District's filters (cuisine, price band, rating, open now, pure veg, serves alcohol, outdoor seating, pet friendly, cafés, fine dining, 30% or 50% off) |
| **Search** | dishes, cuisines or names ("biryani", "sushi", "rooftop") + locations | the matching restaurants near each location |
| **Specific restaurants** | District links, Zomato links or restaurant ids | full details for each one |
| **Every restaurant in a city** | a city (optionally part of a link, like "koramangala") | the city's complete restaurant directory: Delhi NCR alone has more than 37,000 |

**Cover the whole city** repeats a browse or search in every neighbourhood District knows for the city (36 in Mumbai, 11 in Pune; smaller cities get a grid) and merges the results without duplicates. A single location returns about 500 restaurants at most; with this switch Pune returned 3,186 unique restaurants in about 2.5 minutes.

### Why this scraper

- **Offer data nobody else has.** Each row has the pre-book discount (for example 60% off with 6 slots left today), the walk-in discount you get when paying through District, promo codes, and the full list of live offers with their time slots. You can also add bank and card offers.
- **Rich, clean contact data.** 150 of 150 restaurants in a test across Delhi NCR, Bengaluru and Hyderabad had a phone number, address, coordinates, hours, cuisines, cost for two and rating.
- **Fast and cheap.** 50 restaurants with full details take about 15 seconds. Listing-only runs (details off) are faster still: 800 restaurants in 22 seconds.
- **Reliable.** It uses fresh IPs, retries, and switches to Indian residential IPs automatically if it is ever blocked. It never ends a run in failure because of a slow page: it saves what it has and finishes before your timeout.

### Input examples

Top-rated restaurants in Mumbai:

```json
{ "mode": "location", "locations": ["Mumbai"], "sortBy": "rating", "maxItems": 50 }
```

North Indian places in Bengaluru that serve alcohol, cost ₹1,000–1,500 for two and are rated 4.0 or higher, cheapest first:

```json
{
  "locations": ["Bengaluru"],
  "sortBy": "costLowToHigh",
  "cuisines": ["North Indian"],
  "quickFilters": ["servesAlcohol"],
  "costForTwo": ["1000to1500"],
  "minRating": "4.0",
  "maxItems": 200
}
```

The biggest discounts in a neighbourhood:

```json
{ "locations": ["Koramangala, Bengaluru"], "sortBy": "offer", "quickFilters": ["offer50"] }
```

Biryani across all of Hyderabad:

```json
{ "mode": "search", "locations": ["Hyderabad"], "keywords": ["biryani"], "coverWholeCity": true, "maxItems": 300 }
```

Specific restaurants:

```json
{
  "mode": "restaurants",
  "restaurants": [
    "https://www.district.in/dining/ncr/mount-fuji-japanese-pan-asian-restaurant-bar-connaught-place-new-delhi",
    "https://www.zomato.com/mumbai/doolally-veera-desai-area/info",
    "20324919"
  ]
}
```

Every open restaurant in Gurgaon:

```json
{ "mode": "fullCity", "locations": ["Delhi NCR"], "urlContains": "gurgaon", "skipClosed": true, "maxItems": 0 }
```

#### Input reference

| Field | Meaning |
|---|---|
| `mode` | `location` (default), `search`, `restaurants`, or `fullCity`. |
| `locations` | Cities ("Delhi NCR", "Mumbai"), neighbourhoods ("Powai, Mumbai") or "lat, lng". |
| `keywords` | Search terms, used by Search mode. |
| `restaurants` | Links or ids, used by Specific restaurants mode. |
| `maxItems` | Total restaurants to return (default 100; 0 means no limit). |
| `maxItemsPerLocation` | Optional limit for each location, or for each term in Search mode. |
| `sortBy` | `popularity`, `rating`, `offer`, `costLowToHigh`, `costHighToLow`, or `distance`. |
| `cuisines` | Any of District's 87 cuisines, e.g. "Japanese" or "South Indian". |
| `quickFilters` | `openNow`, `openLate`, `pureVeg`, `servesAlcohol`, `outdoorSeating`, `petFriendly`, `cafes`, `fineDining`, `offer30`, `offer50`, `nearAndTopRated`. |
| `costForTwo` | `under1000`, `1000to1500`, `1500to2000`, `2000to2500`, `over2500`. |
| `minRating` | `3.5`, `4.0`, or `4.5`. |
| `coverWholeCity` | Repeat the query in every neighbourhood of the city. |
| `urlContains` | Every-restaurant mode only: keep only links that contain this text. |
| `skipClosed` | Leave out restaurants that are temporarily or permanently closed. |
| `includeDetails` | Full restaurant page data (default on). |
| `includeReviews`, `maxReviews` | Recent reviews, up to 10 per restaurant (rating, text, date, photos; never the reviewer's name). |
| `includeMenuImages` | Links to menu page photos, grouped by section. |
| `includeBankOffers` | Card and bank offers. |
| `maxConcurrency` | Number of parallel requests (default 20). |
| `proxyConfiguration` | Apify Proxy (default: automatic). |

### Output

One row per restaurant. Here is an abbreviated example:

```json
{
  "resId": "21851590",
  "name": "Paschim - Kohinoor Continental",
  "url": "https://www.district.in/dining/mumbai/paschim-kohinoor-continental-chakala",
  "city": "Mumbai",
  "locality": "Chakala",
  "address": "Lobby, Hotel Kohinoor Continental, Andheri - Kurla Road, J B Nagar, Chakala, Mumbai",
  "latitude": 19.1123022344,
  "longitude": 72.8679532385,
  "distanceKm": 2.6,
  "cuisines": ["North Indian", "Maharashtrian", "Kerala", "Rajasthani"],
  "costForTwo": 1500,
  "currency": "INR",
  "rating": 4.8,
  "ratingCount": 238,
  "ratingFood": 4.7,
  "ratingService": 4.7,
  "ratingAmbience": 4.7,
  "reviewCount": 32,
  "offerHeadline": "Flat 60% OFF",
  "discountPct": 60,
  "payDiscountPct": 25,
  "promoText": "FLAT ₹175 OFF",
  "offers": [
    { "text": "FLAT 60% OFF", "details": ["From 12:00 AM, today", "6 slots left"], "type": "preBook" },
    { "text": "FLAT 25% OFF", "details": ["No booking required", "Valid all day"], "type": "walkIn" }
  ],
  "isSponsored": false,
  "isOpenNow": true,
  "openStatus": "Open · 12:00 PM to 3:15 PM",
  "businessStatus": "ACTIVE",
  "openingHours": [{ "day": "Monday", "hours": "12 Noon - 3:15 PM, 7 PM - 11 PM" }],
  "phone": "+919004688669",
  "phones": ["+919004688669", "+919152148019"],
  "facilities": ["Kid-friendly", "Work friendly"],
  "amenities": ["Dinner", "Lunch", "Wine and beer", "All day breakfast", "Large group seating", "Kid friendly", "Cocktails"],
  "about": null,
  "mustTry": null,
  "whyPeopleGo": null,
  "reviewHighlights": [],
  "imageUrl": "https://b.zmtcdn.com/data/pictures/0/21851590/e0f1b313de3ac1616463757d39216e81.jpg",
  "images": ["https://b.zmtcdn.com/data/pictures/0/21851590/e0f1b313de3ac1616463757d39216e81.jpg"],
  "menuUpdated": "Updated 3 months ago",
  "menuPageCount": 29,
  "tableBookingUrl": "https://www.district.in/dining/mumbai/paschim-kohinoor-continental-chakala/book",
  "googleMapsUrl": "https://www.google.com/maps?q=19.1123022344,72.8679532385",
  "chainId": null,
  "rank": 9,
  "source": { "type": "location", "input": "Mumbai", "sortBy": "rating" },
  "scrapedAt": "2026-09-24T06:41:54.748Z"
}
```

Field notes:

- **Discounts.** `discountPct` is the best pre-book table discount. `payDiscountPct` is the walk-in discount for paying the bill through District. `offers` lists every live offer with its time slot and how many slots are left.
- **Missing values.** Fields are `null` when District has nothing to show. New places have no rating, some have no phone, and closed places have no hours. Lists are empty (`[]`), never `null`.
- **Rank.** `rank` is the position in District's list for your sort. Rows are saved as their details arrive, so sort by `rank` if the order matters to you.
- **Business status.** `businessStatus` is `ACTIVE`, `TEMP_CLOSED`, `TEMP_CLOSED_DINING`, `OPENING_SOON`, or similar.
- **Details off.** With details turned off, rows keep the listing fields (name, locality, cuisine, cost, rating, discount, distance and photo). Phone, address, coordinates and link need details.

### Use cases

- **Competitive pricing and promotions:** track which restaurants discount, by how much and at what times, by city, cuisine or price band.
- **Sales leads for restaurant tech, food suppliers and delivery services:** names, phones, addresses and GPS for every restaurant in a city or neighbourhood.
- **Market research:** restaurant density, cuisine mix, price points and ratings by neighbourhood.
- **Location intelligence:** exact coordinates and opening hours, ready for maps and site-selection models.
- **Joining with Zomato data:** restaurant ids match Zomato's.

### FAQ

**Which cities are covered?** Every Indian city where District lists restaurants. The biggest are Delhi NCR, Mumbai, Bengaluru, Pune, Hyderabad, Kolkata, Chennai, Ahmedabad, Jaipur, Chandigarh, Goa and Lucknow, plus hundreds of smaller cities.

**How many restaurants can I get for a city?** Browsing one location returns up to about 500 per sort and filter combination. **Cover the whole city** reaches thousands. **Every restaurant in a city** returns the city's full directory, including closed and delivery-only places; use `skipClosed` to drop the closed ones.

**How many results does Search return?** Up to 20 restaurants per term per location. With **Cover the whole city**, each term is searched in every neighbourhood. In a test, "pizza" across 5 Mumbai neighbourhoods returned 71 unique restaurants.

**Are reviews included?** Only if you turn on `includeReviews`. You get the latest reviews shown on each restaurant's page, up to 10, with rating, text, date and photos. Reviewers are private individuals, so their names, avatars and profiles are never included.

**Do I need a Zomato or District account?** No. No login needed: no account, cookie, phone number or API key. Datacenter proxies are enough (the free automatic Apify Proxy group works); residential proxies are only a fallback if requests start getting blocked.

**Is it legal to scrape District?** This actor collects only publicly available information that District shows to every visitor without logging in: restaurant names, business addresses, published restaurant phone lines, opening hours, ratings, prices, offers and menus, plus review texts and ratings if you turn reviews on. It does not collect information that identifies individual people: reviewer names, avatars and profiles are never included. Scraping public data is generally lawful, but how you use the results is up to you: follow the laws that apply to you (for example India's DPDP Act, GDPR, PIPEDA or CCPA) and District's terms, and check with a lawyer if you are unsure. Apify's guide is a good starting point: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

**Does it access any private data?** No. It reads only what District's public website serves to any visitor: restaurant pages, the public listing, search and the public restaurant sitemap. It never touches user accounts, bookings, orders, payments or anyone's personal profile.

**What does a run cost?** You pay per restaurant saved (the `restaurant` event), plus the small per-run start fee shown on the Pricing tab. Duplicates, closed restaurants you skip and restaurants that are not found are never charged.

**What if something goes wrong?** The run still finishes as *Succeeded*, keeps every restaurant it saved, and explains in its status message what happened and what to change. If your run's timeout is too short for District to answer, the message says so (60 s is plenty for the 50-restaurant example).

**Something looks wrong?** Open an issue on the actor's Issues tab and include your input.

# Actor input Schema

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

<b>Browse a location</b>: restaurants around a city or neighbourhood, with District's sort and filters (up to ~500 per location and filter set; turn on <i>Cover the whole city</i> for thousands).<br><b>Search</b>: restaurants matching a dish, cuisine or name near each location.<br><b>Specific restaurants</b>: District or Zomato restaurant links, or restaurant ids.<br><b>Every restaurant in a city</b>: the complete public directory of a city (includes closed and delivery-only places).

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

Cities ("Mumbai", "Delhi NCR", "Bengaluru"), neighbourhoods ("Powai, Mumbai", "Koramangala") or coordinates ("19.0760, 72.8777"). Used by every mode except <i>Specific restaurants</i>.

## `keywords` (type: `array`):

For <i>Search</i>: dishes, cuisines or restaurant names, e.g. "biryani", "sushi", "rooftop". District returns up to 20 restaurants per term and location; turn on <i>Cover the whole city</i> to repeat the search in every neighbourhood.

## `restaurants` (type: `array`):

For <i>Specific restaurants</i>: district.in/dining/... links, zomato.com restaurant links, or numeric restaurant ids (District and Zomato share ids).

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

Stop after this many restaurants in total. 0 = no limit.

## `sortBy` (type: `string`):

Browse mode only. District's own sort orders.

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

Only restaurants serving any of these cuisines, e.g. "North Indian", "Japanese", "Chinese", "Desserts". Names are matched to District's cuisine list (87 cuisines).

## `quickFilters` (type: `array`):

District's quick filters. All selected filters must match.

## `costForTwo` (type: `array`):

Price bands (in rupees).

## `minRating` (type: `string`):

Only restaurants rated at least this.

## `coverWholeCity` (type: `boolean`):

Repeat the query in every neighbourhood District knows for the city (Mumbai has 36, Pune 11; smaller cities get a grid) and merge the results without duplicates. Goes past the ~500-per-query limit: about 3,000 restaurants for Pune in 2.5 minutes. With the default sort, each neighbourhood is read nearest-first.

## `maxItemsPerLocation` (type: `integer`):

Optional cap for each location (and each search term in Search mode). Empty = only the overall limit applies.

## `urlContains` (type: `string`):

For <i>Every restaurant in a city</i>: keep only restaurants whose link contains this text, e.g. "koramangala", "gurgaon", "bandra-west". District links end with the neighbourhood and city.

## `skipClosed` (type: `boolean`):

Leave out restaurants District marks as temporarily or permanently closed (for dining or altogether). Most useful with <i>Every restaurant in a city</i>, whose directory still lists closed places.

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

Open each restaurant's page for phone, address, GPS, opening hours, rating count and food/service/ambience scores, facilities, highlights, photos and all live offers. Turn off for a faster, lighter listing (name, locality, cuisine, cost for two, rating, discount, distance). Always on for <i>Specific restaurants</i> and <i>Every restaurant in a city</i>.

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

Add the latest reviews shown on each restaurant page (rating, text, date, photos).

## `maxReviews` (type: `integer`):

Up to 10 (what District shows on the restaurant page).

## `includeMenuImages` (type: `boolean`):

Links to every menu page photo, grouped by menu section (Food, Bar, Beverages...).

## `includeBankOffers` (type: `boolean`):

Add the card and bank offers shown on each restaurant page (e.g. "10% OFF up to ₹1,200 on ... Credit Card").

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

Parallel requests. 20 is fast and safe.

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

Apify Proxy's automatic (datacenter) group works and is the cheapest. The actor switches to residential (India) proxies on its own if it gets blocked.

## Actor input object example

```json
{
  "mode": "location",
  "locations": [
    "Mumbai"
  ],
  "maxItems": 50,
  "sortBy": "rating",
  "minRating": "any",
  "coverWholeCity": false,
  "skipClosed": false,
  "includeDetails": true,
  "includeReviews": false,
  "maxReviews": 5,
  "includeMenuImages": false,
  "includeBankOffers": false,
  "maxConcurrency": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All scraped restaurants.

## `report` (type: `string`):

Status message, restaurant count and request statistics for this run.

## `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 = {
    "mode": "location",
    "locations": [
        "Mumbai"
    ],
    "maxItems": 50,
    "sortBy": "rating",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/district-dining-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 = {
    "mode": "location",
    "locations": ["Mumbai"],
    "maxItems": 50,
    "sortBy": "rating",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/district-dining-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 '{
  "mode": "location",
  "locations": [
    "Mumbai"
  ],
  "maxItems": 50,
  "sortBy": "rating",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yugenox/district-dining-scraper --silent --output-dataset

```

## MCP server setup

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