Airbnb Scraper: Listings, Prices & Availability by Location avatar

Airbnb Scraper: Listings, Prices & Availability by Location

Pricing

Pay per event

Go to Apify Store
Airbnb Scraper: Listings, Prices & Availability by Location

Airbnb Scraper: Listings, Prices & Availability by Location

Export Airbnb listings for any city or search URL with prices, ratings, reviews, rooms and coordinates; add dates for real stay prices and availability, or listing URLs for host, amenities and rules. $3 per 1,000 listings, plus $2 per 1,000 with details; no login.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Changefeeds Tools

Changefeeds Tools

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

  • What you get: one row per Airbnb listing for a city or a pasted airbnb.com search URL: name, price and its breakdown, rating, reviews, bedrooms, beds, coordinates and badges.
  • Add dates for real stay prices and availability, or pass listing URLs for full details: description, amenities, house rules, host and sub-ratings. No Airbnb account or login.
  • Price: $3 per 1,000 listings, or $5 per 1,000 with details. Proxy included; failed inputs are free.

Sample output

The prefilled input (Lisbon, Portugal, 10 listings, no dates), run on 2026-10-23. First five rows:

namearearating (reviews)bedrooms / bedspricedates Airbnb priced
Liberdade Boutique @ Chic Condo/ Parking/Lift/AC TSanto António4.98 (49)1 / 1$862 USD total2026-11-22 to 11-27
Chiado Trindade 19 Apartments - 2A CastelãoSanta Maria Maior4.95 (187)1 / 2$870 USD total, originally $1,002 USD2026-11-09 to 11-14
CityLux 1 bedroom Fast Internet with Lift/ElevatorSanta Maria Maior4.93 (223)1 / 2$788 USD total2026-11-02 to 11-07
Boutique Apartment in Cais do Sodré • Time OutSão Paulonew (0)1 / 2$915 USD total2026-11-04 to 11-09
Time Out Market - AC - ElevatorSão Paulo4.87 (491)1 / 2$625 USD total2026-12-01 to 12-06

The fifth row in full (images cut to one):

{
"type": "listing",
"id": "26302507",
"url": "https://www.airbnb.com/rooms/26302507?check_in=2026-12-01&check_out=2026-12-06&adults=2",
"name": "Time Out Market - AC - Elevator",
"title": "Apartment in São Paulo",
"subtitle": "Time Out Market - AC - Elevator",
"roomType": null,
"propertyType": "Apartment",
"area": "São Paulo",
"city": null,
"lat": 38.70682,
"lng": -9.14765,
"rating": 4.87,
"reviewsCount": 491,
"isNew": false,
"isSuperhost": null,
"guestFavorite": true,
"price": {
"amount": 625,
"currency": "USD",
"qualifier": "total",
"nights": null,
"originalAmount": null,
"label": "$625 USD total",
"checkIn": "2026-12-01",
"checkOut": "2026-12-06",
"datesChosenByAirbnb": true,
"breakdown": [
{ "description": "5 nights x $115.91 USD", "amount": 579.57, "text": "$579.57 USD" },
{ "description": "Taxes", "amount": 44.88, "text": "$44.88 USD" },
{ "description": "Total", "amount": 624.45, "text": "$624.45 USD" }
],
"notes": []
},
"available": null,
"unavailableReason": null,
"priceError": null,
"images": ["https://a0.muscache.com/im/pictures/7e8f1a7a-2c4e-4060-9ddb-1cb10552b5ee.jpg"],
"badges": ["Guest favorite"],
"paymentMessages": [],
"bedrooms": 1,
"beds": 2,
"bathrooms": 1,
"guests": null,
"propertyId": null,
"searchInput": "Lisbon, Portugal",
"position": 5,
"hasDetails": false,
"detailsError": null,
"description": null,
"amenities": null,
"houseRules": null,
"highlights": null,
"host": null,
"subRatings": null,
"scrapedAt": "2026-10-23T03:56:55.264Z"
}

