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
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
An unofficial scraper for Resy (resy.com), the restaurant reservation platform. For every restaurant it returns the bookable times for your date and party size, plus rating, cuisine, price band, phone, website, photos and location.
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.
Two modes:
- City search (default): name one or more cities and the actor walks each city's restaurant list and returns every match with its times for the day. A whole city costs one read per page of results, not one read per restaurant.
- URL mode: paste restaurant links and the actor reads exactly those: the full profile (street address, website, menu link, awards, two week availability calendar) plus the day's bookable times.
Availability is live and time dependent: which restaurants have tables at which times changes by the hour. Two runs of the same search legitimately return different slot lists. That is the signal, and the incremental mode below is how you read it.
This actor is not affiliated with Resy or American Express. Data is scraped from the public website on your behalf; respect the source and your plan's fair use.
Quick start
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}
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.
Input parameters
| Field | Mode | Default | What it does |
|---|---|---|---|
mode | - | search | search reads whole cities; url reads only the restaurants you name. |
cities | search | ["new-york-ny"] | One or more cities (slug, name, link or lat,long). Several cities share the Max items budget equally; the last city inherits the remainder. |
query | search | empty | Narrow a city to a restaurant name, cuisine or dish (Italian, omakase). |
radiusMiles | search | the city's own | How far from the city centre to look (1 to 100). |
orderBy | search | availability | availability or distance. |
resyCreditEligibleOnly | search | false | Only restaurants eligible for the platform's dining credit. |
venueUrls (or urls) | url | - | Restaurant links (https://resy.com/cities/<city>/venues/<restaurant>) or bare slugs. |
date | both | today | Day to check, as YYYY-MM-DD, today or tomorrow. A past date is read as today: the source keeps no bookable inventory behind it. |
partySize | both | 2 | Guests at the table (1 to 20). A restaurant with no table this size comes back with no times, which is itself the answer. |
timeFilter | both | empty | Earliest time, HH:MM in the restaurant's local time (19:30). |
maxItems | - | 20 | Stop after this many restaurants. 0 means no limit. |
fetchDetails | search | false | Also read each restaurant's full profile and its two week availability calendar. One extra read per restaurant; see pricing. |
resumeFromRunId | - | - | Paste a previous run or dataset id to continue a large pull without re-returning restaurants already collected there. |
incrementalMode | - | false | For scheduled monitoring: later runs return only what changed (see change types). |
stateKey | - | auto | Name a monitoring campaign so its baseline survives input tweaks, or deliberately share it between runs. |
emitUnchanged | - | false | Also return unchanged restaurants, marked UNCHANGED (extra rows, billed). |
emitExpired | - | false | Also return restaurants that vanished since the last complete scan, marked EXPIRED. |
mcpConnectors | - | empty | MCP connector export: pipe results into your apps (Notion gets a page per restaurant). Authorize a connector under Apify, Settings, API & Integrations, then list its id here. Never changes the dataset. |
notionParentPageUrl | - | - | Notion parent page under which restaurant pages are created. |
maxNotifyListings | - | 50 | Cap on restaurants written to each connector per run. |
proxyConfiguration | - | Apify Proxy on | Works on every proxy plan, including the free tier. |
Output
One record per restaurant. Headline fields:
- Identity:
recordId,venueId,name,url,urlSlug,citySlug,cityName,neighborhood,locality,region,country,streetAddress,postalCode,crossStreet,latitude,longitude. - Classification:
cuisine,priceRange(1 to 4),priceRangeSymbol($to$$$$),rating,ratingCount,collections,awards,venueGroupName,googlePlaceId. - Availability for your
dateandpartySize:isAvailable,slotCount,firstSlotTime,lastSlotTime,seatingTypes, andslots, each slot carryingtime,startsAt,endsAt,seatingType,bookingToken(the source's own identifier for that exact table and time), plus flags for global dining access and add-ons.waitlistAvailableandnotifyAvailablereport the no-table fallbacks. - Profile (URL mode, or with
fetchDetails):phone,website,menuUrl,images,whyWeLikeIt,about,seoDescription,minPartySize,maxPartySize, currency fields,isResyCreditEligible,isGlobalDiningAccess,resySelect,isTockInventory,socialLinks,distanceMiles,detailLoaded, andavailabilityCalendar(which of the next 14 days are bookable) withnextAvailableDate.
A fully booked restaurant is a real answer: it ships with isAvailable
false and zero slots rather than being dropped.
Sample record (illustrative, fictional restaurant):
{"kind": "venue","recordId": "123456","venueId": 123456,"name": "Sample Bistro Alpha","url": "https://resy.com/cities/new-york-ny/venues/example-restaurant","citySlug": "new-york-ny","cuisine": ["Italian"],"priceRange": 2,"priceRangeSymbol": "$$","rating": 4.3,"ratingCount": 128,"availabilityDate": "2026-09-06","partySize": 2,"isAvailable": true,"slotCount": 2,"firstSlotTime": "18:00","lastSlotTime": "20:30","slots": [{"time": "18:00", "seatingType": "Dining Room", "bookingToken": "rgs://resy/123456/..."},{"time": "20:30", "seatingType": "Bar", "bookingToken": "rgs://resy/123456/..."}],"detailLoaded": false}
Incremental monitoring (change types)
With incrementalMode on, every record carries a changeType:
NEW: first time this restaurant was seen in this campaign.UPDATED: seen before and something changed.changedFieldsnames what, typicallyslotsandslotCount: a table opened up or was taken.UNCHANGED: seen before and nothing changed. Suppressed by default; turn onemitUnchangedto receive (and pay for) them.REAPPEARED: seen before, vanished from a previous scan, present again.EXPIRED: present in the baseline but absent from a scan. Produced only when the run completed the whole search uncut (not resumed, not capped, every page read), so a restaurant that merely fell outside a partial budget is never falsely tombstoned. Turn onemitExpiredto receive them.
The baseline is keyed by the city, filters, date wording and party size that
produced it: a nightly schedule that leaves date empty keeps one baseline
across nights, while a run pinned to 2026-12-24 is its own campaign. Use
stateKey to name or deliberately share a campaign.
Resume
A big pull that died halfway does not need to start over. Paste the failed
run's id (or its dataset id) into resumeFromRunId and the new run skips
every restaurant already collected there.
Send results into your apps (MCP connectors)
The MCP connector export is optional: set mcpConnectors to pipe each run's
results into an app you already use, via the Apify MCP gateway: Notion
receives one page per restaurant under
notionParentPageUrl; other connectors receive a best-effort create or a
short digest, capped by maxNotifyListings. What gets written is a
condensed, human-readable summary per restaurant (title plus key fields
flattened to plain text), not the full JSON record; the complete record
always stays in the Apify dataset. The dataset is never modified by this,
and a connector failure never fails the run.
Pricing (pay per event)
- Actor start: charged once per run, scaled by memory.
- Restaurant record: charged for each restaurant returned in the dataset, with its bookable times. This is the primary event.
- Restaurant profile: charged once per restaurant whose full profile page
was read (URL mode always; city search only with
fetchDetails). A profile read that fails still ships the base record, uncharged, and a profile route that fails systemically degrades the run to search records instead of grinding.
Notes
- Works on every Apify proxy plan including the free tier; the source is read through shared connection pools with automatic exit rotation.
- Times are the restaurant's local time, exactly as the source lists them.
- The dataset view is
overview; every record is also available through the standard dataset API.