kestrel actors docs

kestrel actors › Hotel & flight prices

Airbnb Scraper — Prices, Availability Calendar & Occupancy

An Airbnb scraper for Airbnb prices and availability: search any place or paste Airbnb URLs and get every listing's nightly rate and total for your dates and guests in any currency, its rating, location and badges — then, per listing, up to 24 months of availability calendar with occupancy data, the full listing details with the exact price breakdown, and reviews. Scrape Airbnb data as rows you own — the short term rental data behind market analysis, an Airbnb price tracker, or a rate check on your own listings — without an Airbnb API key, a login or cookies: it reads the same public endpoints the airbnb.com front-end uses. You pay per row you receive; a place Airbnb does not recognise, an empty search and every status row cost nothing.

Run Airbnb Scraper on Apify →

Airbnb scraper pricing: what one row costs

EventWhat it isPriceCharged for
listingListing row$0.005One Airbnb listing with its price for your dates (or the default displayed price when no dates are given). Listings that could not be priced are free.
calendar_monthCalendar month$0.002One month of day-by-day availability for one listing (a 12-month calendar row = 12 events).
reviewReview row$0.003One guest review with rating, text, date, reviewer and host reply.

Pay per row: a listing row that carries a price, each calendar_month (a 12-month calendar row = 12 events), each review row. Listings that could not be priced, unknown places, empty searches and status rows are free, and a listing and stay is billed once per run even if two searches return it. Worked examples: 80 Lisbon listings with prices for a weekend = 80 listing events; the same 80 with a 6-month calendar = 80 + 480 calendar-month events; your 10 listings with details, 12-month calendars and 20 reviews each = 10 + 120 + 200 events. Platform compute for those runs is a fraction of a cent. Exact per-event prices are on this page's pricing tab.

Airbnb scraper input reference

Every field of Airbnb Prices & Availability Calendar — input, straight from the actor's input schema.