area is Airbnb's own neighbourhood label (São Paulo is a former parish of central Lisbon, around Cais do Sodré). price.amount is the rounded figure from the search card; breakdown carries Airbnb's exact lines, and nights stays null when the card's label does not state it.

With includeDetails on, or for any listingUrls row, the same row also carries the listing page's fields (from a live run on 2026-09-30, shortened):

{
"roomType": "Entire home/apt",
"propertyType": "Entire rental unit",
"city": "Porto",
"isSuperhost": true,
"guests": 2,
"hasDetails": true,
"description": "Beautiful studio apartment set in a fully renovated 18th-century building, with air conditioning for heating and cooling…",
"amenities": ["River view", "Garden view", "Hair dryer", "Shampoo", "…38 in total"],
"houseRules": ["Check-in: 3:00 PM - 12:00 AM", "Checkout before 11:00 AM", "Self check-in with keypad", "2 guests maximum", "No pets"],
"highlights": ["Top 10% of homes", "Self check-in", "Vibrant neighborhood"],
"host": { "id": "245989121", "name": "Isabel & Igor", "isSuperhost": true, "isVerified": true, "rating": 4.9, "reviewsCount": 4616, "yearsHosting": 7, "responseRate": "Response rate: 100%", "responseTime": "Responds within an hour" },
"subRatings": { "accuracy": 4.93, "checkIn": 4.97, "cleanliness": 4.91, "communication": 4.98, "location": 4.95, "value": 4.89 }
}

How to run in 30 seconds

  1. Click Try for free. The input already holds Lisbon, Portugal and 10 listings.
  2. Click Start. Our test run of that input took 17 seconds and cost $0.03 (10 listings).
  3. Open the Output tab, or export the dataset as CSV, JSON or Excel.

For your own search, replace the place name, or paste a search URL copied from airbnb.com (its filters are kept). Add Check-in and Check-out dates for prices you can compare, and raise Max listings per location (up to 270).

Pricing

  • $0.003 per listing row (listing-returned), $3 per 1,000.
  • $0.002 extra per listing with details (details-added): search results with includeDetails on, and every listingUrls row, since those always come from the listing page. So $5 per 1,000 with details. A search row whose listing page could not be read is delivered with detailsError and charged as a plain listing.
  • Proxy traffic is included. Failed inputs (not_found, invalid, blocked, error) are free.
  • If you set a maximum total charge, the actor checks the remaining budget before each page, stops cleanly once it is reached, and records "max_total_charge_reached" in OUTPUT.stopped_reason.

FAQ

Do I need an Airbnb account? No. Only public, logged-out pages.

Can I use my own search with filters? Yes. Set up the search on airbnb.com (any country domain), copy the URL from the address bar and put it in Locations or search URLs. Its filters are kept; your dates, guests, currency and price fields are added only where the URL does not already set them.

Why are the dates different on every row? You gave no dates, so Airbnb priced each result for its own sample stay. The row says so with price.datesChosenByAirbnb: true. Give dates for comparable prices.

Why fewer listings than "Over 1,000 homes"? Airbnb shows at most 15 pages per search (see Limits). Split the search into price bands.

Why is price null? On a listing URL without dates, Airbnb shows no price. With dates, the listing may be unavailable for them (see available and unavailableReason), or the booking-box call failed (priceError).

