Site scraper

Airbnb Scraper: Public Airbnb Listings via API

HTTP $0.50JS rendering $2.00 per 1,000 results or your own scraper from $1.95/GB

ProxyField's Web Scraping API, in development (Contact sales), is designed to return a whole city's Airbnb listings, prices and availability calendars as JSON at $2.00 per 1,000 successful results, which is $0.002 per call, or $1.00 per 1,000 from 10,000 results in one purchase. One listing's priced calendar, 10 months of open and blocked nights plus the price for 8 open check-in dates in one JSON record, is 9 results, $0.018; a 2,000-listing city with every priced calendar is about 18,300 results, $18.30 at the volume price. Until the API ships, the same scripts run in Playwright on ProxyField residential proxies, starting with the Easy Trial: 1 GB for $2.95.

Web Scraping API per 1,000 successful results
Web Scraping API prices per 1,000 successful results
FetchEntryVolume, from
HTTP$0.50$0.20
JS rendering$2.00$1.00

Billed on successful results only.

Your own scraper on residential proxies
from $1.95/GB Easy Trial: 1 GB for $2.95
gate.proxyfield.io:7000

At a glance (API design of 2026-10-27, in development; API documentation):

Web Scraping API on Airbnb
Statusin development: Contact sales. Not callable yet
Price per call$0.002 per successful result ($2.00 per 1,000, JS rendering); $0.001 ($1.00 per 1,000) when one purchase holds 10,000 results or more
One listing, priced calendar1 result for up to 10 months of open and blocked nights, plus 1 result per priced check-in date: 8 dates = 9 results, $0.018; 30 dates = 31 results, $0.062
City searchone rendered map box per result; boxes that come back full are split, listings deduplicated by room id
A 2,000-listing citylistings and calendars, 1 date pair: 2,300 results, $4.60. With 8 priced check-in dates per listing: 18,300 results, $18.30 at $1.00 (the purchase is over 10,000)
Outputone JSON record per listing: days[] with blocked and, where priced, price, plus a summary (open, blocked, min, median, max)
Billingsuccessful results only; no subscription; paid from the crypto balance, which never expires
Scale20 concurrent requests; batches of up to 1,000 requests with a signed callback; results kept 48 hours
Exit countryany of the pool's 195+ countries (country)
Data

What the JSON looks like: one priced calendar per listing

The API has no fixed Airbnb schema: the JSON is what your evaluate script returns, so you choose the fields. The listing() function on this page merges the calendar and the prices into one record per listing (illustrative values):

JSON
{"id": "<room id 1>", "country": "us", "adults": 2, "nights": 2, "min_nights": 2,
 "checked_at": "2026-11-02T08:00:00Z",
 "days": [{"date": "2026-12-10", "blocked": false, "price": 214, "currency": "€", "price_text": "€214"},
          {"date": "2026-12-11", "blocked": false, "price": 236, "currency": "€", "price_text": "€236"},
          {"date": "2026-12-12", "blocked": true}],
 "summary": {"days": 3, "open": 2, "blocked": 1, "priced": 2, "min": 214, "median": 225, "max": 236}}
Read moreShow less
FieldWhere it comes fromExample
idthe room id in /rooms/<id>"<room id 1>"
days[].date, days[].blockedthe listing's calendar cells, up to 10 months in 1 result"2026-12-12", true
days[].price, currency, price_textthe listing page with that check-in and nights later as check-out, 1 result per date; only open dates are priced214, "€", "€214"
min_nightsthe minimum-stay note, where the page shows one2 or null
summarycounted by your script: open, blocked and priced nights; lowest, median and highest pricesee above
country, adults, nights, checked_atyour request and the time of the check"us", 2, 2

price is the number Airbnb shows for that stay (a total or a nightly rate, depending on the market), currency is the symbol or code in front of it, such as €, CA$ or US$, and price_text keeps the page's own text so you can recheck the parse.

Why prices cost 1 result per date. Airbnb's calendar shows open and blocked nights but no prices; a price appears only for a stay with dates. So the calendar is 1 result, and each priced check-in date is 1 more: the listing page with those dates in its URL. Pricing only open dates keeps the count down.

The city search writes one more file, one record per listing for the search's date pair:

JSON
[
  {"id": "<room id 1>", "title": "Loft in Alfama", "price": 412, "currency": "€", "price_text": "€412",
   "checkin": "2026-12-10", "checkout": "2026-12-14", "nights": 4, "adults": 2, "country": "us"}
]

