How to scrape Airbnb listings, calendars, and reviews through one API
Last updated
Datapika's Airbnb scraper API returns six record types from one Apify actor, and every one of them bills a flat $0.001 per delivered record: search listings, room details with a date-anchored stay quote, reviews, calendar months, host portfolio items, and Experiences (Apify Store pay-per-event billing, August 2026). You start from a pasted airbnb.com search URL or a latitude and longitude bounding box, add check-in and check-out dates to get nightly prices, and every row lands as flat JSON tagged with a record_type field. Empty and failed runs are never billed, 1,000 records of any type cost $1.00, and the actor has completed 488 runs.
What Airbnb data can you scrape with this API?
The actor covers the Airbnb surfaces most analytics and pricing teams need, and each one bills its own per-record event at the same flat $0.001 rate. Search modes return listing cards with nightly price, rating, review count, Superhost and Guest Favorite flags, coordinates, and images. Room details fetches the full listing page: description, amenities, host ID and name, a price quote for your dates, plus embedded reviews and calendar arrays.
Reviews mode returns one row per review with rating, comment text, language, creation date, and reviewer name and location. Calendar mode returns month-by-month availability for each room URL, host portfolio mode returns every active listing for a numeric host ID, and Experiences mode searches Airbnb Experiences by place ID. All rows share the same flat shape, so a single dataset can hold listings and reviews side by side and be filtered on record_type in a spreadsheet, a BI tool, or an LLM pipeline.
- Listing rows: room_id, room_url, title, room_type, person_capacity, bedrooms, beds, bathrooms, rating, review_count, is_superhost, is_guest_favorite, free_cancellation, price_per_night, price_total, latitude, longitude, images
- Room rows add description, amenities, host_id, host_name, host_url, price_currency, and embedded reviews and calendar arrays
- Review rows: room_url, review_id, rating, comment, language, created_at, reviewer_name, reviewer_location
- Calendar rows carry room_url, room_id, and a per-room availability array billed per month scraped
- Host portfolio rows reuse the listing shape with record_type set to host_listing and host_id attached
- Every row includes record_type and a scraped_at ISO timestamp
How do you scrape Airbnb listings by URL or map area?
There are two ways to search for listings and both produce the same listing rows at $0.001 each. Search by URL is the fastest path: apply your filters on airbnb.com in a browser, copy the airbnb.com/s/ URL, and paste it as searchUrl. Since the May 2026 release the actor honors the location segment in the path, so a Paris URL returns Paris listings and multi-segment locations like New-York--NY--United-States work as well.
Search by bounding box is built for map-driven analysis. You pass north-east and south-west latitude and longitude, an optional zoom level from 1 to 20, and filters for check-in and check-out, nightly price range, place type, amenity IDs, and free cancellation only. Both modes accept a currency code, a language code, and a maxResults cap that defaults to 100 and goes up to 5,000, which is the simplest way to keep a large sweep inside budget.
- searchUrl: any airbnb.com/s/ URL with dates, guests, price, and map filters already applied
- neLat, neLng, swLat, swLng plus zoom 1 to 20 (default 12) define the map area for bounding box search
- placeType filters to Entire home/apt, Private room, Shared room, or Hotel room
- priceMin and priceMax filter nightly rates in the currency you set (USD by default)
- Bounding box search only returns prices when both checkIn and checkOut are set
- maxResults defaults to 100 and caps at 5,000 listings per run
How do you get Airbnb prices for specific dates?
Airbnb prices depend on dates, guest count, and currency, so the actor anchors every quote to the stay you specify. In room details mode you pass up to 100 airbnb.com/rooms/ URLs, a checkIn and checkOut date in YYYY-MM-DD format, an adults count from 1 to 16, and a currency code. Each room row then carries price_per_night, price_total, and price_currency for exactly that stay, alongside rating, review count, host, amenities, images, and description.
When a listing is not bookable for your dates, the row still ships with the price fields set to null instead of turning into an error row, so you keep the host, rating, amenity, and image data. Calendar mode is the complement for availability tracking: it returns one calendar record per room URL and bills $0.001 per month in that record, so a room whose calendar spans 12 months costs $0.012 and 100 such rooms cost $1.20.
- room_details inputs: roomUrls (max 100 per run), checkIn, checkOut, adults (default 2, max 16), currency
- Quote fields: price_per_night, price_total, price_currency, tied to the requested stay
- Unavailable dates return null price fields rather than an error row
- room_calendar returns one record per room URL, billed at $0.001 per calendar month
- Reviews and calendar arrays embedded in room rows are best-effort, so a failing sub-fetch never drops the listing
How much does it cost to scrape Airbnb?
Pricing is per delivered record, and every record type bills the same flat $0.001 (Apify Store pay-per-event billing, August 2026). Search listings, host portfolio items, full room details with a stay quote, calendar months, reviews, and Experiences all cost $0.001 per row, so 1,000 records of any kind come to $1.00. Nothing is charged when a run returns no rows or fails outright.
A typical market scan looks like this: 500 listings from a bounding box search cost $0.50, following up with room details on the top 100 costs $0.10, and pulling 1,000 reviews across those rooms costs another $1.00, for $1.60 in total. Each mode bills only its own event, so a run's total is simply the number of delivered records multiplied by $0.001. Keep runs scoped with maxResults and batch room URLs together rather than launching one run per listing.
- listing-scraped: $0.001 per search result (search by URL or bounding box)
- room-details-scraped: $0.001 per full room page with stay quote
- review-scraped: $0.001 per review row
- calendar-month-scraped: $0.001 per calendar month per room
- host-listing-scraped: $0.001 per host portfolio item
- experience-scraped: $0.001 per Experiences result
How does the actor handle Airbnb blocking and partial failures?
Airbnb fingerprints datacenter IP ranges aggressively, so the actor ships with residential proxy enabled by default and the README recommends leaving it on. Room details fetches retry up to 5 times with exponential backoff, and every retry rotates the proxy session so the exit IP changes and a soft block does not follow the request. Challenge and captcha pages are detected explicitly and trigger a fresh-IP retry instead of a misleading parse error.
Batch runs degrade gracefully rather than failing as a whole. If some room URLs are blocked, the successful rows are delivered along with an info row that summarizes how many succeeded and how many to retry, and error rows carry a sanitized error_message, the mode, and the target input that failed. Per-listing sub-fetches for reviews, calendar, and host details are best-effort, so a hiccup on one endpoint returns an empty array and the rest of the row still ships.
- Residential proxy on by default; Airbnb rate-limits datacenter IPs hard
- Up to 5 retries per room with exponential backoff and a new proxy session each attempt
- Challenge pages are detected and retried rather than surfaced as null-value errors
- Info rows summarize partial batches; error rows include error_message, mode, and target
- Every record has a scraped_at ISO timestamp for freshness checks downstream
| Mode | record_type | Price per record | Key fields |
|---|---|---|---|
| search_by_url | listing | $0.001 | room_id, title, room_type, price_per_night, price_total, rating, review_count, is_superhost, is_guest_favorite, free_cancellation, latitude, longitude, images |
| search_by_bbox | listing | $0.001 | Same field set as search_by_url; prices only when checkIn and checkOut are set |
| room_details | room | $0.001 | description, amenities, host_id, host_name, host_url, price_per_night, price_total, price_currency, reviews, calendar |
| room_reviews | review | $0.001 | room_url, review_id, rating, comment, language, created_at, reviewer_name, reviewer_location |
| room_calendar | calendar | $0.001 per month | room_url, room_id, calendar availability array, scraped_at |
| host_listings | host_listing | $0.001 | host_id plus the full listing field set for every active property of that host |
| experience_search | experience | $0.001 | place_id and an experience payload for each Airbnb Experiences result |
How to do it
- 1.Open the Datapika Airbnb scraper on Apify (https://apify.com/openclawai/airbnb-scraper) and pick a mode: search_by_url, search_by_bbox, room_details, room_reviews, room_calendar, host_listings, or experience_search.
- 2.Fill the inputs for that mode: a pasted airbnb.com search URL or four bounding-box coordinates for search, up to 100 room URLs for details, reviews, or calendar, or a numeric hostId for portfolios. Add checkIn, checkOut, adults, and currency when you want stay quotes.
- 3.Set maxResults (default 100, max 5,000), leave the residential proxy on, and start the run. Rows arrive tagged with record_type and can be exported as JSON, CSV, or Excel or pulled through the Apify API.
- 4.For AI agents, connect the MCP endpoint at https://mcp.apify.com/?tools=fetch-actor-details,openclawai/airbnb-scraper so an assistant can call the same modes as tools and pay per delivered record.
Questions, answered
Does Airbnb have an official API I can use instead?
Airbnb runs a partner API at developer.withairbnb.com, but access is limited to approved partners such as property management systems and channel managers, and Airbnb is not currently accepting new access requests from outside developers (Elfsight and Smoobu guides). There is no public key you can sign up for. Datapika's actor needs no Airbnb credentials: it reads public listing, review, and calendar pages and returns them as structured rows billed per record.
How does this compare to other Airbnb scrapers on Apify?
The most used alternative on the Apify Store lists 16,383 users, a 4.52 rating, and a headline price from $1.00 per 1,000 listings, which matches the $1.00 per 1,000 listing rows here (apify.com/tri_angle/airbnb-scraper, checked August 2026). If you only need search cards at volume, the two are priced the same on that headline number. Datapika's case is breadth in one actor at one flat rate: date-anchored room quotes, reviews, per-month calendars, host portfolios, and Experiences all at $0.001 per record, with no charge for empty or failed runs.
How do I scrape every Airbnb listing in a city?
Airbnb limits how many results a single search exposes, so one URL or one large bounding box will not return a whole city. Tile the area into several smaller bounding boxes, raise the zoom level toward 20 for dense districts, and run one search per tile with maxResults set high enough (up to 5,000). Deduplicate on room_id afterwards, since neighbouring tiles overlap at their edges.
Can I scrape Airbnb reviews in other languages?
Yes. Reviews mode takes an ISO two-letter language code (en, es, fr, de, pt, ja, zh, and others) that sets the locale for the review request, and each review row carries its own language field, so you can filter by the language a review was written in. Pass up to 100 room URLs per run and use maxResults to cap reviews fetched per room. Each review row costs $0.001, so 1,000 reviews come to $1.00.
Can an AI agent call the Airbnb scraper through MCP?
Yes. The actor is exposed as an MCP tool at mcp.apify.com with the openclawai/airbnb-scraper identifier, so agents built on Claude, ChatGPT, or any MCP-capable framework can run a bounding box search, request a room quote, or pull reviews as a tool call and pay per record. The flat row shape with record_type and scraped_at fields is designed to be parsed without a custom schema per mode.