Airbnb Scraper: Public Airbnb Listings via API
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.
Through the sales team on our 24/7 live chat
| Fetch | Entry | Volume, from |
|---|---|---|
| HTTP | $0.50 | $0.20 |
| JS rendering | $2.00 | $1.00 |
Billed on successful results only.
At a glance (API design of 2026-10-27, in development; API documentation):
| Web Scraping API on Airbnb | |
|---|---|
| Status | in 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 calendar | 1 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 search | one rendered map box per result; boxes that come back full are split, listings deduplicated by room id |
| A 2,000-listing city | listings 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) |
| Output | one JSON record per listing: days[] with blocked and, where priced, price, plus a summary (open, blocked, min, median, max) |
| Billing | successful results only; no subscription; paid from the crypto balance, which never expires |
| Scale | 20 concurrent requests; batches of up to 1,000 requests with a signed callback; results kept 48 hours |
| Exit country | any of the pool's 195+ countries (country) |
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):
{"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
| Field | Where it comes from | Example |
|---|---|---|
id | the room id in /rooms/<id> | "<room id 1>" |
days[].date, days[].blocked | the listing's calendar cells, up to 10 months in 1 result | "2026-12-12", true |
days[].price, currency, price_text | the listing page with that check-in and nights later as check-out, 1 result per date; only open dates are priced | 214, "€", "€214" |
min_nights | the minimum-stay note, where the page shows one | 2 or null |
summary | counted by your script: open, blocked and priced nights; lowest, median and highest price | see above |
country, adults, nights, checked_at | your 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:
[
{"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.
-
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. -
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.
-
Extract in the browser
Each search is one rendered request with an
evaluateaction that returns the cards as JSON (room id, title, price text). -
Deduplicate by room id
Boxes overlap at their edges; the room id in
/rooms/<id>is the key. -
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.
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
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 type | Example URL | What the public page shows |
|---|---|---|
| Search results | airbnb.com/s/<place>/homes?checkin=…&checkout=…&adults=2 | Listing title, type, rating, review count, price for the dates, a link to each listing |
| Listing page | airbnb.com/rooms/<id> | Description, guests, bedrooms, beds and baths, amenities, house rules, approximate location, host name, rating by category |
| Reviews | on the listing page | Review text, month, reviewer first name, host replies |
| Availability | the listing's calendar | Open and blocked nights, minimum stay |
| Host profile | airbnb.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 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.
# 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):
{
"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>"
}| Choice | Price per 1,000 successful results | Use it for |
|---|---|---|
| JS rendering | $2.00, or $1.00 from 10,000 results | Search results, prices for your dates, the calendar |
| Plain HTTP | $0.50, or $0.20 from 10,000 results | Listing facts that ship in the page's HTML, such as the title and description |
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 | Searches | Listing results | Results | Cost bought on its own |
|---|---|---|---|---|
| One listing, calendar + 8 priced check-in dates | – | 9 | 9 | $0.018 at $2.00 |
| A 2,000-listing city, 1 date pair, every calendar | 300 | 2,000 | 2,300 | $4.60 at $2.00 |
| The same city, 4 date pairs, once | 1,200 | 2,000 | 3,200 | $6.40 at $2.00 |
| The same city, 4 date pairs, weekly (4 runs a month) | 4,800 | 8,000 | 12,800 | $12.80 at $1.00 |
| The same city, every calendar priced for 8 open check-in dates | 300 | 18,000 | 18,300 | $18.30 at $1.00 |
| 1,000 competing listings, tonight's price, daily for 30 days | – | 30,000 | 30,000 | $30 at $1.00 |
| City size | Map boxes | Listings and calendars | Cost on its own | With 8 priced dates per listing | Cost on its own |
|---|---|---|---|---|---|
| 500 listings | 75 | 575 | $1.15 at $2.00 | 4,575 | $9.15 at $2.00 |
| 2,000 listings | 300 | 2,300 | $4.60 at $2.00 | 18,300 | $18.30 at $1.00 |
| 8,000 listings | 1,200 | 9,200 | $18.40 at $2.00 | 73,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
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.
| Item | Airbnb partner API | Web Scraping API |
|---|---|---|
| Who can use it | Approved software partners | ProxyField customers |
| Data | The listings a host or manager runs | Public search, listing, review and calendar pages |
| Partner approval | Airbnb's partner program | Not needed; Airbnb's terms still apply (see below) |
| Cost | Set by the program | $2.00 per 1,000 successful rendered pages, from $1.00 |
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.
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.
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.
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
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.
Is it legal to scrape Airbnb?
Airbnb's terms forbid scraping and other automated access, so collecting its pages breaches its terms, separate from whether it breaks a law. Prices, availability and listing facts are facts; listing photos and descriptions can be protected by copyright, and host and reviewer names are personal data under GDPR in the EU and UK. Collect the facts you need, keep personal data out, and read Is It Legal to Scrape eBay, Walmart, Zillow and Other Marketplaces? and Is Web Scraping Legal? US, EU and UK Rules (2026).
ProxyField's acceptable use policy allows collecting public web data and market research, and forbids accessing data behind logins you are not entitled to. ProxyField's rule for every site: public pages only, and follow the site's terms. This is not legal advice.
More scrapers
- Flight and hotel scraper Booking.com, Skyscanner, Kayak and other travel sites on the same API.
- Expedia scraper hotel prices, reviews and rankings.
- Travel review scraper hotel prices, reviews and rankings.
- Hotel price scraper room rates across booking sites.
- Web Scraping API any URL, plain HTTP or with JS rendering, from $0.20 per 1,000 successful results.
- All scraper APIs
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
How do I handle JavaScript when scraping Airbnb search?
Use a headless browser such as Playwright, or a scraping API with JS rendering, because Airbnb loads search results and prices with scripts. Wait until the listing cards have loaded before you read them, then collect the room ids from the links.
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.
Related pages
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.