OpenTable Scraper at a glance
OpenTable Scraper is a ready-to-run Apify actor from abotapi for collecting automation data. Its documented output includes restaurant, review, overall, food and service, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $1.80 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify.
- Runs on
- Apify cloud: console, API, schedules and integrations
- Data type
- Automation, Developer Tools, Other
- Pricing
- $1.80 per 1,000 results (Free plan), from $1.00 on paid plans
- Output
- Documented below · JSON, CSV, Excel
- Inputs
- 33 options
Scrape full OpenTable.com restaurant reviews by keyword, area, or restaurant profile URLs. Collect every available review with text, ratings, diner profile data, tags, photos, restaurant metadata, cuisines, neighborhood, and profile links in structured rows.
What OpenTable Scraper can do
- Two ways to find restaurants. Search by keyword and location, or paste OpenTable restaurant links directly. No need to look up restaurant IDs by hand.
- Full review depth on every row. Review text plus five per-category ratings, food, service, ambience, value and noise, not just the single overall star score.
- Deep filtering. Minimum rating per category, cuisine, neighborhood, VIP reviewers only, photos only, and a dined date window, so you only pay for reviews that match.
- Restaurant context on every row. Cuisine, neighborhood, restaurant level rating and total review count are carried on each review, so no extra join is needed. When the restaurant page can be read, each row also carries the restaurant's address, phone, website, opening hours, dining style, dress code, parking, payment options, public transit, coordinates, photo count, review summary and rating distribution.
- Built to run at scale. Resume an interrupted pull without paying twice, and cap reviews per restaurant independently from the run wide total.
- Built for schedules. Incremental mode returns only new, updated and reappeared reviews on repeat runs, classified per review.
Choose what to collect
These inputs let you configure OpenTable Scraper - Restaurants, Ratings & Diner Data. Open the actor on Apify to enter your values and review the current options.
| Input | What it controls |
|---|---|
modestring · required | Search mode discovers restaurants around the selected coordinates and collects their full review history. URL mode takes pasted restaurant profile links and collects every review for each one. |
keywordsarray | Restaurant, cuisine, or dining terms to search. Examples: sushi, steakhouse, rooftop, vegan. An OpenTable restaurant link (/r/) pasted here is treated as a restaurant URL. |
locationstring | City, neighborhood, or address to search around (keyword search mode). For example: New York, Chelsea Manhattan, or 90210. The actor resolves this to map coordinates automatically. |
latitudenumber | Optional. Exact latitude to search around. When both latitude and longitude are set they override Location. |
longitudenumber | Optional. Exact longitude to search around. When both latitude and longitude are set they override Location. |
startUrlsarray | Paste OpenTable links: a restaurant page (/r/), a search page (/s?term=...), a city listings page (/metro/-restaurants or /-restaurant-listings) or a numeric restaurant id link (/restaurant/profile/). Other or localized links are skipped with a warning. |
maxItemsinteger | Maximum review rows to save across the whole run. The run can return fewer rows when OpenTable has fewer matching reviews. |
Show 26 more inputs
| Input | What it controls |
|---|---|
maxReviewsPerRestaurantinteger | Optional cap on how many reviews to collect from each restaurant. The default (1000000) is effectively no per-restaurant limit, so collection is bounded only by Max items. |
maxRestaurantsinteger | Keyword search only. How many restaurants around the coordinates to collect reviews from per keyword. |
reviewSortstring | Order of reviews returned for each restaurant. |
minOverallRatingnumber | Only keep reviews with at least this overall review rating. |
minFoodRatingnumber | Only keep reviews with at least this food rating. |
minServiceRatingnumber | Only keep reviews with at least this service rating. |
minAmbienceRatingnumber | Only keep reviews with at least this ambience rating. |
minValueRatingnumber | Only keep reviews with at least this value rating. |
cuisinesarray | Only keep restaurants whose primary or secondary cuisine contains at least one value. |
neighborhoodsarray | Only keep restaurants whose neighborhood contains at least one value. |
fromDinedDatestring | Only keep reviews with a dined date on or after this YYYY-MM-DD date. |
toDinedDatestring | Only keep reviews with a dined date on or before this YYYY-MM-DD date. |
dateTimezonestring | Optional IANA timezone (e.g. Australia/Melbourne, America/New_York). OpenTable's page prints each dining time in the viewer's own browser timezone, so a viewer in a different timezone can see a different day than the restaurant's local one. Set your timezone to make the dined date and the Dined from / to filters match what you see on OpenTable. Empty = the restaurant's local date. Setting it starts a new baseline for recurring (incremental) runs. |
fromReviewDatestring | Only keep reviews posted (submitted) on or after this YYYY-MM-DD date. Independent of the dined date. |
toReviewDatestring | Only keep reviews posted (submitted) on or before this YYYY-MM-DD date. |
vipOnlyboolean | Only keep reviews where OpenTable marks the reviewer as VIP. |
requireReviewPhotosboolean | Only keep reviews that include diner photos. |
resumeFromRunIdstring | Paste a previous run ID or dataset ID to continue a large review pull without returning or charging for reviews already collected there. Use this after an interrupted run, or when continuing a large restaurant's review history in another run. For recurring monitoring of the same search or restaurants, use Incremental mode below instead. |
incrementalModeboolean | Turn this on for daily or recurring monitoring. The first run returns all matching reviews as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED reviews. A review is UPDATED when its own content changes: review text, any rating, dined or submitted date, reply text, reviewer details, photo count, or the restaurant name, cuisine or location. Changes to the helpful counters, the restaurant rating and total review count, and photo links never count (they still appear in the output); add more with "Ignore fields when detecting changes". Turn on "Emit unchanged" or "Emit expired" only when you also want those reviews returned (and billed). State is kept separately for each search/URL and filter setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above. |
emitUnchangedboolean | Off by default. Turn on to also return reviews that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want the full snapshot every run. |
emitExpiredboolean | Off by default. Turn on to also return reviews that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked restaurants, not when Max items capped it, when Resume was used, or when a keyword search may have been truncated. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking. |
stateKeystring | Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the search/URL and filter settings, different searches then never mix state with each other. |
ignoreFieldsForChangesarray | Incremental mode only: changes to ONLY these fields do not mark a review UPDATED (the fields still appear in the output). Add your own field names, or a dotted path for a nested field. Already ignored by default: scrapedAt, the helpful counters (reviewHelpfulUp, reviewHelpfulDown, reviewHelpfulScore), the restaurant counters (restaurantRating, restaurantTotalReviewCount) and the photo links (restaurantPhotoUrl, reviewerPhotoUrl, reviewPhotoUrls). |
mcpConnectorsarray | Optionally send scraped review rows into connected apps via Model Context Protocol connectors. Authorize a connector under Apify > Settings > API & Integrations, then select it here. Supported: Notion, Linear, Airtable, and Apify. |
notionParentPageUrlstring | URL or id of the Notion page under which review pages are created. Required for Notion export; ignored by other connectors. |
maxNotifyListingsinteger | Cap on how many review rows are written to each selected connector per run. Does not affect the dataset. |
Fields in the output
The documented dataset includes the fields below. Availability can depend on the source page and selected mode.
restaurantNameRestaurant (text)reviewTextReview (text)ratingOverallOverall (number)ratingFoodFood (number)ratingServiceService (number)ratingAmbienceAmbience (number)ratingValueValue (number)ratingNoiseNoise (text)dinedDateDined date (date)reviewerNameReviewer (text)reviewerLocationReviewer location (text)reviewHelpfulScoreHelpful score (number)Show 71 more fields
restaurantReplyTextRestaurant reply (text)restaurantPrimaryCuisineCuisine (text)restaurantNeighborhoodNeighborhood (text)restaurantRatingRestaurant rating (number)restaurantTotalReviewCountTotal reviews (number)restaurantUrlRestaurant URL (link)reviewIdReview ID (text)scrapedAtScraped at (date)changeTypeChange type (text)changedFieldsChanged fields (text)firstSeenAtFirst seen at (date)lastSeenAtLast seen at (date)submittedDateTimePosted at (date)dinedDateTimeDined at (date)reviewTypeReview type (text)reviewerIsVipReviewer VIP (boolean)reviewerApprovedReviewCountReviewer review count (number)reviewHelpfulUpHelpful up (number)reviewHelpfulDownHelpful down (number)reviewPhotoUrlsReview photos (array)reviewPhotoCountReview photo count (number)restaurantIdRestaurant ID (number)restaurantCuisinesCuisines (array)restaurantMetroMetro (text)restaurantMacroRegion (text)restaurantPriceBandPrice band (text)restaurantCurrencySymbolCurrency symbol (text)sourceModeSource mode (text)sourceQuerySource query (text)sourceUrlSource URL (link)restaurantAddressLine1Address (text)restaurantCityCity (text)restaurantStateState (text)restaurantPostalCodePostal code (text)restaurantCountryCountry (text)restaurantCountryCodeCountry code (text)restaurantLatitudeLatitude (number)restaurantLongitudeLongitude (number)restaurantPhonePhone (text)restaurantPhoneIntlPhone (international) (text)restaurantWebsiteWebsite (link)restaurantHoursOpening hours (text)restaurantDiningStyleDining style (text)restaurantDressCodeDress code (text)restaurantDescriptionDescription (text)restaurantPhotosCountPhotos (number)restaurantParkingInfoParking (text)restaurantPaymentOptionsPayment options (array)restaurantPublicTransitPublic transit (text)restaurantCrossStreetCross street (text)restaurantExecutiveChefExecutive chef (text)restaurantAdditionalDetailsAdditional details (array)restaurantFeaturesFeatures (array)restaurantPopularDishesPopular dishes (array)restaurantDeliveryPartnersDelivery partners (array)restaurantMetroIdMetro ID (number)restaurantNeighborhoodIdNeighborhood ID (number)restaurantReviewSummaryReview summary (text)restaurantRatingBasedOnRating based on (text)restaurantRatingDistributionRating distribution (text)restaurantReviewCategoriesReview categories (array)restaurantAwardsAwards (array)restaurantAccessibilityDetailsAccessibility (array)restaurantHasGenderNeutralRestroomGender-neutral restroom (boolean)restaurantIsGroceryStoreGrocery store (boolean)restaurantCallForDeliveryCall for delivery (boolean)restaurantCurrencyCodeCurrency code (text)restaurantRecommendCountDiners who recommend (number)restaurantDontRecommendCountDiners who do not recommend (number)restaurantHasAffiliatedRestaurantsHas affiliated restaurants (boolean)restaurantNetworkListingStatusNetwork listing status (boolean)Example output
An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.
{
"reviewId": "OT-1000001-2100000001-100000000001",
"reviewText": "Great spot for a birthday dinner, the staff were attentive all night and the sushi was excellent.",
"ratingOverall": 5,
"ratingFood": 5,
"ratingService": 4,
"ratingAmbience": 5,
"ratingValue": 4,
"ratingNoise": "MODERATE",
"reviewType": "OPENTABLEVERIFIED",
"submittedDateTime": "2026-06-10T16:02:39Z",
"dinedDateTime": "2026-06-09T18:45:00-04:00",
"dinedDate": "2026-06-09",
"reviewHelpfulUp": 2,
"reviewHelpfulDown": 0,
"reviewHelpfulScore": 2,
"restaurantReplyText": null,
"reviewerName": "Jordan K.",
"reviewerInitials": "JK",
"reviewerIsVip": false,
"reviewerLocation": "New York City",
"reviewerApprovedReviewCount": 3,
"reviewerProfileColor": "#3E7C59",
"reviewerPhotoUrl": null,
"reviewPhotoUrls": [
"https://www.opentable.com/example-assets/photos/sample-1.jpg"
],
"reviewPhotoCount": 1,
"restaurantId": 1000001,
"restaurantName": "Sample Sushi House",
"restaurantUrl": "https://www.opentable.com/r/sample-sushi-house-new-york",
"restaurantMetro": "New York City",
"restaurantMacro": "Northeast",
"restaurantNeighborhood": "Tribeca",
"restaurantPrimaryCuisine": "Japanese",
"restaurantCuisines": [
"Japanese",
"Sushi"
],
"restaurantPriceBand": 3,
"restaurantCurrencySymbol": "$",
"restaurantRating": 4.7,
"restaurantPhotoUrl": "https://www.opentable.com/example-assets/restaurants/sample-profile.jpg",
"restaurantTotalReviewCount": 5397,
"restaurantAddressLine1": "100 Example St",
"restaurantCity": "New York",
"restaurantState": "NY",
"restaurantPostalCode": "10007",
"restaurantCountryCode": "US",
"restaurantPhone": "(212) 555-0100",
"restaurantWebsite": "https://www.example.com/sample-sushi-house",
"restaurantDiningStyle": "Casual Elegant",
"restaurantDressCode": "Business Casual",
"restaurantPaymentOptions": [
"AMEX",
"Visa"
],
"sourceMode": "search",
"sourceQuery": "sushi",
"sourceUrl": null,
"scrapedAt": "2026-06-15T09:12:00.000000+00:00"
}Ways to use this data
- Reputation management: track new reviews and rating trends for your own restaurants as they come in.
- Competitive research: compare food, service, ambience and value ratings, and cuisine mix, across nearby restaurants.
- Market research: build a dataset of diner sentiment and review volume across neighborhoods or cities.
- Lead generation: find highly rated restaurants and their OpenTable profile links for outreach or listing sites.
- AI and NLP: feed review text into sentiment analysis, review summarization, or an AI agent answering "where should I eat" questions.
Before you run
Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.
Questions about this actor
What data does OpenTable Scraper return?
The documented output for OpenTable Scraper includes restaurant, review, overall, food, service, ambience, value and noise. Availability of each field depends on the source page and the selected mode.
How much does OpenTable Scraper cost?
It costs $1.80 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.
Can I get only new reviews on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then classifies every review as new, updated, unchanged, reappeared, or expired against the previous run for that search, and unchanged reviews are not billed unless you turn that on.
Why do I get one row with "error": true instead of an empty dataset?
When a run finds zero matching reviews, whether from an unmatched search, an unresolved restaurant URL, or filters that exclude everything, the actor pushes a single row shaped like {"error": true, "code": "ZERO_RESULTS", "message": "..."} instead of leaving the dataset empty, so "nothing matched" is never confused with a run that silently produced nothing. Try broader keywords, nearby coordinates, fewer filters, or different restaurant URLs.
Why did my run fail instead of returning results?
A run fails, rather than returning an empty or ZERO_RESULTS dataset, when the actor could not establish a working connection to OpenTable at all, when it lost that connection partway through, could not recover, and had not saved any reviews yet (if some reviews were already saved, the run finishes with those partial results), when resumeFromRunId points at a run or dataset ID it cannot read, or when Incremental mode already has saved state for a search and resumeFromRunId is set at the same time. Each of these stops the run with a clear status message describing what to check or retry.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration, or from an AI agent through Apify's MCP server.