How the API is designed to cover a whole city

Airbnb's search stops after a limited number of result pages, so a whole city never fits in one search. The way around it is to split the map until no search comes back full.

  1. Fix the search

    One set of dates, guests and country for the whole run: checkin=2026-12-10&checkout=2026-12-14&adults=2, sent from the country whose prices you want.

  2. Split the city into map boxes

    Start with the city's bounding box; when a box comes back with a full page of listings, split it in four and search each part, until no box is full.

  3. Extract in the browser

    Each search is one rendered request with an evaluate action that returns the cards as JSON (room id, title, price text).

  4. Deduplicate by room id

    Boxes overlap at their edges; the room id in /rooms/<id> is the key.

  5. Fetch each listing once for its priced calendar (next section), then write one JSON file per city and date pair.

Read moreShow less

The script follows the Web Scraping API's design (API documentation); access is through Contact sales. The selectors are examples: Airbnb changes its markup, so check them against a page you saved.

Python
import json, re, requests

API = "https://api.proxyfield.io/v1/scrape"
HEAD = {"Authorization": "Bearer <api_key>"}
CHECKIN, CHECKOUT, ADULTS, COUNTRY = "2026-12-10", "2026-12-14", 2, "us"
DATES = f"checkin={CHECKIN}&checkout={CHECKOUT}&adults={ADULTS}"
FULL_PAGE = 18   # cards on one full result page in your sample: check it
EXTRACT = r"""(() => [...document.querySelectorAll('[itemprop="itemListElement"]')].map(c => ({
  url: c.querySelector('meta[itemprop="url"]')?.content,
  title: c.querySelector('meta[itemprop="name"]')?.content,
  price: (c.innerText.match(/[A-Z]{0,3}[$€£¥₹]\s?\d[\d.,]*/) || [null])[0]
})))()"""

def parse_price(text):
    m = re.match(r"\s*([^\d\s]+)\s?([\d.,]+)", text or "")
    if not m:
        return None, None
    return int(re.sub(r"\D", "", m.group(2))), m.group(1)   # whole-currency card prices

def search(ne_lat, ne_lng, sw_lat, sw_lng):
    url = (f"https://www.airbnb.com/s/homes?{DATES}&search_by_map=true"
           f"&ne_lat={ne_lat}&ne_lng={ne_lng}&sw_lat={sw_lat}&sw_lng={sw_lng}")
    r = requests.post(API, headers=HEAD, timeout=180, json={
        "url": url, "render": True, "country": COUNTRY, "output": "json",
        "wait_for": "[itemprop='itemListElement']",
        "actions": [{"type": "evaluate", "script": EXTRACT}]}).json()
    return r["actions_log"][0].get("result") or []

def crawl(box, out, depth=0):
    cards = search(*box)
    for c in cards:
        m = re.search(r"/rooms/(\d+)", c.get("url") or "")
        if m:
            price, currency = parse_price(c.get("price"))
            out[m.group(1)] = {"id": m.group(1), "title": c.get("title"), "price": price,
                               "currency": currency, "price_text": c.get("price"),
                               "checkin": CHECKIN, "checkout": CHECKOUT, "adults": ADULTS,
                               "country": COUNTRY}
    if len(cards) >= FULL_PAGE and depth < 6:        # a full box: split it in four
        ne_lat, ne_lng, sw_lat, sw_lng = box
        mlat, mlng = (ne_lat + sw_lat) / 2, (ne_lng + sw_lng) / 2
        for b in [(ne_lat, ne_lng, mlat, mlng), (ne_lat, mlng, mlat, sw_lng),
                  (mlat, ne_lng, sw_lat, mlng), (mlat, mlng, sw_lat, sw_lng)]:
            crawl(b, out, depth + 1)

listings = {}
crawl((38.80, -9.09, 38.69, -9.23), listings)       # Lisbon: NE corner, SW corner
json.dump(list(listings.values()), open(f"lisbon-{CHECKIN}.json", "w"), ensure_ascii=False, indent=1)
print(len(listings), "listings")

For large runs, the same request goes into a batch of up to 1,000 requests, with a signed callback per finished job and results kept 48 hours; an account runs 20 concurrent requests (higher limits through sales).

Airbnb availability calendars with prices, as JSON

