๐ Airbnb Availability & Rate Scraper
Pricing
$19.99/month + usage
๐ Airbnb Availability & Rate Scraper
Monitor Airbnb occupancy and availability across listings or cities. Retrieve booked nights, seasonal trends, and pricing signals. Designed for researchers, investors, and revenue teams needing trusted data.
Pricing
$19.99/month + usage
Rating
0.0
(0)
Developer
SimpleAPI
Maintained by CommunityActor stats
0
Bookmarked
12
Total users
0
Monthly active users
6 hours ago
Last modified
Categories
Share
Airbnb Availability Scraper โ Rates, Calendar and Booking Status
Pull the forward-looking availability calendar for any Airbnb listing straight from Airbnb's own PdpAvailabilityCalendar endpoint: per-day availableForCheckin, availableForCheckout, bookable, minNights, maxNights, and the nightly price when Airbnb actually exposes one. From those real values the actor derives an honestly-labeled unavailableRate, plus adr, estimatedRevenue, and revpar โ computed only from real calendar prices, never a guess. Revenue managers, short-term-rental investors, and market analysts use it to track pricing and booking-window patterns across a portfolio of known listings. No Airbnb account or login is required.
What is Airbnb Availability Scraper?
Airbnb Availability Scraper is an Apify Actor that takes a list of Airbnb listing URLs or numeric room IDs and returns their availability calendar and, where present, nightly pricing โ as structured JSON rows in an Apify dataset. It does not search or discover new listings; you supply the listings you already know about, and it fetches each one's calendar directly from Airbnb's GraphQL API, bypassing the need for a browser.
- Discovery is by listing, not by search. Input is a plain list of Airbnb room URLs (
https://www.airbnb.com/rooms/35329051) or bare numeric IDs (35329051) โ both are accepted in the same list. - Core calendar fields returned per day:
availableForCheckin,availableForCheckout,bookable,minNights,maxNights, andprice(a real number ornull, never a placeholder value). - Secondary derived data: an honestly-labeled
unavailableRate(host-blocked and booked nights combined โ see the honesty note below), plusadr,estimatedRevenue, andrevpar, allnullwhen no real calendar price exists for the window. - Temporal fields:
date,dayOfWeek,isWeekendon every day row, andwindowStart/windowEnd/totalDayson the listing summary row. - Real filters exposed: a
startDate/endDatecalendar window, abillingModethat controls cost granularity, and three on/off toggles (includeDays,includeListingDetails,includeHostProfile) that shape which rows and fields come back. - Export formats: every Apify dataset โ including this actor's โ can be downloaded from the Apify Console or API as JSON, CSV, Excel (XLSX), XML, RSS, or an HTML table.
What data can I extract with Airbnb Availability Scraper?
The actor writes two row types into the same dataset, distinguished by the type field ("listing" or "day") and the isChild boolean. Every field below is read directly from src/main.py and src/helpers.py โ several exist in the underlying data but are not in the dataset's default view (36 columns), so open "API โ Dataset items" or download the raw JSON to see all of them.
| Field | Row type | In default view? | Example value | Use case |
|---|---|---|---|---|
type | both | yes | "listing" / "day" | Split parent summaries from day-level detail |
isChild | both | yes | false / true | Programmatic filter for row type |
roomId | both | yes | "35329051" | Join listing and day rows |
listingUrl | both | yes | "https://www.airbnb.com/rooms/35329051" | Canonical link back to the listing |
scrapedAt | both | yes | "2026-07-26T14:03:00Z" | Freshness check on every row |
currency | both | yes | "USD" (listing) / "USD" or null (day) | Pair with any price field |
parentId | day | no | "35329051" | Same as roomId on day rows; kept for explicit parent-child joins |
date | day | yes | "2026-08-01" | Calendar day key |
dayOfWeek | day | yes | "Saturday" | Weekday pricing/demand analysis |
isWeekend | day | yes | true | Weekend-vs-weekday segmentation |
available | day | yes | false | Raw Airbnb availability flag (see honesty note) |
availableForCheckin | day | yes | false | Whether a stay can start this day |
availableForCheckout | day | yes | true | Whether a stay can end this day |
bookable | day | yes | false | Airbnb's own bookability flag for the day |
minNights | day | yes | 2 | Minimum stay length enforced that day |
maxNights | day | yes | 365 | Maximum stay length enforced that day |
price | day | yes | 128.5 or null | Real nightly price when Airbnb returns one |
windowStart / windowEnd | listing | yes | "2026-08-01" / "2026-10-31" | The resolved date range actually scraped |
totalDays | listing | yes | 92 | Denominator for every rate below |
availableDays / unavailableDays | listing | yes | 40 / 52 | Raw day counts behind unavailableRate |
unavailableRate | listing | yes | 0.5652 | Host-blocked + booked days รท counted days |
priceCoverage | listing | yes | "40/92" | How many of the window's days actually carried a real price |
pricedDays | listing | no | 40 | Numerator of priceCoverage, kept as its own field |
adr | listing | yes | 128.5 | Average of real nightly prices only |
minPrice / maxPrice | listing | yes | 110.0 / 210.0 | Price spread across priced days |
estimatedRevenue | listing | yes | 6682.0 | ADR ร unavailable days โ an upper bound, see honesty note |
revpar | listing | yes | 72.63 | ADR ร unavailable-day rate โ also an upper bound |
title | listing (opt-in) | yes | "Modern Loft Near Downtown" | Listing display name |
starRating | listing (opt-in) | yes | 4.87 | Parsed from the page's star display, null if absent |
roomType / propertyType | listing (opt-in) | yes | "Entire home" / "Apartment" | Property classification |
personCapacity | listing (opt-in) | yes | 4 | Guest capacity |
bedrooms | listing (opt-in) | no | 1 | Parsed from capacity text or embedded state |
beds / bathrooms | listing (opt-in) | yes | 2 / 1 | Room counts |
latitude / longitude | listing (opt-in) | no | 40.7128 / -74.006 | Approximate, jittered pre-booking coordinates |
coordinatesApproximate | listing (opt-in) | no | true | Always true โ flags that the coordinates above are Airbnb's jittered pre-booking values, not exact |
hostIsSuperhost | listing (opt-in) | yes | true | Superhost badge status |
hostName | listing (opt-in) | no | "Maria" | Best-effort host display name |
hostResponseRate | listing (opt-in) | no | "100%" | As shown on the listing page |
hostSince | listing (opt-in) | no | null | Present in the schema, currently always returned null โ Airbnb's public room page does not expose it in the embedded state this actor parses |
Revenue and demand metrics
adr, estimatedRevenue, revpar, and unavailableRate are the fields most buyers of this data actually want, and they are computed only from real calendar prices โ never a regional average or a search-page estimate. adr is the mean of every real nightly price found in the window; when a listing exposes no price at all in its calendar, adr is null and so are estimatedRevenue and revpar. estimatedRevenue and revpar additionally assume every unavailable night is a paid booking, which makes them an upper bound โ they intentionally include host-blocked nights, and the field names and this document say so rather than presenting them as realized revenue. A revenue manager pulling a 90-day window across ten listings can rank them by revpar to spot underpriced or over-blocked units without ever seeing a number that wasn't in Airbnb's own calendar payload.
Booking-window and constraint fields
minNights, maxNights, availableForCheckin, and availableForCheckout are the fields readers segment on to answer "can a guest actually book this stretch of dates." A day can be available yet not availableForCheckin if it only works as a mid-stay night under the listing's minimum-stay rule โ these three fields, read together per day, are what tell you whether a specific arrival date is workable, not just whether the night is open.
Why not build this yourself?
Airbnb has no public, self-serve API for third-party developers โ there is no documented signup flow or published rate-limit page to build against, so there is no official API to compare this actor to. What exists instead is Airbnb's internal, undocumented GraphQL calendar endpoint, and reaching it reliably from your own code runs into three separate problems that this actor's source code is built specifically to handle:
- TLS fingerprinting. Airbnb sits behind Akamai/PerimeterX, which blocks plain
requests/aiohttptraffic at the TLS (JA3) handshake layer before a request ever reaches the application. This actor usescurl_cffiwith Chrome impersonation (transport.py) so every request replays a genuine Chrome TLS handshake. - A persisted-query hash that Airbnb rotates without notice. The calendar call requires a
sha256Hashvalue tied to thePdpAvailabilityCalendaroperation. The actor ships a known-good hash and, if Airbnb rotates it, self-heals by scanning the room page's JS bundles and then the full asyncRequire chunk manifest (discover_hash/scan_chunks_for_hash) for a fresh one โ a non-trivial reverse-engineering step to reproduce and keep maintained. - Soft-block detection. An airlock, CAPTCHA, or empty response shell has to be told apart from a legitimate "no availability" response, or you silently harvest garbage.
detect_html_blockanddetect_calendar_blockkey on the presence of expected bootstrap markers plus explicit block signatures, and the actor escalates to a fresh residential-proxy session on every soft block, retrying up to4bootstrap attempts and3calendar-fetch attempts per listing before giving up on it.
Build it yourself if you need a bespoke pipeline and have the engineering time to track Airbnb's endpoint changes indefinitely. Use this actor when you want the calendar data now, with the anti-bot and self-healing work already done.
How to use data extracted from Airbnb?
Revenue managers and short-term-rental hosts
Point the actor at your own listing IDs with a 12-month startDate/endDate window and includeDays: true. The day rows give you every future price and bookable flag Airbnb currently shows guests, so you can catch pricing gaps (a stretch of days with price: null where a competitor's calendar is fully priced) or spot nights sitting available with no price set at all โ a common symptom of a forgotten pricing rule.
Property management and STR agencies
Run the same actor across a client portfolio with billingMode: "per_listing" so the run's cost scales with listing count, not window length. Feed roomId, unavailableRate, and revpar from the parent rows into a recurring client report that benchmarks each managed unit against the others on the same schedule โ weekly or monthly, on an Apify Schedule.
Market research and intelligence
Set includeListingDetails: true to pull roomType, propertyType, and personCapacity alongside the pricing metrics, then group adr and revpar by property type or capacity band across a sample of listings in a submarket to see which configurations command the highest realized asking rates โ useful groundwork before an acquisition or a new-listing pricing strategy.
AI agents and automated pipelines
Because the actor is a standard Apify Actor invoked over apify_client, an agent framework can call it as a tool: pass a list of listings and a date window, get back typed JSON with price, bookable, and unavailableRate per listing, and feed that directly into a pricing-recommendation or booking-availability agent without any scraping code of its own.
๐ผ Input sample
| Parameter | Required | Type | Description | Example value |
|---|---|---|---|---|
listings | yes | array | One listing per line โ full room URL or bare numeric ID. | ["https://www.airbnb.com/rooms/35329051", "769824007018240779"] |
startDate | no | string | First calendar day to keep. Absolute (2026-08-01) or relative ("7 days", "1 month"). Past dates are clamped to today since Airbnb's calendar is forward-only. Empty = today. | "2026-08-01" |
endDate | no | string | Last calendar day to keep. Absolute or relative ("3 months", "1 year"). Empty = startDate + 30 days. Airbnb serves up to roughly 12 months ahead. | "2026-11-30" |
billingMode | no | string, enum per_listing | per_day, default "per_listing" | per_listing charges once per listing regardless of window length (recommended). per_day charges once per calendar-day row. Day rows are always produced either way โ this only controls what is billed. | "per_listing" |
includeDays | no | boolean, default true | When on, each calendar day is emitted as its own child row. Turn off to keep only the parent listing summary row. | true |
includeListingDetails | no | boolean, default false | Adds title, room/property type, guest capacity, bedrooms/beds/bathrooms, and approximate coordinates to the parent row โ best-effort, null when not exposed. | false |
includeHostProfile | no | boolean, default false | Adds superhost flag, host name, and response rate to the parent row โ best-effort, null when not exposed. | false |
proxyConfiguration | no | object | Your proxy choice is honored as-is. Defaults to Apify residential proxy, which is strongly recommended โ datacenter IPs are frequently blocked by Airbnb. | { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] } |
{"listings": ["https://www.airbnb.com/rooms/35329051", "769824007018240779"],"startDate": "2026-08-01","endDate": "2026-11-30","billingMode": "per_listing","includeDays": true,"includeListingDetails": true,"includeHostProfile": false,"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }}
Common pitfall: leaving billingMode on the default per_listing is deliberate โ the input schema's own description warns that per_day on a 12-month window bills roughly 365 events per listing instead of one. Switch to per_day only when you specifically need to pay per calendar-day row rather than per listing. Separately, an in-the-past startDate is not an error: it is silently clamped to today with a warning logged to the run console, since PdpAvailabilityCalendar cannot return historical dates.
๐ฝ Output sample
Output is typed, normalized JSON with a consistent schema per row type, downloadable from the Apify Console or API as JSON, CSV, Excel, XML, RSS, or an HTML table. Day rows are also mirrored into a separate per-run dataset named days-<runId> when includeDays is on, in addition to the default dataset.
Parent โ type: "listing" (one row per target, always produced):
{"type": "listing","isChild": false,"roomId": "35329051","listingUrl": "https://www.airbnb.com/rooms/35329051","windowStart": "2026-08-01","windowEnd": "2026-10-31","totalDays": 92,"availableDays": 40,"unavailableDays": 52,"unavailableRate": 0.5652,"adr": 128.5,"priceCoverage": "40/92","pricedDays": 40,"estimatedRevenue": 6682.0,"revpar": 72.63,"minPrice": 110.0,"maxPrice": 210.0,"currency": "USD","scrapedAt": "2026-07-26T14:03:00Z"}
Child โ type: "day" (one row per calendar day, only when includeDays is on):
{"type": "day","isChild": true,"parentId": "35329051","roomId": "35329051","listingUrl": "https://www.airbnb.com/rooms/35329051","date": "2026-08-01","dayOfWeek": "Saturday","isWeekend": true,"available": false,"availableForCheckin": false,"availableForCheckout": true,"bookable": false,"minNights": 2,"maxNights": 365,"price": null,"currency": null,"scrapedAt": "2026-07-26T14:03:00Z"}
price is always a real number or null โ never 0 used as a stand-in for "no price." unavailableRate, adr, estimatedRevenue, and revpar follow the same rule on the parent row.
How do you target specific Airbnb listings and date windows?
This actor doesn't discover new listings by category or search โ you supply the listings you already know, and the real targeting happens in how you shape the calendar pull for each one:
- Listing identification. Both full room URLs and bare numeric IDs work in the same
listingsarray, so you can mix a scraped list of URLs with hand-typed IDs without normalizing them first. - Window precision.
startDateandendDateaccept either an absolute date or a relative offset ("7 days","3 months","1 year"), so a monitoring pipeline can request"today"through"90 days"on every run without hardcoding dates. - Cost granularity, not just row volume.
billingModeis itself a targeting lever:per_listingkeeps run cost proportional to your listing count regardless of how far out you look, whileper_dayties cost to the number of calendar days actually returned โ useful if you only care about a handful of pricing spot-checks. - Row-shape control.
includeDaystoggles whether you get per-day granularity at all;includeListingDetailsandincludeHostProfileadd optional enrichment fields to the parent row without touching the day rows.
A 90-day pricing snapshot, minimal cost:
{ "listings": ["35329051"], "startDate": "", "endDate": "90 days", "billingMode": "per_listing" }
A full 12-month revenue-modeling pull, same per-listing cost as the snapshot above:
{ "listings": ["35329051"], "startDate": "today", "endDate": "1 year", "billingMode": "per_listing", "includeListingDetails": true }
A bulk portfolio scan with only summary rows, no per-day detail:
{ "listings": ["35329051", "769824007018240779"], "includeDays": false, "includeListingDetails": true, "includeHostProfile": true }
โถ๏ธ Want to try other listing and marketplace scrapers?
This is currently the only Airbnb scraper published under the SimpleAPI catalogue. The closest comparable marketplace/listing scrapers in this catalogue:
| Scraper | What it extracts |
|---|---|
| ../Amazon-Best-Seller-%26-Products-Scraper | Amazon best-seller and product listing data, including pricing |
| ../amazon-seller-data-extractor | Amazon marketplace seller and listing data |
How to extract Airbnb data programmatically
Every run is a standard Apify Actor call โ one API call with your Apify token, structured JSON back. There is no separate Airbnb credential to manage; the actor authenticates to Airbnb's own calendar endpoint internally.
Python example
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run_input = {"listings": ["https://www.airbnb.com/rooms/35329051"],"startDate": "today","endDate": "3 months","billingMode": "per_listing",}run = client.actor("simpleapi/airbnb-availability-scraper").call(run_input=run_input)for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item["type"] == "listing":print(item["roomId"], item["adr"], item["unavailableRate"])
Export to spreadsheets or CRM
Download the dataset as CSV directly from the Apify Console (or via the API's ?format=csv dataset export) and import it into Google Sheets or a CRM. Map roomId and listingUrl as the join key, date/price/bookable for a per-night pricing sheet, or roomId/adr/unavailableRate/revpar for a one-row-per-listing revenue summary.
Is it legal to scrape Airbnb?
Scraping publicly accessible Airbnb calendar and pricing data is generally lawful in most jurisdictions โ this data is not behind a login and exists specifically to be shown to prospective guests. This actor returns listing and calendar data, which is business/product data rather than personal data, so it is governed primarily by Airbnb's Terms of Service and database-rights considerations rather than GDPR or CCPA. The exception is the optional includeHostProfile fields (hostName, hostIsSuperhost, hostResponseRate), which can include an identifiable individual's name โ treat that subset with normal data-minimization care if you store or resell it, since it may fall under GDPR/CCPA depending on how you use it. Consult legal counsel for commercial applications involving bulk storage of personal data.
โ FAQ
What happens if a listing is removed or delisted?
The actor doesn't emit a row with nulled-out fields for a delisted or blocked listing โ it omits the listing entirely from the dataset and logs its roomId in the run's "Failed/blocked" summary line instead. Check the run log if a listing you submitted is missing from the output.
Can I get pricing data along with availability?
Yes, by default. Every day row already carries price (a real number or null), and the parent listing row carries adr, minPrice, maxPrice, estimatedRevenue, and revpar, all derived only from real calendar prices found in the window โ no interpolation or regional averaging.
How accurate is the availability and pricing data?
The actor returns exactly what Airbnb's own calendar API returns at the moment of the request โ the same data a browser would show a guest checking dates on that listing. Airbnb calendars change as bookings and host edits happen, so treat the data as a point-in-time snapshot and re-run the actor close to the dates you care about if freshness matters.
How many calendar days can I get per run?
There is no maxItems-style cap in the input schema on the number of listings or days. The practical ceiling is Airbnb's own calendar horizon โ it serves availability roughly 12 months ahead โ and the actor's internal request cap, which fetches at most 12 calendar months per listing per run (months_span, capped at 12 in helpers.py) to match what Airbnb's endpoint accepts in a single request.
What's the most useful targeting control here?
billingMode combined with the date window: setting billingMode to "per_listing" keeps cost tied to how many listings you track rather than how far out you look, which is the difference between a cheap monthly monitoring run and one that scales badly with a 12-month window. See "How do you target specific Airbnb listings and date windows?" above.
Why are there two row types, listing and day, in one dataset?
The parent listing row carries the window-level summary and derived metrics; the child day rows carry the per-day detail. Only the row type matching your billingMode is charged โ under per_listing, day rows are still pushed to the dataset but generate no charge, and vice versa under per_day. Filter on type to work with either level independently.
Does Airbnb Availability Scraper work with Claude, ChatGPT, and AI agent frameworks?
It has no dedicated MCP server integration published for this actor. It is callable as a standard Apify Actor via apify_client or the Apify REST API from any agent framework that can make an HTTP call, so an agent can invoke it as a tool and parse the returned JSON directly.
How does Airbnb Availability Scraper compare to other Airbnb scrapers?
As observed on the Apify Store on 2026-07-26, agenscrape/airbnb-availability-calendar documents a single-listing-per-run input (listingUrl) with an enrichWithPricing toggle that adds tax and instant-book fields, and lists export integrations including Google Sheets, Zapier, Make, Slack, and webhooks; oneary/airbnb-hotel-price-scraper documents search-based discovery by location with filters for check-in/out dates, guests, and price range, returning up to a maxListings cap per its own schema; rigelbytes/airbnb-availability-calendar documents a single-URL input with a raw availability output and is billed as a flat monthly subscription rather than pay-per-event, per its own listing. This actor differs by accepting a batch listings array of URLs or bare IDs in one run, deriving adr/estimatedRevenue/revpar from real calendar prices rather than only surfacing per-day rates, and billing per listing regardless of window length by default.
Can I use Airbnb Availability Scraper without an Airbnb account or API key?
Yes. The actor needs only an Apify account and token to run โ it fetches Airbnb's public room page and calendar endpoint the same way a signed-out browser would, with no Airbnb login, cookie, or developer credential required.
Conclusion
Airbnb Availability Scraper turns a list of listing URLs or IDs into a structured, honestly-labeled availability and pricing calendar โ real per-day fields from Airbnb's own API, derived revenue metrics that are null rather than faked when no price exists, and a billing mode that keeps cost predictable across any window length. It's built for revenue managers, STR agencies, and market researchers who need calendar data at scale without maintaining their own anti-bot pipeline against Airbnb's Akamai/PerimeterX defenses. Start a run from the Apify Console or call it with apify_client using the Python example above.
