Airbnb Scraper — Listings Search & Detail avatar

Airbnb Scraper — Listings Search & Detail

Pricing

from $3.40 / 1,000 listing results

Go to Apify Store
Airbnb Scraper — Listings Search & Detail

Airbnb Scraper — Listings Search & Detail

Scrape Airbnb listings into clean structured JSON. Search any location with dates, guests, price and room-type filters — automatic price-range splitting gets past Airbnb's ~270-result cap. Or pass listing URLs for full detail: price, rating, coordinates, host, amenities count, description.

Pricing

from $3.40 / 1,000 listing results

Rating

0.0

(0)

Developer

Nomad.Dev

Nomad.Dev

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

Scrape Airbnb listings into clean, structured JSON — search any location with dates, guests, price, room-type and bedroom/bed filters, or resolve listing URLs to full detail records (optionally including an availability calendar). Built for reliability: automatic price-range splitting gets past Airbnb's ~270-result cap, blocks are classified and logged (never crash a run), and every record comes back in one flat, predictable shape.

What Airbnb data does this scraper extract?

One flat JSON record per listing:

FieldMeaning
idAirbnb listing id
urlDirect airbnb.com/rooms/... link
titleListing name
propertyTypee.g. "Entire rental unit", "Apartment in Lisbon"
price / currency / pricePerNumeric price, ISO currency, qualifier (total / night)
rating / reviewsCountGuest rating and review count
roomTypeEntire home/apt, Private room, Shared room, Hotel room
beds / bedrooms / bathsWhere Airbnb exposes them
lat / lngListing coordinates
hostNameHost first name (detail mode)
imagesCountNumber of photos
amenitiesCountNumber of amenities (detail mode)
personCapacity / isSuperhost / descriptionDetail mode extras
calendar[{month, year, availableDays}, ...] — only populated when calendarMonths > 0 (detail mode); otherwise null
modesearch or detail

Input

NameTypeDefaultDescription
modestring (search | detail)"search"Search a location, or resolve specific listing URLs/ids to full detail records.
locationstringWhere to search, as typed on airbnb.com (e.g. "Lisbon, Portugal"). Required in search mode.
listingUrlsarray of stringsListing URLs or bare numeric ids. Required in detail mode.
checkIn / checkOutstring (YYYY-MM-DD)Optional dates. With both set, prices become stay totals.
priceMin / priceMaxinteger0Nightly price filter bounds. 0 = no bound.
adults / childreninteger0Guest counts.
roomTypestring (enum)"any"any, entire_home, private_room, shared_room, hotel_room.
minBedroomsinteger0Only listings with at least this many bedrooms. 0 = no filter.
minBedsinteger0Only listings with at least this many beds. 0 = no filter.
minBathroomsinteger0Only listings with at least this many bathrooms. 0 = no filter.
calendarMonthsinteger0Detail mode only. Fetch this many months (0–6) of availability into the calendar output field. 0 = skip. Best-effort (see Known limitations).
maxItemsinteger100Hard cap on listings returned.
currencystring"USD"ISO currency code for returned prices.
concurrency (Advanced)integer2Parallel listing fetches in detail mode (max 4). Keep low — Airbnb rate-limits aggressively.
maxPriceSplits (Advanced)integer8How many times a search may auto-split its price range past the ~270-result cap. Lower it to cap cost on dense markets.
proxyConfigurationobjectApify ResidentialProxy group. Residential is strongly recommended — see Pricing below for its separate billing.

How to scrape Airbnb listings with this Actor

Search mode — set location (e.g. "Lisbon, Portugal"), optionally checkIn/checkOut, priceMin/priceMax (per night), adults, roomType, minBedrooms/minBeds/minBathrooms and maxItems. With dates set, prices are stay totals for those dates. When a query hits Airbnb's ~270-result ceiling, the Actor automatically splits the price range into sub-ranges (up to maxPriceSplits times) and searches each — so large markets still come back complete up to your maxItems.