A listing's calendar is on its public page: each night is open or blocked. Fetch airbnb.com/rooms/<id> with JS rendering, then run browser actions in the same request: a click on the calendar's next-month button for each further month, and an evaluate that returns each day cell's date and state. Up to 20 actions run in one request, so a listing's next 10 months (an evaluate on each view, 9 clicks and the minimum-stay read, 20 actions) are still one result. prices() adds 1 result per check-in date, and listing() runs both and returns the one record shown above: 8 priced dates are 9 results, $0.018 at $2.00 per 1,000.

Read moreShow less
Python
import statistics
from datetime import date, timedelta

DAYS = r"""(() => [...document.querySelectorAll('[data-testid^="calendar-day-"]')].map(d => ({
  date: d.getAttribute('data-testid').replace('calendar-day-', ''),
  blocked: d.getAttribute('data-is-day-blocked') === 'true'
})))()"""
MIN_NIGHTS = r"""(() => { const m = document.body.innerText.match(/(\d+)[- ]night minimum/i);
  return m ? Number(m[1]) : null; })()"""

def calendar(room_id, months=6):                      # up to 10 months: 2 * months - 1 + 1 <= 20 actions
    read = {"type": "evaluate", "script": DAYS}
    actions = [read] + [{"type": "click", "selector": "<next-month button>"}, read] * (months - 1)
    actions.append({"type": "evaluate", "script": MIN_NIGHTS})
    r = requests.post(API, headers=HEAD, timeout=180, json={
        "url": f"https://www.airbnb.com/rooms/{room_id}", "render": True,
        "country": COUNTRY, "output": "json", "wait_for": "[data-testid^='calendar-day-']",
        "actions": actions}).json()
    evals = [s for s in r["actions_log"] if s["type"] == "evaluate"]
    days = {}
    for step in evals[:-1]:
        for d in step.get("result") or []:
            days[d["date"]] = d                            # views overlap: one record per date
    blocked = sum(d["blocked"] for d in days.values())
    return {"id": room_id, "country": COUNTRY, "min_nights": evals[-1].get("result"),
            "days": list(days.values()),
            "summary": {"days": len(days), "open": len(days) - blocked, "blocked": blocked}}

PRICE = r"""(() => (document.body.innerText.match(/[A-Z]{0,3}[$€£¥₹]\s?\d[\d.,]*/) || [null])[0])()"""

def prices(room_id, first_checkin, n_dates=30, nights=2):   # 1 result per check-in date
    out = []
    for i in range(n_dates):
        ci = date.fromisoformat(first_checkin) + timedelta(days=i)
        co = ci + timedelta(days=nights)
        r = requests.post(API, headers=HEAD, timeout=180, json={
            "url": f"https://www.airbnb.com/rooms/{room_id}?check_in={ci}&check_out={co}&adults={ADULTS}",
            "render": True, "country": COUNTRY, "output": "json",
            "actions": [{"type": "evaluate", "script": PRICE}]}).json()
        price, currency = parse_price(r["actions_log"][0].get("result"))
        if price is not None:
            out.append({"checkin": str(ci), "checkout": str(co), "nights": nights,
                        "price": price, "currency": currency,
                        "price_text": r["actions_log"][0].get("result")})
    vals = [p["price"] for p in out]
    return {"id": room_id, "country": COUNTRY, "adults": ADULTS, "prices": out,
            "summary": {"dates": len(vals), "min": min(vals, default=None),
                        "median": statistics.median(vals) if vals else None,
                        "max": max(vals, default=None)}}

def listing(room_id, first_checkin, n_dates=8, nights=2, months=10):
    cal = calendar(room_id, months)                          # 1 result
    open_days = [d["date"] for d in sorted(cal["days"], key=lambda d: d["date"])
                 if not d["blocked"] and d["date"] >= first_checkin][:n_dates]
    priced = {}
    for ci in open_days:                                     # 1 result per open check-in date
        p = prices(room_id, ci, n_dates=1, nights=nights)["prices"]
        if p:
            priced[ci] = p[0]
    days = []
    for d in sorted(cal["days"], key=lambda d: d["date"]):
        row = {"date": d["date"], "blocked": d["blocked"]}
        if d["date"] in priced:
            row.update({k: priced[d["date"]][k] for k in ("price", "currency", "price_text")})
        days.append(row)
    vals = [p["price"] for p in priced.values()]
    return {"id": room_id, "country": COUNTRY, "adults": ADULTS, "nights": nights,
            "min_nights": cal["min_nights"], "days": days,
            "summary": {**cal["summary"], "priced": len(vals), "min": min(vals, default=None),
                        "median": statistics.median(vals) if vals else None,
                        "max": max(vals, default=None)}}

