Resy Scraper - Restaurants & Live Table Availability
Pricing
from $1.20 / 1,000 restaurant records
Resy Scraper - Restaurants & Live Table Availability
Scrape Resy restaurants and live reservation availability by city or URL. Get bookable times by date and party size, plus ratings, cuisine, price, phone, website, photos, and coordinates. Includes availability monitoring, resume, and MCP export.
Pricing
from $1.20 / 1,000 restaurant records
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
2
Bookmarked
1
Total users
1
Monthly active users
21 hours ago
Last modified
Categories
Share
Resy Scraper: Restaurants, Profiles & Live Table Availability
Resy Scraper turns Resy (resy.com) into a queryable restaurant availability feed. For every restaurant it returns the bookable times for your date and party size, plus rating, cuisine, price band, phone, website, photos and location. Turn on one setting to also pull the full profile: street address, menu link, awards and a two week availability calendar. Search whole cities by name, or paste exact restaurant links, then export to JSON, CSV or Excel, or pull results straight into your app through the API.
No account, sign-in or key of any kind is required: the actor reads the same public data the resy.com website itself reads in a visitor's browser.
Availability is live and time dependent: which restaurants have tables at which times changes by the hour, so two runs of the same search can legitimately return different slot lists. That is the signal, not noise, and incremental mode (below) is how you read only what changed.
This actor is not affiliated with Resy or American Express. Data is read from the public website on your behalf; respect the source and your plan's fair use.
Why This Scraper?
- Live, honest availability. Every restaurant ships with its actual bookable times for your date, party size and optional earliest time, and a fully booked restaurant comes back as a real zero slot answer instead of being dropped.
- Two ways to read it. Walk a whole city's restaurant list page by page, or paste exact restaurant links and read just those.
- One read per page, not per restaurant. A city search costs one page read for every 20 restaurants; the full profile read is priced per restaurant, and it is optional in search mode (URL mode always reads it).
- Full profiles on demand. Turn on one setting to also pull each restaurant's street address, phone, website, menu link, awards and a two week availability calendar.
- About 2,100 cities. Mostly United States, plus Mexico, Spain, Italy and Canada, matched by slug, name, page link or coordinates.
- Built for monitoring. Incremental mode returns only new, updated, reappeared, and (on a complete scan) expired restaurants on repeat runs, and a resumed run never re-adds what you already collected.
- No account needed. The actor reads the same public data the resy.com website itself reads in a visitor's browser; nothing is signed in on your behalf.
Use Cases
- Reservation hunting tools and bots: watch specific restaurants or whole neighborhoods for a table to open up at the time and party size you want.
- Dining recommendation and discovery apps: feed cuisine, price band, rating and live availability into your own restaurant finder.
- Hospitality and market research: track price bands, ratings, collections and awards across a city's dining scene.
- Group and event planners: check bookable times and seating types across a shortlist of restaurants for one date and party size in a single run.
- Availability alert services: schedule incremental runs and notify users the moment a watched restaurant's table shows up as NEW or UPDATED.
Data You Get
Sample shape: values are illustrative placeholders, not from a live record.
| Field | Example |
|---|---|
kind | "venue" |
recordId / venueId | "87654" / 87654 |
name / url / urlSlug | "Sample Bistro Alpha" / Resy link / "example-restaurant" |
citySlug / cityName | "new-york-ny" / "New York" |
neighborhood / locality / region / country | "Sample Neighborhood" / "New York" / "NY" / "US" |
streetAddress / postalCode / crossStreet | full profile only: "123 Sample Street" / "10001" / "Sample Avenue" |
latitude / longitude | 40.7128 / -74.006 |
cuisine | ["Italian"] |
priceRange / priceRangeSymbol | 2 (1 to 4) / "$$" |
rating / ratingCount | 4.3 / 128 |
collections / awards / venueGroupName | tags, honors, restaurant group name (when present) |
availabilityDate / partySize | "2026-12-31" / 4 (your run's date and party size) |
isAvailable / slotCount / firstSlotTime / lastSlotTime / seatingTypes | true / 2 / "18:00" / "20:30" / ["Bar", "Dining Room"] |
slots | each with time, startsAt, endsAt, seatingType, bookingToken (the source's own identifier for that table and time) |
waitlistAvailable / notifyAvailable | no-table fallbacks the source itself offers |
phone / website / menuUrl | full profile only |
images / imageUrl | photo URLs |
minPartySize / maxPartySize | full profile only |
isResyCreditEligible / isGlobalDiningAccess / isTockInventory / resySelect | platform eligibility and membership flags |
distanceMiles / detailLoaded | distance from the search centre / whether the full profile was read |
availabilityCalendar / nextAvailableDate | which of the next 14 days are bookable (full profile only) |
changeType / changedFields | incremental mode only: "UPDATED" / ["slots", "slotCount"] |
Profile-only records also carry whyWeLikeIt, about, seoDescription, currencyCode, currencySymbol, googlePlaceId and socialLinks.
How to Use
- Pick a mode:
search(walk one or more cities) orurl(paste restaurant links). - For search, list the cities, and narrow with a keyword, radius or sort order if you want. For URL mode, paste the restaurant links.
- Set the date, party size and, optionally, an earliest time. Turn on Read the full profile if you want street address, menu link, awards and the two week calendar.
- Set Max items to control run size and cost, click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.
City search, tonight, 3 guests, New York:
{"mode": "search","cities": ["new-york-ny"],"partySize": 3,"maxItems": 50}
URL mode, a named restaurant on a pinned date:
{"mode": "url","venueUrls": ["https://resy.com/cities/new-york-ny/venues/example-restaurant"],"date": "2026-12-31","partySize": 4}
A cuisine search with full profiles:
{"mode": "search","cities": ["Chicago"],"query": "Italian","radiusMiles": 5,"fetchDetails": true,"maxItems": 25}
Incremental monitoring, nightly:
{"mode": "search","cities": ["new-york-ny"],"partySize": 2,"incrementalMode": true,"emitExpired": true,"maxItems": 100}
Cities accept a city slug (new-york-ny), a city name (Chicago), a city page link, or a latitude,longitude pair. Around 2,100 cities are covered, mostly United States plus Mexico, Spain, Italy and Canada.
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/resy-restaurant-availability-scraper").call(run_input={"mode": "search","cities": ["new-york-ny"],"partySize": 2,"maxItems": 50})for venue in client.dataset(run["defaultDatasetId"]).iterate_items():print(venue["name"], venue["slotCount"], venue["firstSlotTime"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/resy-restaurant-availability-scraper').call({mode: 'search',cities: ['new-york-ny'],partySize: 2,maxItems: 50,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Cities and the Max items budget
Several cities in one run share Max items evenly, and the last city inherits whatever is left over, so a small city that runs out of restaurants before its share never strands the rest of the budget. City search walks pages of 20 restaurants at a time, most relevant first by your chosen sort order, and stops once Max items is reached, so a capped run returns a city's top matches rather than a random slice.
Resume and recurring updates
- Resume (
resumeFromRunId) continues one interrupted run: paste its run or dataset ID and the actor skips every restaurant already collected there, so you don't pay twice. - Incremental mode (
incrementalMode) is for monitoring the same search over time. Each record is classifiedNEW,UPDATED(withchangedFields, typicallyslotsandslotCountwhen a table opens up or is taken),UNCHANGED(suppressed and not billed unlessemitUnchangedis on),REAPPEARED, orEXPIRED(only after a run that scanned the whole search uncut, not resumed and not capped, so a restaurant that merely fell outside a partial budget is never falsely tombstoned; turn onemitExpiredto receive these). The baseline is keyed by city, filters, date wording and party size; usestateKeyto name or deliberately share a monitoring campaign.
Two things worth knowing about how these interact in practice:
EXPIREDrows are not counted against Max items. That budget only governs how many restaurants the run itself reads; theEXPIREDbatch size instead reflects however many previously tracked restaurants are missing from a complete scan. If your monitored scope can shrink sharply between runs (a narrower time filter, a smaller radius, a genuinely quieter night), a single eligible run can emit far moreEXPIREDrows thanmaxItemswould suggest. This only fires on a complete, unresumed, uncapped scan (a run that fills Max items counts as capped and skipsEXPIRED); turn offemitExpired, or keep monitored scopes narrow and stable, if a sudden burst ofEXPIREDrows would be a problem for your billing.- Resume still reads restaurants it is about to discard. In search mode with Read the full profile on, and in URL mode always, an already-collected restaurant's profile (plus its calendar, or in URL mode its availability) is still read before the actor recognises it as a duplicate and drops it. The row is correctly not re-added to the dataset and neither the record nor the profile surcharge is charged again, but the reads themselves still happen. If that matters to you, run large full-profile pulls in smaller batches rather than one big capped-and-resumed run.
- Resume and incremental mode together can repeat rows on the next scheduled run. Restaurants that a resumed run skips as already collected are not written into the incremental baseline. If the interrupted run never finished (so it never saved its own baseline), the next regular incremental run reports those restaurants again, as
NEWorUPDATED, and they are billed again. To avoid this, let an interrupted monitoring run be replaced by the next scheduled run instead of resuming it.
Send results into your apps (MCP connectors)
The MCP connector export is optional: pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each restaurant, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify, Settings, Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where restaurant pages should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. A connector failure never fails the run. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search reads whole cities; url reads only the restaurants you name. |
cities | array | ["new-york-ny"] | Search mode: one or more cities (slug, name, link or lat,long). Several cities share the Max items budget equally. |
query | string | (empty) | Search mode: narrow a city to a restaurant name, cuisine or dish. |
radiusMiles | integer | the city's own | Search mode: how far from the city centre to look (1 to 100). |
orderBy | string | availability | Search mode: availability or distance. |
resyCreditEligibleOnly | boolean | false | Search mode: only restaurants eligible for the platform's dining credit. |
venueUrls | array | sample | URL mode: restaurant links or bare slugs. |
urls | array | (none) | Alias for venueUrls, accepted under the name other actors use for URL mode. |
date | string | today | Day to check, as YYYY-MM-DD, today or tomorrow. A past date is read as today. |
partySize | integer | 2 | Guests at the table (1 to 20). No table for this size comes back as no times, which is itself the answer. |
timeFilter | string | (empty) | Earliest time, HH:MM in the restaurant's local time. |
maxItems | integer | 20 | Stop after this many restaurants (0 = no limit). |
fetchDetails | boolean | false | Also read each restaurant's full profile and its two week availability calendar. URL mode always reads the profile; there this adds the calendar. |
resumeFromRunId | string | (none) | Continue one interrupted run without re-collecting what it already has. |
incrementalMode | boolean | false | Return only new and changed restaurants on recurring runs. |
stateKey | string | (none, auto) | Name or share an incremental-mode monitoring campaign. |
emitUnchanged | boolean | false | Also return (and bill) unchanged restaurants. |
emitExpired | boolean | false | Also return restaurants absent from a complete scan since the last run. |
mcpConnectors | array | (none) | Optional: send a summary of each restaurant to apps you authorized under Integrations. |
notionParentPageUrl | string | (none) | Notion connector only: page under which restaurant pages are created. |
maxNotifyListings | integer | 50 | Cap on restaurants written to each connector per run. |
proxyConfiguration | object | Apify Proxy | Connection settings. |
Output Example
Sample shape: values are illustrative placeholders, not from a live record.
{"kind": "venue","recordId": "87654","venueId": 87654,"name": "Sample Bistro Alpha","url": "https://resy.com/cities/new-york-ny/venues/example-restaurant","urlSlug": "example-restaurant","citySlug": "new-york-ny","cityName": "New York","neighborhood": "Sample Neighborhood","locality": "New York","region": "NY","country": "US","streetAddress": "123 Sample Street","postalCode": "10001","crossStreet": "Sample Avenue","latitude": 40.7128,"longitude": -74.006,"cuisine": ["Italian"],"priceRange": 2,"priceRangeSymbol": "$$","rating": 4.3,"ratingCount": 128,"collections": ["Editor's Picks"],"awards": ["Sample Award 2025"],"phone": "+1 212 555 0100","website": "https://example-restaurant.example.com","menuUrl": "https://example-restaurant.example.com/menu","images": ["https://img.resy.com/sample/1.jpg"],"imageUrl": "https://img.resy.com/sample/1.jpg","minPartySize": 1,"maxPartySize": 8,"isResyCreditEligible": true,"isGlobalDiningAccess": false,"isTockInventory": false,"distanceMiles": 0.4,"detailLoaded": true,"availabilityDate": "2026-12-31","partySize": 4,"isAvailable": true,"slotCount": 2,"firstSlotTime": "18:00","lastSlotTime": "20:30","seatingTypes": ["Bar", "Dining Room"],"slots": [{ "time": "18:00", "startsAt": "2026-12-31T18:00:00", "endsAt": "2026-12-31T19:30:00", "seatingType": "Dining Room", "bookingToken": "rgs://resy/sample/token1" },{ "time": "20:30", "startsAt": "2026-12-31T20:30:00", "endsAt": "2026-12-31T22:00:00", "seatingType": "Bar", "bookingToken": "rgs://resy/sample/token2" }],"waitlistAvailable": false,"notifyAvailable": true,"availabilityCalendar": [{ "date": "2026-12-31", "reservation": "available", "event": "none", "walkIn": "none" }],"nextAvailableDate": "2026-12-31"}
Plan Requirement
The default proxy setting works out of the box for typical runs. For high-volume city search across many cities, or frequent incremental monitoring, the residential proxy group gives more headroom; pick it under Connection.
FAQ
How much does it cost?
You pay per restaurant record returned. The full profile read is billed separately per restaurant: in search mode only when you turn it on, and in URL mode on every restaurant whose profile was read. The Pricing tab shows the current rates. Use Max items to cap the cost of any run.
Is it legal to scrape Resy?
This actor collects only publicly available restaurant and availability data. You are responsible for how you use it: follow Resy's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution.
Can I get only new or changed availability on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated and reappeared restaurants, and unchanged ones are not billed unless you turn that on too.
Why do two runs of the same search return different times?
Availability is live: which restaurants have tables at which times changes by the hour. A different slot list an hour later is the correct answer, not a bug. That is exactly what incremental mode is for.
Why did my run fail instead of returning an empty dataset?
If every request is refused, the run stops with a clear message so "no tables tonight" is never confused with "nothing could be read". Run it again in a few minutes. If only some restaurants or pages could be read, you still get what was found.
Why did an incremental run return far more rows than Max items?
EXPIRED rows (restaurants missing from a complete scan since the last run) are not counted against Max items, which only governs the new and updated side of a run. A monitoring scope that shrinks sharply between runs can emit a burst of EXPIRED rows. This only happens on a complete, uncapped, unresumed scan; turn off Emit expired if you don't want these rows.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.
๐ More scrapers you might like
Pair this actor with these related scrapers from the same team:
| ๐ GrabFood Restaurant Scraper Scrape GrabFood restaurants across Southeast Asia, including SG, MY, TH, VN, PH, ID, KH... | ๐งฉ OpenTable Reviews Scraper Scrape full OpenTable.com restaurant reviews by keyword, area, or restaurant profile... |
| ๐ Google Maps Scraper Extract business data from Google Maps at scale. Get names, addresses, phone numbers... | ๐ Zomato Restaurants & Reviews Scraper Scrape restaurants and reviews from zomato.com. Get names, cuisines, ratings and votes... |
| ๐ท Wolt.com From $0.8/1K. Scrape Wolt restaurants and full menus at the city scale. Extract 60+... | ๐งฉ Fever Scraper Scrape Fever events by city, category, keyword or URL. Extract from-prices, venues, dates... |
๐ Browse all abotapi scrapers
๐ฌ Support & custom scrapers
- ๐ Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- ๐ ๏ธ Need another site, extra fields or a private build? Email contact@abotapi.com or message Telegram @abotapi.
- โญ Enjoying it? A quick review on the actor page helps other users find it.