FieldTypeDefaultWhat it does
locationQueriesarrayPlaces to search exactly as you would type them on Airbnb: "Lisbon, Portugal", "Algarve", "Brooklyn, NY". An unrecognised place produces a status row (unknown_area) and costs nothing instead of random listings.
startUrlsarray[]Airbnb search URLs (all their filters are honoured: dates, guests, price, room type, bedrooms, map bounds) or listing URLs (https://www.airbnb.com/rooms/12345678).
listingIdsarray[]Numeric Airbnb listing ids to price and/or fetch calendars, details and reviews for — no search needed.
maxListingsPerQueryinteger40Distinct listings to collect per place or search URL (Airbnb returns at most about 280 for one search; split big areas into neighbourhoods or price bands for more). Range 1-280.
checkInstringCheck-in date, YYYY-MM-DD or relative to the run date ("30 days", "6 weeks") — relative dates keep a schedule valid forever. Leave empty for each listing’s default displayed price.
checkOutstringCheck-out date (after check-in), absolute or relative.
adultsinteger2Adults; prices depend on guests exactly as on Airbnb. Range 1-16.
childreninteger0Children (2–12). Range 0-10.
infantsinteger0Infants (under 2). Range 0-5.
petsinteger0Pets. Range 0-5.
currencystring"USD"Currency for every price (USD, EUR, GBP, …). Echoed in every row.
localestring"en"Airbnb locale for names, descriptions and reviews (en, fr, de, es, pt, it, ja, …).
priceMininteger0Minimum nightly price in the currency above; 0 = no minimum. Minimum 0.
priceMaxinteger0Maximum nightly price in the currency above; 0 = no maximum. Minimum 0.
roomTypesarray[]Restrict to entire homes, private rooms, shared rooms and/or hotel rooms.
minBedroomsinteger0Minimum bedrooms. Minimum 0.
minBedsinteger0Minimum beds. Minimum 0.
minBathroomsinteger0Minimum bathrooms. Minimum 0.
includeDetailsbooleanfalseFetch each listing’s page: description, amenities, house rules, cancellation policy, category ratings, host, capacity, sleeping arrangement, exact price breakdown for the dates (one extra call per listing; same listing price).
calendarMonthsinteger00 = no calendar. N = a calendar row per listing with day-by-day availability for the next N months (up to 24) and an occupancy summary. Priced per listing-month. Range 0-24.
maxReviewsPerListinginteger00 = none. N = up to N reviews per listing with rating, text, date, reviewer and host reply. Range 0-200.
reviewsSortstring (enum)"most_recent"Which reviews to take first. One of: most_recent, highest_rated, lowest_rated, most_relevant.
proxyConfigurationobject{"useApifyProxy": true}Airbnb accepts Apify datacenter proxies for these calls; keep the default.
sessionsinteger4Concurrent egress IPs; each paced at perIp requests per second. Range 1-16.
perIpnumber1Pace per session. Airbnb tolerated 1 request/second and short bursts in tests. Range 0.1-3.

Example input

{ "locationQueries": ["Lisbon, Portugal"], "checkIn": "2026-10-03", "checkOut": "2026-10-06", "adults": 2, "currency": "EUR", "maxListingsPerQuery": 80 }
{ "locationQueries": ["Algarve, Portugal"], "checkIn": "30 days", "checkOut": "33 days", "adults": 2, "currency": "EUR", "maxListingsPerQuery": 200, "calendarMonths": 6 }

Airbnb scraper output fields

Row types in one dataset: listing (price for the dates, rating, location, optional details), calendar (day-by-day availability with an occupancy summary), review, status (per place or listing; never charged).

Dataset views in the Apify Console: Overview, Listings, Calendar, Reviews, Run status.

FieldTypeWhat it holds
typestring
idstringNumeric Airbnb listing id.
urlstringListing URL.
querystringThe place search that produced the row.
namestringListing name as shown in search.
titlestringSearch title, e.g. 'Apartment in Graça' (or the listing page title with details).
property_typestring
areastring
subtitlestring
check_instring
check_outstring
nightsinteger
adultsinteger
childreninteger
infantsinteger
petsinteger
currencystring
localestring
latnumber
lngnumber
location_textstring
ratingnumber
reviews_countinteger
rating_breakdownobject
bedroomsinteger
bedsinteger
bathroomsinteger
summaryarray
price_totalnumberTotal for the stay as Airbnb displays it (after discounts).
price_total_displaystring
price_originalnumberTotal before discounts, when discounted.
price_nightlynumberBase nightly rate from Airbnb's breakdown ('3 nights x $140.87').
price_nightly_effectivenumberTotal ÷ nights (what the stay costs per night after discounts).
price_nightsinteger
price_breakdownarrayAirbnb's price lines: label, amount (discounts negative), original.
badgesarray
is_guest_favoriteboolean
is_superhostboolean
free_cancellationboolean
picturesarray
detailsbooleanTrue when the listing page was fetched (description, amenities, policies, host, exact breakdown).
room_typestring
person_capacityinteger
availablebooleanWhether the listing can be booked for the dates (details only).
unavailable_messagestring
cancellation_policystring
house_rulesarray
descriptionstring
amenitiesarray
amenities_countinteger
sleepingarray
highlightsarray
hostobject
monthsinteger
daysarrayCalendar rows: one object per day (date, available, available_for_checkin, available_for_checkout, min_nights, max_nights, price).
nights_30integer
available_30integer
occupancy_30numberShare of the next 30 nights not available (blocked or booked).
nights_90integer
available_90integer
occupancy_90number
nights_365integer
available_365integer
occupancy_365number
next_availablestring
min_nights_typicalinteger
first_daystring
last_daystring
review_idstring
textstring
text_localizedstring
languagestring
created_atstring
date_labelstring
reviewer_namestring
reviewer_idstring
reviewer_locationstring
reviewer_is_superhostboolean
host_replystring
host_reply_datestring
highlightstring
stay_typestring
reviews_totalinteger
listing_idstring
statusstring
resolved_placestringThe place Airbnb actually searched (from its canonical URL).
canonical_urlstring
pagesinteger
listingsinteger
pricedinteger
duplicatesinteger
calendarsinteger
calendar_monthsinteger
reviewsinteger
detail_errorsinteger
calendar_errorsinteger
review_errorsinteger
errorstring
fetched_atstring

Example row from a real run

Taken from the actor's README — this is the shape your dataset holds.

{ "type": "listing", "id": "1018680572065141154", "url": "https://www.airbnb.com/rooms/1018680572065141154", "name": "Lisboa Bica Nature Fast Net AC Heating", "title": "Apartment in Lisbon",
  "query": "Lisbon, Portugal", "check_in": "2026-10-03", "check_out": "2026-10-06", "nights": 3, "adults": 2, "children": 0, "infants": 0, "pets": 0, "currency": "USD",
  "price_total": 426.0, "price_total_display": "$426", "price_original": 516.0, "price_nightly": 171.73, "price_nightly_effective": 142.0, "price_nights": 3,
  "price_breakdown": [{ "label": "3 nights x $171.73", "amount": 515.19 }, { "label": "Early booking discount", "amount": -89.73 }, { "label": "Price after discount", "amount": 425.46 }],
  "rating": 4.88, "reviews_count": 156, "bedrooms": 1, "beds": 1, "bathrooms": null, "lat": 38.70975, "lng": -9.14708, "badges": ["Guest favorite"], "is_guest_favorite": true, "is_superhost": false, "free_cancellation": false,
  "pictures": ["https://a0.muscache.com/im/pictures/…"], "details": false, "fetched_at": "2026-08-26T09:10:00+00:00" }
{ "type": "calendar", "id": "11562247", "name": "Charming studio in Baixa", "months": 12, "first_day": "2026-08-01", "last_day": "2027-07-31",
  "nights_30": 30, "available_30": 6, "occupancy_30": 0.8, "nights_90": 90, "available_90": 47, "occupancy_90": 0.478, "nights_365": 340, "available_365": 137, "occupancy_365": 0.597,
  "next_available": "2026-08-29", "min_nights_typical": 3, "days": [{ "date": "2026-08-29", "available": true, "available_for_checkin": true, "available_for_checkout": true, "min_nights": 3, "max_nights": 1125, "bookable": null, "price": null }], "fetched_at": "…" }

Airbnb scraper in Python, JavaScript and curl

Python

from apify_client import ApifyClient
client = ApifyClient("<TOKEN>")
run = client.actor("kestrel/airbnb-prices-calendar").call(run_input={"locationQueries": ["Lisbon, Portugal"], "checkIn": "30 days", "checkOut": "33 days", "adults": 2, "currency": "EUR", "maxListingsPerQuery": 80, "calendarMonths": 3})
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())
listings = [r for r in rows if r["type"] == "listing"]; cal = {r["id"]: r for r in rows if r["type"] == "calendar"}
for l in sorted(listings, key=lambda r: r["price_nightly_effective"] or 0)[:10]: print(l["name"], l["price_nightly_effective"], "occupancy 90d", cal.get(l["id"], {}).get("occupancy_90"))