city = [listing(room_id, "2026-12-10") for room_id in listings]   # listings: from crawl() above
json.dump(city, open("lisbon-calendars.json", "w"), ensure_ascii=False, indent=1)

A check-in date the host has blocked is never priced, so a listing with 5 open dates in the window costs 6 results, not 9.

The day-cell attributes, the next-month button, the minimum-stay wording, the first price on the page and the check_in/check_out names in the listing URL are examples: check each against a listing page you saved and a URL you copy from your browser, and convert the date to YYYY-MM-DD in the format your page shows. A dated listing page can also show other amounts, such as a struck-through price, so confirm the price_text against the page on a sample. Read the calendar carefully: an open night is not proof that a listing is unbooked, and a blocked night is not proof of a booking, because hosts block dates themselves. Occupancy estimates from calendars are estimates; compare several snapshots over time.

Airbnb data on public pages

Airbnb shows logged-out visitors its search results, listing pages and host profiles; you need no account to read them. Prices appear only once a search has dates, so every price you collect belongs to a set of dates, guests, a currency and the market the request comes from.

Page typeExample URLWhat the public page shows
Search resultsairbnb.com/s/<place>/homes?checkin=…&checkout=…&adults=2Listing title, type, rating, review count, price for the dates, a link to each listing
Listing pageairbnb.com/rooms/<id>Description, guests, bedrooms, beds and baths, amenities, house rules, approximate location, host name, rating by category
Reviewson the listing pageReview text, month, reviewer first name, host replies
Availabilitythe listing's calendarOpen and blocked nights, minimum stay
Host profileairbnb.com/users/show/<id>Name, years hosting, listings, reviews about the host

Host and reviewer names are personal data, so store them only where your purpose needs them. In its design, the API returns the page itself as HTML, Markdown or plain text, or a JSON envelope with the status code, the final URL, the headers, the cookies, the content and the results of your browser actions; it has no parsed Airbnb fields, so your evaluate script or your own parser reads them.

How it works

How the Web Scraping API fetches an Airbnb page

Airbnb builds its search results and prices with scripts after the page loads, so send search URLs and any page you need prices from with JS rendering on; the API is designed to return the rendered page. The API takes a POST to https://api.proxyfield.io/v1/scrape with your API key in an Authorization: Bearer <api_key> header and a JSON body: url, render (false for plain HTTP, true for JS rendering), country and output (html, markdown, text or json). With rendering, wait_for takes a CSS selector to wait for, so the listing cards are on the page before it comes back. Parameter reference: API documentation.

Shell
# The request the Web Scraping API takes (access through Contact sales)
curl https://api.proxyfield.io/v1/scrape \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.airbnb.com/s/Lisbon--Portugal/homes?checkin=2026-12-10&checkout=2026-12-14&adults=2", "render": true, "country": "us", "output": "json"}'

