# OpenTable Scraper (`scraptivo/opentable-scraper`) Actor

Collects OpenTable restaurant listings and reviews — ratings, price band, cuisine, location, contact details, and availability — by search query (with date, time, and party size) or OpenTable URLs. Optionally enriches each restaurant with full profile details and diner reviews.

- **URL**: https://apify.com/scraptivo/opentable-scraper.md
- **Developed by:** [Scraptivo](https://apify.com/scraptivo) (community)
- **Categories:** Developer tools, Agents, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.70 / 1,000 restaurants

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

**OpenTable Scraper** collects restaurant listings, profile details, and diner reviews from OpenTable — ratings, price band, cuisine, location, and contact details — and turns them into structured data for market research, lead generation, and competitor monitoring. Search by city or cuisine, paste an OpenTable search URL, or target a specific restaurant profile, then export results to JSON, CSV, or Excel. Use it to map local dining markets, track ratings, and build contact lists. Pay per event: $2 per 1,000 restaurants, with optional details and reviews billed separately.

### What can you automate with OpenTable Scraper?

- **Map a city's dining scene** — collect restaurant directories by location or cuisine with ratings, price band, and review counts.
- **Capture competitor intelligence** — record hours, amenities, dress code, parking, website, and social links from profiles.
- **Mine diner reviews** — collect overall, food, service, ambience, and value scores with text and dates, capped per restaurant when needed.
- **Search by availability** — set reservation date, time, and party size so results reflect real availability.
- **Build lead lists** — gather phone, email, and website details for outreach or partnerships.
- **Export anywhere** — download structured data as JSON, CSV, or Excel, or stream it through the Apify API.

### Who is this scraper for?

| Team | Workflow |
|---|---|
| Market researchers | Analyze restaurant supply, price bands, and rating distributions in any city |
| Competitive analysts | Track how competitors' ratings, reviews, and hours change over time |
| Lead-generation teams | Build contact lists of restaurants for outreach or partnerships |
| Data teams | Feed structured restaurant data into CRMs, dashboards, or models |

### What data can you collect from OpenTable?

| Data group | Example fields | How it helps |
|---|---|---|
| Identity & ratings | `restaurantId`, `name`, `url`, `rating`, `reviewCount` | Match and deduplicate restaurants by their OpenTable ID |
| Location | `neighborhood`, `city`, `state`, `postCode`, `address`, `latitude`, `longitude` | Map restaurants and filter by geography |
| Offer & contact | `cuisine`, `priceBand`, `phone`, `website`, `diningStyle` | Understand the menu, price level, and how to reach them |
| Profile extras | `hoursOfOperation`, `amenities`, `hasTakeout`, `outdoorSeating`, `photos` | Enrich listings with full profile detail when enabled |
| Reviews | `reviews[]` with `overall`, `food`, `service`, `ambience`, `value` | Capture diner feedback when enabled |

*Profile and review fields are only returned when the matching input toggle is enabled.*

### How to use OpenTable Scraper

1. Open the Actor on Apify.
2. Add an OpenTable search URL or a search term (for example "Dresden" or "Italian in Berlin").
3. Optionally set the reservation date, time, and party size.
4. Enable listing details or reviews if you need deeper data.
5. Run the Actor and export the dataset to JSON, CSV, or Excel.

```json
{
    "searchQueries": ["Dresden"],
    "time": "19:00",
    "partySize": 2,
    "scrapeListingDetails": true,
    "scrapeReviews": true,
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": ["RESIDENTIAL"]
    }
}
```

### Example workflow

#### Build a weekly list of new restaurants in a city

1. Run a city search every week for the areas you cover.
2. Keep restaurants that are new or whose rating or review count changed.
3. Send new records to Google Sheets or a CRM.
4. Deduplicate using the stable `restaurantId` value.

### Automate and integrate your results

- **Schedules** — run daily to track ratings and review counts, or weekly for market research snapshots.
- **Webhooks** — trigger a webhook on run completion to update a database, spreadsheet, or notification pipeline automatically.
- **Integrations** — push results to Google Sheets, Make, Zapier, Slack, a CRM, or cloud storage, or call the Actor from the Apify API.
- **Deduplication** — each restaurant is keyed by its `restaurantId`; deduplicate across runs on `restaurantId`.

### Input reference

| Field | Type | Required | Default | What it controls |
|---|---|---|---:|---|
| `startUrls` | array | optional | — | OpenTable search or restaurant profile URLs (takes priority) |
| `searchQueries` | array | optional | — | Location or restaurant search terms, e.g. "Dresden" |
| `date` | string | optional | tomorrow | Reservation date (YYYY-MM-DD) for availability search |
| `time` | string | optional | 19:00 | Preferred dining time in 24h HH:MM |
| `partySize` | integer | optional | 2 | Number of diners (1–20) |
| `scrapeListingDetails` | boolean | optional | false | Fetch full profile details (hours, amenities, photos) |
| `scrapeReviews` | boolean | optional | false | Fetch diner reviews per restaurant |
| `maxReviews` | integer | optional | 0 | Max reviews per restaurant (0 = all) |
| `maxItems` | integer | optional | 0 | Maximum restaurants to collect (0 = unlimited) |
| `proxyConfiguration` | object | optional | residential | Proxy settings for reliable OpenTable access |

#### What is the difference between `startUrls` and `searchQueries`?

`startUrls` accepts exact OpenTable search or restaurant profile URLs and takes priority when provided. `searchQueries` are free-text terms such as "Dresden" or "Italian in Berlin", used when `startUrls` is empty.

### Output example

```json
{
    "restaurantId": 227388,
    "name": "Peter Pane - Dresden",
    "url": "https://www.opentable.com/r/peter-pane-dresden-am-zwinger-dresden",
    "cuisine": "Burgers",
    "priceBand": "€30 and under",
    "currencySymbol": "€",
    "rating": 4.5,
    "reviewCount": 515,
    "recentReservationCount": 21,
    "neighborhood": "Old Town",
    "city": "Dresden",
    "state": "SN",
    "postCode": "01067",
    "address": "Wilsdruffer Straße 14-16, Dresden, SN, 01067",
    "latitude": 51.0515654,
    "longitude": 13.7349184,
    "phone": "0351 48676840",
    "diningStyle": "Casual Dining",
    "hasTakeout": true,
    "outdoorSeating": false,
    "photoUrl": "https://resizer.otstatic.com/v3/photos/92048640-2?width=320&height=320&webp=true",
    "searchQuery": "Dresden",
    "detailsFetched": false,
    "reviewsFetched": false,
    "reviews": null
}
```

### How much does it cost to scrape OpenTable?

The Actor uses pay-per-event billing, so you pay only for the data you receive:

- **$2 per 1,000 restaurants** — charged as a `dataset-item` event for every restaurant saved to the dataset.
- **$3 per 1,000 restaurants** — charged as a `listing-details` event, only when `scrapeListingDetails` is enabled.
- **$2 per 1,000 restaurants** — charged as a `restaurant-reviews` event, only when `scrapeReviews` is enabled.

A run also charges a one-time $0.00005 actor-start event. Higher Apify plans (Bronze, Silver, Gold) apply discounted per-event rates, up to 15% off. Use `maxItems` and `maxReviews` to control spend exactly.

### Reliability and responsible use

- **Proxy** — Apify Residential proxies are strongly recommended; the default configuration enables them.
- **Enrichment controls** — listing details and reviews are only collected when their toggles are enabled, keeping listing-only runs faster and cheaper.
- **Conditional fields** — profile and review fields are null unless the matching toggle is on.
- **Availability snapshots** — reservation availability reflects the moment of the run; treat it as a point-in-time snapshot.
- **Lawful use** — you are responsible for using collected data in line with OpenTable's terms and applicable laws.

### Frequently asked questions

#### Can I collect reviews for a single restaurant?

Yes. Put the restaurant profile URL (`https://www.opentable.com/r/...`) in `startUrls`, set `scrapeReviews` to true, and optionally cap with `maxReviews`.

#### Can I schedule OpenTable Scraper to run automatically?

Yes. Use the Scheduler tab in Apify Console to run daily or weekly, and set up webhooks to push fresh data into your pipeline.

#### What counts as one result?

Each restaurant saved to the dataset bills one `dataset-item` event. Enabling details adds a `listing-details` event per restaurant; enabling reviews adds a `restaurant-reviews` event per restaurant.

#### Why did my run return no restaurants?

OpenTable may be limiting requests. Keep the default Apify Residential proxy enabled in `proxyConfiguration`, and retry with a different query or date.

#### How do I avoid duplicate records?

Deduplicate by `restaurantId`, which is stable across runs. You can also cap output with `maxItems`.

#### Do I need a proxy?

Yes. Residential proxies are strongly recommended for reliable OpenTable access; keep the default configuration enabled.

### Related Scraptivo automations

- **[Yelp Scraper](https://apify.com/scraptivo/yelp-scraper)** — collect Yelp business listings, ratings, and reviews.
- **[TripAdvisor Reviews Scraper](https://apify.com/scraptivo/tripadvisor-reviews-scraper)** — collect restaurant and hotel reviews from TripAdvisor.
- **[Instacart Scraper](https://apify.com/scraptivo/instacart-scraper)** — collect menus, stores, and delivery data from Instacart.
- **[Publix Scraper](https://apify.com/scraptivo/publix-scraper)** — collect Publix product and store data.

### Support and custom workflows

Need a different field, source, or delivery workflow? Contact Scraptivo at scraptivo@gmail.com. Include the Actor name, a sample URL, the required fields, and expected volume so we can assess the request.

# Actor input Schema

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

OpenTable search URLs (https://www.opentable.com/s?...) or restaurant profile URLs (https://www.opentable.com/r/...). Takes priority when provided.

## `searchQueries` (type: `array`):

Location or restaurant search terms (e.g. Dresden, New York, Italian in Berlin). Used when startUrls are empty. Resolved via OpenTable autocomplete.

## `date` (type: `string`):

Date for availability search (YYYY-MM-DD). Defaults to tomorrow when omitted. Also used when parsing searchQueries.

## `time` (type: `string`):

Preferred dining time in 24h HH:MM format (e.g. 19:00).

## `partySize` (type: `integer`):

Number of diners (covers) for the search.

## `scrapeListingDetails` (type: `boolean`):

When enabled, opens each restaurant profile page and extracts full details (hours, dress code, website, amenities, photos, etc.). Charges a listing-details event per restaurant.

## `scrapeReviews` (type: `boolean`):

When enabled, paginates and extracts reviews for each restaurant. Charges a restaurant-reviews event per restaurant. Nested under the reviews field on each dataset item.

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

Maximum reviews to extract per restaurant when scrapeReviews is enabled (0 = all reviews).

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

Maximum number of restaurants to scrape (0 = unlimited).

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

Proxy settings. Residential proxies are strongly recommended — OpenTable uses Akamai Bot Manager and blocks most datacenter IPs.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.opentable.com/s?dateTime=2026-08-15T19%3A00%3A00&covers=2&latitude=51.052008&longitude=13.741322&areaId=geohash%3Au31f2twp&suggestedSearchName=Dresden&shouldUseLatLongSearch=true&showMap=true"
    }
  ],
  "searchQueries": [
    "Dresden"
  ],
  "time": "19:00",
  "partySize": 2,
  "scrapeListingDetails": false,
  "scrapeReviews": false,
  "maxReviews": 10,
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

JSON array of scraped restaurants at {{links.apiDefaultDatasetUrl}}/items

## `runStats` (type: `string`):

Aggregate scrape stats (counts, timestamps)

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

Apify Console link to inspect 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 = {
    "startUrls": [
        {
            "url": "https://www.opentable.com/s?dateTime=2026-08-15T19%3A00%3A00&covers=2&latitude=51.052008&longitude=13.741322&areaId=geohash%3Au31f2twp&suggestedSearchName=Dresden&shouldUseLatLongSearch=true&showMap=true"
        }
    ],
    "searchQueries": [
        "Dresden"
    ],
    "time": "19:00",
    "scrapeListingDetails": false,
    "scrapeReviews": false,
    "maxReviews": 10,
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraptivo/opentable-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 = {
    "startUrls": [{ "url": "https://www.opentable.com/s?dateTime=2026-08-15T19%3A00%3A00&covers=2&latitude=51.052008&longitude=13.741322&areaId=geohash%3Au31f2twp&suggestedSearchName=Dresden&shouldUseLatLongSearch=true&showMap=true" }],
    "searchQueries": ["Dresden"],
    "time": "19:00",
    "scrapeListingDetails": False,
    "scrapeReviews": False,
    "maxReviews": 10,
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scraptivo/opentable-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 '{
  "startUrls": [
    {
      "url": "https://www.opentable.com/s?dateTime=2026-08-15T19%3A00%3A00&covers=2&latitude=51.052008&longitude=13.741322&areaId=geohash%3Au31f2twp&suggestedSearchName=Dresden&shouldUseLatLongSearch=true&showMap=true"
    }
  ],
  "searchQueries": [
    "Dresden"
  ],
  "time": "19:00",
  "scrapeListingDetails": false,
  "scrapeReviews": false,
  "maxReviews": 10,
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call scraptivo/opentable-scraper --silent --output-dataset

```

## MCP server setup

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