Detail mode — set mode to detail and pass listingUrls (full URLs or bare numeric ids). Each listing resolves to a full record including coordinates, per-category ratings source, host, photo and amenity counts, a plain-text description, and — if you set calendarMonths — a month-by-month availability summary.

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("nomad-agent/airbnb-scraper").call(run_input={
"mode": "search",
"location": "Lisbon, Portugal",
"checkIn": "2026-09-23",
"checkOut": "2026-09-28",
"priceMax": 150,
"maxItems": 200,
"proxyConfiguration": {"useApifyProxy": True,
"apifyProxyGroups": ["RESIDENTIAL"]},
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["price"], item["currency"], "|", item["title"], item["url"])
curl -X POST \
"https://api.apify.com/v2/acts/nomad-agent~airbnb-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"mode": "detail", "listingUrls": ["https://www.airbnb.com/rooms/796929"]}'

Output example

Real push_data shape (detail mode, live-fetched 2026-07 — description truncated for brevity):

{
"id": "796929",
"url": "https://www.airbnb.com/rooms/796929",
"title": "Rental unit in Lisbon",
"propertyType": "Entire rental unit",
"price": 465.0,
"currency": "EUR",
"pricePer": "total",
"rating": 4.92,
"reviewsCount": 463,
"roomType": "Entire home/apt",
"beds": 2.0,
"bedrooms": 1.0,
"baths": 1.0,
"lat": 38.71991,
"lng": -9.13289,
"hostName": "Bruno",
"imagesCount": 44,
"amenitiesCount": 63,
"personCapacity": 4,
"isSuperhost": true,
"description": "A very cool flat in a great location! ...",
"calendar": null,
"mode": "detail"
}

With calendarMonths set (e.g. 2), calendar is populated instead of null:

"calendar": [
{"month": 7, "year": 2026, "availableDays": 2},
{"month": 8, "year": 2026, "availableDays": 8}
]

Pricing

Pay per event: $0.05 per Actor start and $0.004 per listing returned. 100 listings ≈ $0.45. No subscription — pay only for what you fetch.

Residential proxy is billed separately. The default proxyConfiguration prefill ({"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}) turns Apify's Residential Proxy on by default, and that traffic is billed separately from the actor's own pay-per-event pricing above — per GB, on top of your Apify plan. As of 2026, Apify lists Residential Proxy at roughly $7–8/GB depending on plan tier (Free/Starter ≈ $8/GB, Scale ≈ $7.5/GB, Business ≈ $7/GB) — check Apify's current proxy pricing for the up-to-date rate, since this changes independently of this Actor. If cost-sensitive, you can switch proxyConfiguration to a datacenter group or disable it, at the risk of more frequent blocks (see Anti-blocking notes).

Integrations

Dataset results export straight to JSON, CSV, Excel/XLSX, or a plain HTML table from the Apify Console. Pull them into Make, Zapier or n8n via Apify's native integrations, call run-sync-get-dataset-items from any HTTP client (see the curl example above), or use the Apify MCP server to let an LLM agent drive this Actor and read results directly.

Why this Actor?

Airbnb scrapers are notorious for flaky runs and messy nested output. This one is built around three choices: (1) it reads the same structured payloads Airbnb's own site renders from, not brittle HTML selectors; (2) every record is one flat object with stable field names — no digging through sections[12].section.cardData; (3) blocks and rate limits are detected and reported with the partial results you already paid for, instead of a crashed run.

Anti-blocking notes

Airbnb aggressively blocks datacenter and shared IPs. Residential proxies are strongly recommended — set proxyConfiguration to Apify residential (the default prefill). The Actor uses a fixed browser User-Agent, randomized 1–2.5 s delays between requests, and low concurrency (default 2, max 4). A 403/429/challenge response stops the run gracefully and keeps everything collected so far.

Use cases

  • Market and pricing research for short-term rentals (STR analytics)
  • Competitive sets for property managers and revenue managers
  • Feeding availability/pricing data into investment models
  • Monitoring specific listings (price, rating, review count over time)

FAQ

Is it legal to scrape Airbnb? The Actor only reads publicly visible listing data — the same data any logged-out visitor sees. Review Airbnb's terms and your local regulations for your use case; you are responsible for how you use the data.

Why do I get fewer results than Airbnb claims exist? Airbnb itself only serves ~15 pages (~270 listings) per query. The Actor splits price ranges to go past that; extremely dense markets may still need narrower filters (dates, room type).

Why are prices totals, not per night? With checkIn/checkOut set (or when Airbnb picks default dates), listing cards show stay totals — pricePer tells you which one you got. Divide by nights for a nightly rate.

The run says "blocked" — what now? Switch to residential proxies, lower concurrency to 1, and retry. Partial results are kept.

Can I filter by property type (house, apartment, guesthouse, ...) instead of room type? Not currently. roomType (entire home / private room / shared room / hotel room) is a confirmed, documented-by-reverse-engineering raw filter on Airbnb's search page. A separate "property type" facet (house vs. apartment vs. guesthouse) does not have a similarly discoverable raw query param on the public search page — Airbnb only exposes that facet through its interactive UI, not a stable URL param we could verify. propertyType is still returned per-listing in the output (e.g. "Entire rental unit") — it just isn't a request-side filter.

How reliable is calendarMonths? It replays an internal, unauthenticated Airbnb GraphQL persisted query (PdpAvailabilityCalendar) using a known-good operation hash — live-verified working as of 2026-07. Unlike the amenities count (whose operation hash is rediscovered from a JS bundle on every run), this hash is not currently re-discoverable at runtime from any bundle we could find referenced by the listing page, so it's a static snapshot. If Airbnb ever rotates it, calendar fetches fail closed (best-effort — the rest of the record is unaffected) and calendar comes back null for that run until the Actor is updated.

Something broken or missing? Open an issue on the Actor's Issues tab — it is monitored and fixes ship fast.

Attribution

See NOTICE. Price-range-splitting pagination strategy inspired by digital-engineering/airbnb-scraper (GPL-3.0) — algorithm inspiration only, no code copied, translated or derived. All code in this Actor was written from scratch against Airbnb's current site (2026) and is MIT-licensed.