Example response (shortened; content is the rendered page's HTML):

JSON
{
  "metadata": {"id": "req_42bd6a8463b03f49", "api": "web_scrape", "status": "success", "billed": true},
  "status_code": 200,
  "final_url": "https://www.airbnb.com/s/Lisbon--Portugal/homes?checkin=2026-12-10&checkout=2026-12-14&adults=2",
  "content_type": "text/html; charset=utf-8",
  "content": "<!DOCTYPE html><html lang=\"en\">…</html>"
}
ChoicePrice per 1,000 successful resultsUse it for
JS rendering$2.00, or $1.00 from 10,000 resultsSearch results, prices for your dates, the calendar
Plain HTTP$0.50, or $0.20 from 10,000 resultsListing facts that ship in the page's HTML, such as the title and description
Pricing

Pricing: $2.00 per 1,000 Airbnb pages, from $1.00

Airbnb pages cost the Web Scraping API's JS rendering price: $2.00 per 1,000 successful results, from $1.00 at volume; pages that need no browser cost $0.50 per 1,000, from $0.20. You pay only for successful results. The volume prices start at 10,000 successful results in one purchase.

Billed: a page Airbnb answered with a 2xx status. Not billed: blocked requests, timeouts and errors on our side; a blocked request is retried on new IPs, and the retries are not billed. In the API's design, every response says whether it was billed. A target's 404 or 410, and a sign-in page the site serves with a 200 status, count as billed results. Contact sales through the sales team on our 24/7 live chat.

Sizing a city. The volume price needs 10,000 results in one purchase, so each cost below is for the run bought on its own, at the rate that purchase gets. The map-box count, about 15 boxes per 100 listings, is an example input, not a measurement: count your own boxes on a first run.

Fill a purchase to get $1.00: 10,000 results cost $10 at the volume price and cover about 4 runs of a 2,000-listing city with one date pair (2,300 results each). What you do not use stays on your balance, which never expires.

By city size, for one date pair:

Workload
Workload, Searches, Listing results, Results, Cost bought on its own
WorkloadSearchesListing resultsResultsCost bought on its own
One listing, calendar + 8 priced check-in dates–99$0.018 at $2.00
A 2,000-listing city, 1 date pair, every calendar3002,0002,300$4.60 at $2.00
The same city, 4 date pairs, once1,2002,0003,200$6.40 at $2.00
The same city, 4 date pairs, weekly (4 runs a month)4,8008,00012,800$12.80 at $1.00
The same city, every calendar priced for 8 open check-in dates30018,00018,300$18.30 at $1.00
1,000 competing listings, tonight's price, daily for 30 days–30,00030,000$30 at $1.00
City sizeMap boxesListings and calendarsCost on its ownWith 8 priced dates per listingCost on its own
500 listings75575$1.15 at $2.004,575$9.15 at $2.00
2,000 listings3002,300$4.60 at $2.0018,300$18.30 at $1.00
8,000 listings1,2009,200$18.40 at $2.0073,200$73.20 at $1.00

One result is one rendered request: a search box is one result, a listing page with its calendar clicks is one result, and a listing's price for one check-in date is one result. The $1.00 price applies when one purchase covers 10,000 results or more. Payment and balance: the same crypto balance as proxies, which never expires; there is no subscription or monthly fee. All prices: pricing.

Through the sales team on our 24/7 live chat

Compare

Airbnb's API or a scraper?

Airbnb has no open public API. Its API is for approved software partners, such as property management and channel tools that manage hosts' own listings, and it does not give market data on other people's listings. Research on the market is done by reading the public pages, or by using data someone has already collected, such as the Inside Airbnb project, which publishes listing data for a number of cities.

ItemAirbnb partner APIWeb Scraping API
Who can use itApproved software partnersProxyField customers
DataThe listings a host or manager runsPublic search, listing, review and calendar pages
Partner approvalAirbnb's partner programNot needed; Airbnb's terms still apply (see below)
CostSet by the program$2.00 per 1,000 successful rendered pages, from $1.00
Good to know

Why Airbnb prices differ by visitor

The same listing can show a different price to two visitors. Airbnb prices by the dates and the number of guests, shows the currency of the visitor's market, and in some countries shows the total with fees while in others it shows the nightly rate. To collect what guests in one market see, send the search from that country: ProxyField residential proxies offer targeting by country, region (state) and city, with 412M+ residential IPs in 195+ countries. In a Web Scraping API request, country sets the country the request comes from (the exit IP), as a two-letter code such as de; the countries it accepts: the proxy pool's 195+ countries. Fix the dates, guests and country in every check, or the numbers will not compare.

Good to know

Why Airbnb is hard to scrape

Airbnb limits automated traffic: fast searches from one IP and datacenter ranges get errors or empty results. A search also stops after a limited number of result pages, so a large city has to be split into smaller areas, map boxes or price bands to reach every listing, as in the script above. And because the layout changes often, check your parser against a sample every week. With your own scraper, spread searches over rotating residential IPs and keep one sticky session, from 30 s to 36 h, for the steps of one search. Error codes explained: errors.

Use cases

What teams use Airbnb data for

  • Revenue management what similar listings charge for the same nights, so hosts and managers can set their own prices.
  • Investment research occupancy signals from calendars, nightly rates and review counts by neighborhood.
  • Market reports listing counts, prices and listing types by city and season.
  • Guest experience what reviews praise or criticize across comparable listings.

Booking, holding dates or contacting hosts through a scraper is not data collection; fraud and fake accounts are forbidden under ProxyField's acceptable use policy. Proxies for other travel work: travel proxies.

Do it yourself

Scrape Airbnb with Python and ProxyField proxies (works today)

The API is in development; residential proxies are on sale now. This script runs the same EXTRACT and DAYS scripts from the sections above in your own Playwright browser through a residential IP, and writes the same JSON. Playwright runs the page's scripts, which a plain HTTP request would not.

Read moreShow less
Python
import json, re
from playwright.sync_api import sync_playwright
# EXTRACT, DAYS, DATES and parse_price: as in the API scripts above

URL = f"https://www.airbnb.com/s/Lisbon--Portugal/homes?{DATES}"
BLOCK = {"image", "font", "media"}                    # cuts the traffic each page uses

with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        "server": "http://gate.proxyfield.io:7000",
        "username": "<login>-country-us-city-new_york-session-lisbon01-ttl-600",  # one New York IP for 10 min
        "password": "<password>"})
    page = browser.new_page()
    page.route("**/*", lambda r: r.abort() if r.request.resource_type in BLOCK else r.continue_())
    page.goto(URL, wait_until="domcontentloaded", timeout=90_000)
    page.wait_for_selector("[itemprop='itemListElement']")
    rows = []
    for c in page.evaluate(EXTRACT):
        m = re.search(r"/rooms/(\d+)", c.get("url") or "")
        if m:
            price, currency = parse_price(c.get("price"))
            rows.append({"id": m.group(1), "title": c.get("title"), "price": price,
                         "currency": currency, "price_text": c.get("price")})
    json.dump(rows, open("lisbon-search.json", "w"), ensure_ascii=False, indent=1)
    print(len(rows), "listings")
    browser.close()