Limits

  • Airbnb shows at most 15 pages of 18 results per search, and the pages overlap. A live 15-page run for "Lisbon, Portugal" returned 242 unique listings, although Airbnb says "Over 1,000 homes". Such a search is marked truncated and listed in OUTPUT.truncated_inputs. To get more, run the same place in price bands (minPrice/maxPrice, e.g. 0-80, 80-150, 150-300, 300+), by neighbourhood, or with smaller map-area search URLs. maxItems is capped at 270 for this reason.
  • Prices are what the card or booking box shows, in the format Airbnb uses for your currency and region; depending on the region that may be before taxes. price.breakdown and price.notes carry Airbnb's own lines. Hotels can show "Price may vary by room type".
  • isSuperhost is null on plain search rows unless the card shows a Superhost badge; search cards do not say when a host is not one. The listing page (includeDetails) gives the real value.
  • Listing URLs get a price only with dates. With dates, the actor makes one more request for the booking box; if that fails, the row still arrives with priceError.
  • Search results include what Airbnb puts in them, such as "Featured hotel" placements (badges, propertyId set).
  • Not supported: vanity /h/... links (use the /rooms/<id> URL), experiences, review text, calendars beyond the dates you give, and anything that needs a login. The actor never solves CAPTCHAs; a challenged request is retried from a new proxy IP up to 8 times, then reported as a free blocked row.
  • It stays polite: search pages one at a time, at most 2 listing pages in flight, at least 500 ms between requests, 20 s timeouts, HTTP 429/5xx retried with backoff (up to 3 retries, Retry-After honoured up to 60 s).
  • Airbnb changes its site. The actor reads the data embedded in Airbnb's pages and finds the booking-box query id in Airbnb's current JavaScript at run time. A layout change can still break a field until the actor is updated; a page without the expected data becomes an error row, never a silently empty result.

Input reference

FieldTypeDefaultWhat it does
locationslist of stringsA place name per line ("Lisbon, Portugal"), or a full airbnb.com/s/... search URL copied from your browser. A pasted URL is used as-is, with all its filters (room type, amenities, map area).
listingUrlslist of stringsairbnb.com/rooms/<id> URLs (any Airbnb country domain) or bare numeric ids. One detail row each.
checkIn / checkOutYYYY-MM-DDnoneOptional; give both or neither. With dates, search prices are for your stay and listing URLs also get a price and availability.
adultsinteger 1-162Guests. Changes which listings show and their prices.
currency3-letter codeUSDEUR, GBP, JPY, ... A pasted search URL that already has currency= keeps its own.
minPrice / maxPriceintegernoneAirbnb's own per-night price filter, in currency. Searches only.
maxItemsinteger 1-270100Max listings per location.
includeDetailsbooleanfalseAlso open each search result's listing page and add the detail fields (one extra page per listing; see Pricing).
proxyproxy settingsApify Proxy, residentialAirbnb blocks many datacenter IPs, so requests go through residential proxy by default.

Priced for your dates, with details:

{ "locations": ["Porto, Portugal"], "checkIn": "2026-11-20", "checkOut": "2026-11-23", "currency": "EUR", "minPrice": 60, "maxPrice": 150, "includeDetails": true, "maxItems": 50 }

Specific listings, with availability:

{ "listingUrls": ["https://www.airbnb.com/rooms/12537150", "1144816383633864634"], "checkIn": "2026-11-28", "checkOut": "2026-12-03" }

Output reference

A listing URL with dates it is booked for comes back as "available": false, "unavailableReason": "Those dates are not available", "price": null. With dates it is free for, price holds the booking-box total, with "available": true.

A failed input gets a free status row instead:

{ "type": "status", "input": "https://www.airbnb.com/rooms/1", "source": "listingUrls", "status": "not_found", "error": "Listing 1 not found (removed, unlisted, or never existed).", "checkedAt": "2026-09-30T05:37:53.680Z" }
  • not_found: the listing is gone, or Airbnb did not recognise the place name (it fell back to a generic map area).
  • invalid: not a place, search URL, listing URL or id (a /rooms/ URL put in locations is pointed at listingUrls), or a duplicate listing.
  • blocked: Airbnb's bot protection refused the request from every proxy IP tried.
  • error: any other HTTP or network failure.

The key-value store record OUTPUT holds a run summary: counts by type, charged_events, stopped_reason, truncated_inputs, and per location the search URL used, Airbnb's own heading ("Over 1,000 homes in Lisbon"), pages fetched and why it stopped. Every run leaves at least one dataset row, so a quiet run is never mistaken for a broken one.