Resy Scraper - Restaurants & Live Table Availability avatar

Resy Scraper - Restaurants & Live Table Availability

Pricing

from $1.20 / 1,000 restaurant records

Go to Apify Store
Resy Scraper - Restaurants & Live Table Availability

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

Abot API

Maintained by Community

Actor 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

FieldModeDefaultWhat it does
mode-searchsearch reads whole cities; url reads only the restaurants you name.
citiessearch["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.
querysearchemptyNarrow a city to a restaurant name, cuisine or dish (Italian, omakase).
radiusMilessearchthe city's ownHow far from the city centre to look (1 to 100).
orderBysearchavailabilityavailability or distance.
resyCreditEligibleOnlysearchfalseOnly restaurants eligible for the platform's dining credit.
venueUrls (or urls)url-Restaurant links (https://resy.com/cities/<city>/venues/<restaurant>) or bare slugs.
datebothtodayDay to check, as YYYY-MM-DD, today or tomorrow. A past date is read as today: the source keeps no bookable inventory behind it.
partySizeboth2Guests at the table (1 to 20). A restaurant with no table this size comes back with no times, which is itself the answer.
timeFilterbothemptyEarliest time, HH:MM in the restaurant's local time (19:30).
maxItems-20Stop after this many restaurants. 0 means no limit.
fetchDetailssearchfalseAlso 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-falseFor scheduled monitoring: later runs return only what changed (see change types).
stateKey-autoName a monitoring campaign so its baseline survives input tweaks, or deliberately share it between runs.
emitUnchanged-falseAlso return unchanged restaurants, marked UNCHANGED (extra rows, billed).
emitExpired-falseAlso return restaurants that vanished since the last complete scan, marked EXPIRED.
mcpConnectors-emptyMCP 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-50Cap on restaurants written to each connector per run.
proxyConfiguration-Apify Proxy onWorks 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 date and partySize: isAvailable, slotCount, firstSlotTime, lastSlotTime, seatingTypes, and slots, each slot carrying time, startsAt, endsAt, seatingType, bookingToken (the source's own identifier for that exact table and time), plus flags for global dining access and add-ons. waitlistAvailable and notifyAvailable report 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, and availabilityCalendar (which of the next 14 days are bookable) with nextAvailableDate.

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. changedFields names what, typically slots and slotCount: a table opened up or was taken.
  • UNCHANGED: seen before and nothing changed. Suppressed by default; turn on emitUnchanged to 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 on emitExpired to 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.