JavaScript (Node)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<TOKEN>' });
const run = await client.actor('kestrel/airbnb-prices-calendar').call({ listingIds: ['11562247'], checkIn: '30 days', checkOut: '33 days', includeDetails: true, calendarMonths: 12 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter(r => r.type === 'calendar').map(r => [r.id, r.occupancy_90, r.next_available]));

curl

curl -X POST "https://api.apify.com/v2/acts/kestrel~airbnb-prices-calendar/run-sync-get-dataset-items?token=<TOKEN>" -H "Content-Type: application/json" \
  -d '{"locationQueries": ["Lisbon, Portugal"], "checkIn": "2026-10-03", "checkOut": "2026-10-06", "maxListingsPerQuery": 20}'

The same three calls are runnable files in the examples repository: examples/airbnb-prices-calendar.py|.js|.sh.

Limits and honest notes

  • A search returns the site's ranking up to its cap (about 280 listings); cover a city with neighbourhood queries, price bands (priceMin/priceMax) or map bounds in a pasted URL.
  • occupancy_* counts nights that are not available; blocked nights and booked nights look the same in the calendar.
  • Prices are what a logged-out visitor sees in currency for the stay and guests given; some markets show all-in prices, others add fees at checkout — the breakdown says which.
  • The query hashes change occasionally; the actor refreshes them automatically from the site's bundles, a daily canary run watches it, and failures appear as status rows rather than silent zeros.

FAQ

Does it need an Airbnb API key, login or cookies?

No. It uses the public key every visitor's browser uses and no session; there is no API key for guests to request.

Is there a free Airbnb scraper here?

Apify's free plan covers small runs, and the actor never charges for unknown places, unpriced listings or empty searches. The Python and JavaScript examples above are complete.

Why does a place come back as unknown_area?

An unrecognised place is answered with listings from all over the world; the actor detects that (empty canonical URL, listings thousands of km apart), returns a status row and charges nothing. Use the spelling the site suggests, e.g. "Lisbon, Portugal".

Can I get more than 280 listings for a city?

Yes — run several searches: neighbourhoods, price bands, room types, or pasted search URLs with map bounds. Each listing is billed once per run.

Is occupancy the same as bookings?

No. It is the share of nights not available; hosts also block nights. Over a market it tracks demand well; for one listing treat it as an upper bound.

Can I track Airbnb prices and availability over time?

Yes. Schedule the actor with relative dates; every run appends dated rows (fetched_at), and the calendar summary gives occupancy per run.

Can I scrape Airbnb host emails or phone numbers?

No, by design: the rows carry the host's public first name, Superhost and verification flags and stats, nothing off-platform.

Can I download an Airbnb dataset as CSV?

Every run's dataset downloads as JSON, CSV or Excel from the run page or the API — an Airbnb dataset for the market, dates and listings you chose, with calendar days as nested arrays (CSV flattens them per day).

Can I get Airbnb listing data without dates?

Yes: leave checkIn/checkOut empty and each listing row carries the default displayed price and price_nights; add includeDetails for description, amenities and host.

Which languages and currencies?

Any site locale for text (locale) and any ISO currency for prices (currency); both are echoed in every row.

Last verified working: 2026-08-29.

How to use Airbnb Scraper

Ready-made runs you can open and start

Each one is a saved input on the Apify Store — open it, press Start, and it runs with the fields already filled in. All 163 across the suite.

Ready-made runWhat it does
Airbnb Availability Calendar for a MarketForty Lisbon listings with six months of day-by-day availability each, plus an occupancy summary per listing - one run, one dataset.
Airbnb Comps: Nightly Rate by BedroomsEntire homes with two or more bedrooms in Austin between $80 and $400 a night - the comp set a host prices against, filtered before billing.
Short-Term Rental Data: AirDNA AlternativeA hundred Barcelona listings with rates, amenities, house rules, host data and three months of calendar - the inputs a rental-market model needs.
Airbnb Occupancy Data by Listing IDTwelve months of day-by-day availability for three known listing ids, with the booked-night count per listing - no search, no wasted rows.
Airbnb Nightly Rate by Listing IDFive known Lisbon listings priced for the same three-night stay: nightly rate, total with fees, guests, bedrooms and rating in one row each.
Airbnb Listing Data: Amenities and RulesTwenty-five Porto listings with description, amenities, house rules, cancellation policy, sleeping arrangements, host and category ratings.
Scrape Airbnb Reviews and Prices TogetherTwenty Seville listings with their nightly rate and the twenty most recent guest reviews each - price and sentiment joined on the same listing id.
Airbnb Price Tracker from a Search URLPaste an Airbnb search URL and every filter on it is honoured - map bounds, dates, guests, room type - so the tracked set is exactly what you saw.
Scrape Airbnb Listings Over $500 a NightAspen entire homes priced above $500 a night: the luxury tier only, with cheaper listings filtered out before a single row is billed.
Airbnb Market Data for Private RoomsBerlin private rooms under 80 EUR a night: the budget tier of a market, sized and priced without pulling every entire home in the city.
Airbnb Data for 3-Bedroom Family HomesAlgarve entire homes with three bedrooms and two bathrooms, priced for four adults and two children on a seven-night summer stay.
Airbnb API Alternative: One Call, JSON OutAirbnb has no public listings API. This is the smallest replacement: one place, one stay, 25 priced Paris listings as JSON, in French and EUR.
Airbnb Data API: 28-Night Monthly RatesA 28-night stay in Medellin triggers Airbnb monthly discounts, so the nightly rate a digital nomad pays is not the nightly rate a week-long guest sees.

Run Airbnb Scraper

The actor lives on the Apify Store, where the pricing tab carries the live per-row price and the input form has every field above: apify.com/kestrel/airbnb-prices-calendar