Airbnb Occupancy Scraper
Pricing
$19.99/month + usage
Airbnb Occupancy 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
28 minutes ago
Last modified
Categories
Share
๐ Airbnb Availability & Rate Scraper
Scrape the forward-looking availability calendar of Airbnb listings and the real per-day fields Airbnb's own calendar returns โ check-in / check-out eligibility, the bookable flag, minimum / maximum nights, and the nightly price when it is present. From those real values it derives an honest unavailableRate and, only from real calendar prices, ADR / estimated revenue / RevPAR.
This actor is deliberately honest about what the data is and is not. Read the two notes below before using it.
โ ๏ธ Honesty notes (read these)
- This is availability, not occupancy. Airbnb's calendar tells you whether a night is available. An unavailable night can be either genuinely booked or blocked by the host โ the public calendar cannot distinguish the two. We therefore report
unavailableRate= unavailable days รท counted days, clearly labeled "includes host-blocked days; not a booking/occupancy rate." We never call unavailable nights "booked" and never emit an "occupancy rate." - Money fields come only from real prices.
adr,estimatedRevenueandrevparare computed exclusively from nightly prices that appear in the calendar payload. When a listing exposes no calendar prices, these fields arenullโ never a regional average, a search-page price, or an interpolated guess.estimatedRevenue/revparadditionally assume every unavailable night is a paid booking, which is an upper bound (it includes host-blocked nights); they are labeled as such. - Forward-only.
PdpAvailabilityCalendarreturns future availability. Past dates are clamped to today. There is no historical calendar available from this endpoint.
How it works
- curl_cffi Chrome TLS impersonation. Airbnb sits behind Akamai / PerimeterX. Plain
requests/aiohttpare blocked at the TLS (JA3) layer before reaching the app. This actor usescurl_cffiwithimpersonate="chrome"so requests replay a real Chrome handshake. - Soft-block guard + proxy escalation. An airlock / challenge / empty shell is detected and reported as a block (the run keys on the presence of the expected bootstrap container, not on loose tokens), and the actor retries on a fresh residential proxy IP.
- Dynamic persisted-query discovery. The GraphQL persisted-query hash is found by scanning the room page and its JS bundles for the hash next to
PdpAvailabilityCalendarโ no hardcoded bundle name that breaks on every Airbnb deploy. - Harvest + derive. Every already-in-payload day field is emitted; derived metrics are computed with the honesty rules above.
Input
| Field | Type | Notes |
|---|---|---|
listings | array (required) | Room URLs or bare IDs, one per line. |
startDate | date | Absolute (2026-08-01) or relative (7 days, 1 month). Empty = today. Past โ clamped to today. |
endDate | date | Absolute or relative. Empty = start + 30 days. Up to ~12 months ahead. |
billingMode | enum | per_listing (default, 1 charge/listing) or per_day. |
includeDays | boolean | Emit per-day child rows (default true). |
includeListingDetails | boolean | Best-effort title/type/capacity/beds/baths/coords (default false). |
includeHostProfile | boolean | Best-effort superhost/name/response rate (default false). |
proxyConfiguration | proxy | Default residential (recommended; datacenter is usually blocked). |
{"listings": ["https://www.airbnb.com/rooms/35329051"],"startDate": "2026-08-01","endDate": "2026-10-31","billingMode": "per_listing","includeDays": true,"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }}
Output
Two row types share the dataset and are distinguished by type / isChild.
Parent โ type: "listing" (one per target):
{"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-03T12:00:00Z"}
Child โ type: "day" (one per calendar day, mirrored to a per-run days-<runId> dataset):
{"type": "day", "isChild": true, "parentId": "35329051", "roomId": "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-03T12:00:00Z"}
price is a real number or null (never 0). unavailableRate, adr, estimatedRevenue, revpar are null when the underlying data is absent.
Billing
Pay-per-event. per_listing (default) charges one listing_result per listing. per_day charges one day_result per calendar-day row (~30 for a month, ~365 for a year). Day rows are always produced; billingMode only controls what is billed. See .actor/pay_per_event.json.
Keywords
airbnb scraper, airbnb availability, airbnb calendar, airbnb rates, nightly price, adr, revpar, short-term rental data, str analytics, vacation rental availability, airbnb api, booking calendar, occupancy alternative, curl_cffi, akamai bypass.
Compliance
Only publicly visible calendar data is accessed. Ensure your use complies with Airbnb's Terms of Service and applicable law.