For a whole city, call it once per map box as in the crawl function above, run page.evaluate(DAYS) on each listing page for its calendar, and open the listing with each open check-in date in its URL for the price, as listing() does. Traffic is what decides the cost on proxies: measure one run first; at an example 1 MB per page with images blocked, the 2,300 pages of a 2,000-listing city would use about 2.3 GB: a 3 GB purchase at $2.95/GB costs $8.85, and the unused traffic stays on your balance, since it never expires.

Access opens once the payment is confirmed; the gateway, credentials or allowlist are in your account. Username syntax beyond country and city: -region-<region>, -session-<id> and -ttl-<seconds> (30 to 129,600 seconds, 20 minutes by default) after the location, as in <login>-country-us-region-new_york-city-new_york-session-he9f2qga-ttl-600. Residential proxies cost $2.95/GB for 1 GB and from $1.95/GB at volume, with unlimited concurrent threads; the traffic never expires, and all purchases are final. More on browser automation: Playwright.

FAQ

Airbnb Scraper FAQ

24/7 support by live chat, including help with setup and integration.

Is there a good Airbnb scraper API that returns listing prices and availability calendars as JSON for a whole city?

ProxyField's Web Scraping API, in development (Contact sales), is designed for this at $0.002 per successful result ($2.00 per 1,000), or $0.001 when one purchase holds 10,000 results or more. One listing's priced calendar, 10 months of open and blocked nights plus prices for 8 open check-in dates in one JSON record with min, median and max, is 9 results, $0.018; a whole 2,000-listing city, split into map boxes until none is full, is 2,300 results ($4.60) for listings and calendars, or 18,300 results ($18.30 at the volume price) with every calendar priced. Until the API ships, the same scripts run in Playwright on residential proxies from 1 GB for $2.95; Airbnb's own API is only for approved partners.

How does an Airbnb scraper API work?

ProxyField's Web Scraping API is designed to take an Airbnb search or listing URL with your dates and guests, load it with JS rendering and return the page, for $2.00 per 1,000 successful results, or $1.00 from 10,000. Your code reads the listings, prices and ratings from it; you pay only for successful results.

How do I scrape Airbnb data?

Build search URLs for your area with fixed dates and guests, load them in a browser or an API that runs JavaScript, collect the listing links, then fetch each listing for its facts, reviews and calendar. Send the requests from the country whose prices you want and repeat on a schedule.

What data can I scrape from Airbnb?

Public pages show the listing title and type, price for given dates, rating and review count, guests, bedrooms and baths, amenities, house rules, approximate location, reviews, the availability calendar and the host's public profile. Messages, bookings and anything behind a login are out of scope.

Does Airbnb have an API?

Not an open one: Airbnb's API is for approved software partners that manage hosts' own listings. It does not give market data on other listings, which is why research teams read the public pages.

Can I scrape Airbnb reviews or the availability calendar?

