DEV Community

Feedsmith
Feedsmith

Posted on

Airbnb has no public API - how to get listing and price data for any city (Python)

People search "Airbnb API" thousands of times a month, but Airbnb has never had a public API for listing
data. Its partner APIs are for hosts and software vendors managing their own listings. If you're sizing a
short-term-rental market, pricing your own place against the neighbourhood, or doing a data-science project, you
end up doing one of these:

  1. Download a static dataset (Inside Airbnb, Kaggle): free and great for research, but a snapshot, with no prices for your dates.
  2. Pay for a market-analytics subscription: polished dashboards, priced for professionals.
  3. Collect the public search results yourself.

This post is about option 3, done without writing or maintaining a scraper.

The 270-result wall

An Airbnb search tops out at 15 pages of 18 results: about 270 listings per query, however many exist. A city
like Lisbon has thousands. Most tools stop at that wall, and the popular Airbnb scraper on the Apify Store states
a 240-result limit.

The way around it is to split the query until each piece fits under the wall: first by nightly-price band,
then, if a band is still full, into map quadrants. Then de-duplicate by listing id. I built that into an
Apify Actor called "exhaustive mode". In a cloud test on
Porto for four nights it returned 330 unique listings from 28 sub-queries (41 HTTP requests) in 50 seconds,
past the single-query ceiling. A Lisbon test hit the requested 400-listing cap with zero duplicate ids.

Script: a city's listings for your dates

import csv, os, requests

resp = requests.post(
    "https://api.apify.com/v2/acts/feedsmith~airbnb-listings-scraper/run-sync-get-dataset-items",
    params={"timeout": 600},
    headers={"Authorization": f"Bearer {os.environ['APIFY_TOKEN']}"},
    json={
        "locations": ["Porto, Portugal"],
        "checkIn": "2026-11-06", "checkOut": "2026-11-09",
        "exhaustive": True, "maxItems": 300, "currency": "USD",
    },
    timeout=630,
)
resp.raise_for_status()
listings = resp.json()

fields = ["id", "name", "roomType", "priceNightly", "priceTotal", "nights",
          "rating", "reviewsCount", "latitude", "longitude", "url"]
with open("airbnb_listings.csv", "w", newline="") as f:
    w = csv.DictWriter(f, fieldnames=fields, extrasaction="ignore")
    w.writeheader()
    w.writerows(listings)
print(len(listings), "listings")
Enter fullscreen mode Exit fullscreen mode

Real rows from that run (2026-09-18):

id,name,roomType,priceNightly,priceTotal,nights,rating,reviewsCount,latitude,longitude,url
38350016,São Bento Dream Loft - City's  Historic Center,entire_home,87.67,263,3,4.92,241,41.1444,-8.6113,https://www.airbnb.com/rooms/38350016
19666593,Casas de SantAna - Old town amazing views,entire_home,130.33,391,3,4.98,632,41.1426,-8.6133,https://www.airbnb.com/rooms/19666593
Enter fullscreen mode Exit fullscreen mode

priceTotal is what Airbnb shows for your whole stay. priceNightly is that total divided by the nights, so it
includes cleaning and service fees spread over the stay. That's usually what you want when comparing listings, but
it can sit a bit above the "per night" figure Airbnb's own price filter uses.

A trap when computing market stats

My first version of this script printed median prices from those 300 listings: $158.67 per night for entire homes,
and a p75 of $536. That p75 is wrong as a market figure. Exhaustive mode walks the city price band by price
band
, so a run that stops at maxItems has only covered some of the bands. The sample is skewed, not random.

Two ways to get honest numbers:

  • Raise maxItems until the run finishes below it. Then you have every listing Airbnb returns for those dates and filters.
  • Or narrow the search (a neighbourhood's map bounds, a price range, roomType) so the full set is small.

The example repo's script now prints a warning when a run was cut off by maxItems.

Details per listing

Set "includeDetails": true to also fetch each listing page: description, the amenities list, house rules, bedrooms,
beds, bathrooms, guest capacity, the host's first name and superhost flag, and six sub-ratings (cleanliness, accuracy,
check-in, communication, location, value). In a four-listing test all four came back complete.

Cost

What Price
Listing (search data) $1.20 per 1,000
Listing details (optional) $2.00 per 1,000

The Porto run above (300 listings) cost the user about $0.36. Duplicates and failed pages are free.

Caveats

  • Prices depend on dates, guests and currency. Always pass dates if you care about prices.
  • About one search page in five comes back as an empty page shell. The Actor retries it up to three times, and if it still fails it logs a warning rather than dropping data silently.
  • It collects public listing data only: no host contact details and no guest reviews' author data.
  • Airbnb's terms restrict automated access. Use the data responsibly and check what's appropriate for your use case and jurisdiction.

Links

Not affiliated with Airbnb. Disclosure: I built this Actor. This article was drafted with AI assistance (Claude); every command, number and output above comes from real runs on 2026-09-18.

Top comments (0)