# Restaurant Discovery API by City (`quiago/restaurant-discovery-api`) Actor

Restaurants by city/country: ratings, reviews count, phone, address, coordinates, price, menu, cuisines, hours, delivery/booking, awards and review snippets. Optional full reviews.

- **URL**: https://apify.com/quiago/restaurant-discovery-api.md
- **Developed by:** [Carlos Quiala](https://apify.com/quiago) (community)
- **Categories:** Lead generation, Automation, Travel
- **Stats:** 4 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 restaurant records

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Restaurant Discovery API by City

Get **every restaurant in a city, country or TripAdvisor geo** with the data
you actually need — ratings, contact details, location, menus, hours,
cuisines, awards and review snippets — plus **optional full reviews**.

This is not "just reviews". It's a **restaurant directory + local discovery +
review intelligence** dataset, ready for market research, recommendation
apps and hospitality lead-gen.

### Why this Actor

- 🌍 **Search by name or geoId** — type `Dubai` or `Spain`, or pass an exact
  `geoId`.
- 📦 **Complete records** — 25+ fields per restaurant, consistent nulls,
  arrays for cuisines / schedule / snippets, numeric coordinates.
- 🔁 **Beyond the 10k cap** — large geos are recursively partitioned by
  facets with global de-duplication, so you get the *full* catalog.
- 🎯 **Server-side filters** — `minRating`, `minReviews`, `onlyOpenNow`,
  `includeSponsored`, applied before optional review enrichment.
- 💬 **Optional full reviews** — text, ratings per aspect, owner responses.
- 🛡️ **Resilient** — real-browser session warm-up, rate limiting, backoff,
  session rotation, proxy support.

### Input

| Field | Description |
|---|---|
| `query` | City / country / municipality name (e.g. `Dubai`, `Spain`) |
| `geoId` | Exact TripAdvisor geo id (e.g. `295424`) — overrides `query` |
| `maxItems` | Cap on restaurants fetched (**default 100**) |
| `getAllResults` | Ignore `maxItems` and fetch the **entire** geo (auto-partitions) |
| `includeSponsored` | Keep paid listings (default `true`) |
| `minRating` | Keep only rating ≥ value (0–5) |
| `minReviews` | Keep only with ≥ N reviews |
| `onlyOpenNow` | Keep only currently open |
| `withReviews` | Also fetch full reviews per restaurant |
| `reviewsLimit` | Reviews per restaurant (empty = all) |
| `proxyConfiguration` | **Use Apify Residential** (prefilled) |

Minimal run:

```json
{ "query": "Dubai", "maxItems": 100, "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] } }
```

### Output

One item per restaurant in the dataset. Real example (trimmed):

```json
{
  "geo_id": 295424,
  "location_id": 1062228,
  "name": "Fish Market",
  "url": "https://www.tripadvisor.com/Restaurant_Review-g295424-d1062228-Reviews-Fish_Market-Dubai_Emirate_of_Dubai.html",
  "rating": 4.6,
  "review_count": 1147,
  "telephone": "+971 4 205 7033",
  "full_address": "2nd Floor, Plaza Building, Baniyas Road, Deira, Dubai 0000 United Arab Emirates",
  "postal_code": "0000",
  "country": "United Arab Emirates",
  "parent_geo": "Dubai",
  "parent_geo_id": 295424,
  "latitude": 25.265236,
  "longitude": 55.31004,
  "price_range": "$$$$",
  "menu_url": null,
  "cuisines": ["Seafood"],
  "establishment_types": ["Restaurants"],
  "open_status": "OPEN",
  "open_status_text": "Open now",
  "has_delivery": null,
  "has_reservation": null,
  "is_sponsored": false,
  "is_premium": false,
  "award_type": "COE",
  "award_year": 2025,
  "thumbnail": "https://dynamic-media-cdn.tripadvisor.com/media/photo-o/23/5d/a7/72/fish-market-restaurant.jpg?w={width}&h={height}&s=1",
  "schedule": { "mon": [{ "open_time": "12:30:00", "close_time": "23:00:00" }], "tue": "..." },
  "review_snippets": [
    {
      "text": "You can pick from a wide variety of fish seabass, snapper, salmon to calamari...",
      "url": "https://www.tripadvisor.com/ShowUserReviews-g295424-d1062228-r1033153743-Fish_Market-Dubai_Emirate_of_Dubai.html"
    }
  ],
  "reviews": []
}
```

When `withReviews` is enabled, each restaurant's `reviews[]` is filled with
real review objects:

```json
{
  "review_id": 939549784,
  "restaurant_name": "Swiss Butter",
  "rating": 5,
  "title": "Amazing!",
  "text": "The food was delicious and the service was amazing. Everyone was so friendly. Their secret sauce was incredible, i dipped literally everything in it. Can't wait to go back.",
  "language": "en",
  "published_date": "2024-02-26",
  "trip_type": "FRIENDS",
  "user_name": "Julia Marie C",
  "user_contributions": 2,
  "additional_ratings": { "Value": 5, "Service": 5, "Food": 5, "Atmosphere": 5 },
  "mgmt_response_text": "Thank you for your feedback💚",
  "mgmt_response_date": "2024-02-27",
  "photos": []
}
```

### Use cases

1. **Market research / BI** — benchmark a city by rating, review volume,
   cuisine mix, price level and awards.
2. **Recommendation & travel apps** — geo, hours, menus, snippets and
   delivery / booking signals out of the box.
3. **Hospitality lead-gen** — phone, address, URL and type for outreach or
   enrichment, filtered by `minReviews` / `minRating`.

### How it works & limitations

- A real browser warms the session (solving TripAdvisor's datadome
  challenge), then fast HTTP pagination reuses that session.
- Geos above TripAdvisor's ~10,000 cap are split recursively by facets
  (neighbourhoods → cuisines → …) and de-duplicated globally.
- **Use Apify Residential proxies.** Datacenter IPs are challenged and may
  return no data. The input prefills the residential group.
- `maxItems` caps fetched rows; filters reduce the final count afterwards —
  raise `maxItems` if you need N rows *after* filtering.
- Data comes from TripAdvisor's public pages; use responsibly and in line
  with applicable terms and local regulations.

# Actor input Schema

## `query` (type: `string`):

Place name to resolve to a geoId (e.g. "Dubai", "Spain"). Ignored if geoId is set. Defaults to "Dubai" so a zero-config run works.

## `geoId` (type: `integer`):

Exact TripAdvisor geo id (e.g. 295424 for Dubai). Takes precedence over the query.

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

Cap on restaurants fetched (before filtering). Default 100. Ignored when 'Get ALL results' is on.

## `getAllResults` (type: `boolean`):

Ignore 'Max restaurants' and fetch the entire geo (auto-partitions geos above TripAdvisor's ~10k cap). Can be large and slow.

## `includeSponsored` (type: `boolean`):

Keep paid/sponsored listings mixed with organic ones.

## `minRating` (type: `number`):

Keep only restaurants with rating >= this value (0-5).

## `minReviews` (type: `integer`):

Keep only restaurants with at least this many reviews.

## `onlyOpenNow` (type: `boolean`):

Keep only restaurants currently open.

## `withReviews` (type: `boolean`):

Also fetch full reviews per restaurant (slower / more units).

## `reviewsLimit` (type: `integer`):

Cap reviews per restaurant. Empty = all reviews. Only used when 'Fetch full reviews' is on.

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

Strongly recommended: use Apify Residential proxies. Datacenter IPs are challenged by TripAdvisor's anti-bot (datadome).

## Actor input object example

```json
{
  "query": "Dubai",
  "maxItems": 100,
  "getAllResults": false,
  "includeSponsored": true,
  "onlyOpenNow": false,
  "withReviews": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `restaurants` (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 = {
    "query": "Dubai",
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("quiago/restaurant-discovery-api").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 = {
    "query": "Dubai",
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("quiago/restaurant-discovery-api").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 '{
  "query": "Dubai",
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call quiago/restaurant-discovery-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,quiago/restaurant-discovery-api"
        }
    }
}

```

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/P6td9k2hStwvOxvHh/builds/z7EfTri0jaTfGfbms/openapi.json
