How to scrape Airbnb listings, availability, and reviews at scale
Key Takeaways
Does Airbnb have a public API for this kind of data? No — Airbnb shut down its public search API years ago. Everything here reads the same public listing and search pages a guest's browser loads, which is why residential proxies are required: Airbnb blocks datacenter IPs aggressively.
Can you get an exact price for specific travel dates, not just a generic nightly rate?
Yes — setting checkIn/checkOut on a listing search returns the exact quote for that stay, including the full fee breakdown (cleaning fee, service fee, taxes), not just a headline nightly number.
Is 12 months the real limit for availability data?
Yes — Airbnb itself only exposes 12 months of forward calendar per listing, so that's the ceiling for both the search-level calendarMonths option and the dedicated calendar scraper, regardless of how far out you ask.
Three Layers of Airbnb Data
"Scraping Airbnb" usually means one of three genuinely different jobs: finding listings that match a market, checking whether a specific property is bookable, and reading what past guests said about it. Treating these as one scrape produces a slow, over-fetched run when you only needed one layer.
| Layer | What it answers | Actor |
|---|---|---|
| Search & pricing | Which listings exist in a market, at what price | Airbnb Scraper & API |
| Availability | Is this specific listing bookable on these dates | Airbnb Availability Calendar Scraper |
| Reviews | What do past guests actually say | Airbnb Reviews Scraper |
Finding and Pricing Listings
The Airbnb Scraper & API takes a location query — "Lisbon, Portugal", "Tokyo, Japan" — or a direct Airbnb URL, and returns every matching listing with live pricing:
{
"id": "788405891732745420",
"title": "Recanto da Lima",
"nightlyPrice": 263.52,
"totalPrice": 1510,
"currency": "USD",
"ratingScore": 4.98,
"reviewCount": 129,
"roomType": "Private room in home",
"isSuperHost": true,
"coordinates": { "latitude": 38.546, "longitude": -8.84326 }
}
Set checkIn/checkOut and the price fields reflect that exact stay, fee breakdown included. Leave dates unset for a general market scan. skipDetailPages: true skips the per-listing detail fetch (amenities, host profile, house rules) for a faster, cheaper search-only run — useful when you only need price and location, not the full listing page.
Airbnb caps a single search at roughly 270 results; the actor handles this automatically by splitting a busy location into price-range sub-searches, so a dense market like central Paris still returns its full inventory rather than stopping at the cap.
Checking Availability Day by Day
Search results tell you what's listed, not what's actually bookable next month. The Airbnb Availability Calendar Scraper takes a single listing URL and returns a day-by-day calendar:
{
"listingId": "860663943931949474",
"date": "2025-12-07",
"available": true,
"bookable": true,
"minNights": 1,
"maxNights": 1125,
"nightlyRate": 48.34,
"totalPrice": 65.03,
"currency": "GBP",
"canInstantBook": false
}
startDate/endDate accept rolling offsets like +7 and +90 instead of fixed calendar dates — set those once and a scheduled run always looks the correct number of days ahead, rather than needing its input updated every week. Enable enrichWithPricing for the nightly rate and taxes on every bookable date, priced in any ISO currency you choose, not just the listing's native one.
Reading the Review History
The Airbnb Reviews Scraper pulls every review from a listing's page — text, star rating, reviewer and host profiles, and host responses:
{
"reviewId": "9384756",
"text": "Beautiful apartment, exactly as described. The host was incredibly responsive.",
"rating": 5,
"localizedDate": "3 weeks ago",
"hostResponse": "Thank you so much for staying with us!",
"reviewerName": "Sarah",
"hostIsSuperhost": true
}
filterByTopic narrows results to reviews mentioning a specific theme — CLEANLINESS, NOISE, WIFI, and 15 others — matched against the review text itself, useful when you're checking a specific complaint pattern rather than reading every review. Turn on enableAIAnalysis to add a sentiment label and score plus an English translation for non-English reviews, which matters if you're benchmarking listings across markets where guests review in the local language.
Putting the Three Together
async function evaluateListing(listingUrl) {
const [search, calendar, reviews] = await Promise.all([
runActor("airbnb-scraper", { startUrls: [{ url: listingUrl }] }),
runActor("airbnb-availability-calendar-scraper", {
listingUrl,
startDate: "+0",
endDate: "+90",
enrichWithPricing: true,
}),
runActor("airbnb-reviews-scraper", { startUrls: [{ url: listingUrl }], enableAIAnalysis: true }),
]);
const bookableDays = calendar.filter((d) => d.bookable).length;
const avgSentiment = average(reviews.map((r) => r.sentimentScore));
return { listing: search[0], occupancyProxy: 1 - bookableDays / 90, avgSentiment };
}
occupancyProxy here is a rough stand-in for real booking data Airbnb doesn't expose directly: the fraction of the next 90 days already blocked off tells you roughly how in-demand a listing is, without needing the host's actual reservation system.
FAQ
Do you need to log in or have an Airbnb account to run any of this? No — all three actors read only public listing pages, the same data any visitor sees without signing in.
How often should availability be re-checked? Daily for a listing you're actively monitoring for booking gaps; weekly is plenty for general market or investment research, since occupancy patterns shift slowly outside of last-minute cancellations.
For a look at how availability data fits into a broader short-term-rental investment pipeline, browse the travel actor category on ParseBird.