Yes, both are on public listing pages: reviews with their text, month and host replies, and the calendar with open and blocked nights. Both load through scripts, so fetch them with JS rendering or a headless browser; a blocked night may be the host's own block, not a booking.

How much does it cost to scrape Airbnb?

On ProxyField's Web Scraping API, a 2,000-listing city with 4 date pairs is about 3,200 rendered results, $6.40 (or $3.20 inside a purchase of 10,000+); a daily price check on 1,000 listings is 30,000 results a month, $60 or $30. Your own scraper on residential proxies starts at 1 GB for $2.95.

Can Airbnb block scrapers?

Yes: Airbnb answers fast or repetitive traffic from one IP with errors, challenges or empty results, and blocks datacenter ranges quickly. Spread requests over rotating residential IPs, keep a low rate per IP and send normal browser headers.

What are the rate limits for scraping Airbnb?

Airbnb publishes no rate limit for its public pages; it slows or blocks clients that search too often from one IP. Keep several seconds between searches per IP and spread a large job across many IPs.

Do I need an account to scrape Airbnb?

No. Search results, listing pages, reviews, calendars and host profiles are visible to logged-out visitors, and a scraper should never sign in. Your trips, messages and wish lists are behind a login and out of scope.

Show 12 more questionsShow fewer questions

Can I capture Airbnb prices in different currencies and regions?

Yes: send the same search from IPs in different countries, because Airbnb shows the currency and price format of the visitor's market. ProxyField residential proxies offer targeting by country, region (state) and city, with 412M+ residential IPs in 195+ countries.

Are there limits to the number of Airbnb listings I can scrape at once?

One search stops after a limited number of result pages, so a big city never fits in one search. Split it into map boxes, neighborhoods or price bands until no search comes back full, then remove duplicates by room id.

How much bandwidth does Airbnb scraping use?

It depends on the page and on whether you load images, so measure it on a sample run before you size a job. ProxyField's dashboard shows usage in real time, and blocking images and fonts in your browser cuts the traffic a page uses.

How often should I refresh Airbnb prices?

Daily for the next few weeks of dates, where prices move most, and weekly for dates further out. Store each price with its dates, guests, currency and the time of the check, so the history stays comparable.

What is scraped Airbnb data used for?

Hosts and managers price against comparable listings, investors estimate income from nightly rates and booked nights, and analysts track supply and prices by city and season. Most of these uses need facts such as price, dates and ratings rather than people's details.

How do I scrape Airbnb with Python?

Use Playwright, because Airbnb's results load through scripts: open the search URL through a proxy, wait for the results and read the room ids and prices, as in the code on this page. Then fetch each listing for its details and save any page that does not parse.

What does Airbnb scraper JSON output look like?

With ProxyField's Web Scraping API design, the JSON is what your evaluate script returns, so you choose the fields: this page's listing() function returns one record per listing with days[] (date, open or blocked, and the price, currency and price text for each priced check-in date), the minimum stay and a summary of open, blocked and priced nights with the lowest, median and highest price. The city search adds one record per listing with its id, title and price for the search's dates; each map box, calendar or priced date is one result, $0.002 at $2.00 per 1,000.

Can I estimate Airbnb occupancy from scraped calendars?

Only roughly: a blocked night may be a booking or a date the host closed, and an open night may still be booked later. Take calendar snapshots on a schedule, such as weekly, and count nights that change from open to blocked, which is a better signal than one snapshot.

Is there an Airbnb scraper on GitHub?

Yes, several open-source Airbnb scrapers are on GitHub, mostly in Python. Many break when Airbnb changes its pages, so check the last update and run them through rotating residential IPs.

What should I do if my Airbnb scraper stops working or returns errors?

Save the page it received: an empty result or a challenge page means you are sending too fast or from a blocked IP, while a page with data that no longer parses means Airbnb changed its layout. Slow down and rotate IPs for the first, update your selectors for the second.

Are there alternatives to scraping Airbnb, such as official APIs or data providers?

Airbnb's API is only for approved partners, but the Inside Airbnb project publishes listing data for a number of cities, and short-term rental analytics firms sell market data. Scraping makes sense when you need your own areas, dates or refresh schedule.

Collect Airbnb pages with the Web Scraping API

Billed on successful results only. Contact sales for the Web Scraping API and the volume you need, or run your own scraper on residential proxies. 24/7 live chat helps with setup and integration.