Airbnb Scraper API
An Airbnb scraper API that takes a place name and returns the stays Airbnb lists for it, one row each: title and property type, rating and review count, the nightly rate and the stay total with the pre-discount figure when there is one, beds, bedrooms and baths, Guest favorite and free-cancellation flags, the map coordinates, the first photo and the listing URL. Pass check-in and check-out dates to price a specific stay.
$0.001 per delivered stay · $2 free every month · Failed runs never billed
$ curl $QD/airbnb_stays/run \
-H "Authorization: Bearer $QD_API_KEY" \
-d '{"location": "Rome, Italy", "max_results": 18}'
{ "status": "done", "count": 18,
"results": [
{
"listing_id": "…",
"title": "…",
"property_type": "…",
"name": "…" } ],
"cost": 0.018 }
# 18 stays × $0.001 · nothing delivered, nothing charged
Try it
Airbnb stays, running now
Change the input and run it against the live collector — nothing to install, no sign-up.
Run it from your own code, on your own inputs
Same collector, same rows — $2 of free API credit every month, no card.
What an Airbnb scraper API does
A plain fetch of an Airbnb search page contains no listings at all — zero card nodes, zero room links — because the cards are rendered in the browser. What the page does ship is its hydration island, a JSON block holding every stay as a typed object, and that is what this collector reads. It is not a workaround for the missing DOM; it is the better source. Coordinates, the price breakdown and the review count are in the island and were never in the markup.
Two things about that island would corrupt a naive parser, and both are handled. It holds the listings twice — once for the results list, once for the map — so scanning it for stay objects delivers most rows twice and advances the page cursor past listings that were never read; this collector scopes itself to the results array. And Airbnb streams the page, so the island often arrives cut off mid-JSON: on nine captures of one city search every one ended inside a photo URL. A single JSON.parse fails on all of them. Each row is instead located by marker and brace-matched on its own, so complete rows are delivered and an unfinished tail row is dropped and counted in the run notes — never delivered half-filled.
Limits, in plain numbers
Everything that bounds one run of this collector. No hidden throttles.
Max per run
90 stays
Price
$0.001 / stay
Per 1,000
$1.00
Failed runs
Free zero rows, zero charge
Free every month
$2 no card
Rate limit
60 req/min on the free tier
What one stay looks like
Every delivered stay carries these fields. Nullable means the source did not publish it — the field stays empty instead of being guessed.
| Field | Type | What it holds |
|---|---|---|
rank | integer | Position in Airbnb's order for this response. Airbnb re-ranks between requests, so this is not a stable property of the listing. |
listing_id | string · nullable | Airbnb listing id — the number in the /rooms/ URL. |
title | string · nullable | Card heading as Airbnb writes it, property type then area ("Apartment in Monti"). |
property_type | string · nullable | Property type taken from the head of the title ("Apartment", "Condo", "Penthouse"). Null when the title is not of that shape. |
name | string · nullable | The host's own listing name. |
subtitle | string · nullable | Card subtitle — usually the listing name, sometimes a short description. |
rating | number · nullable | Average rating out of 5. Null on a listing with no reviews yet. |
reviews | integer · nullable | Number of reviews. |
guest_favorite | boolean | True when Airbnb badges the listing a Guest favorite. |
badges | string[] · nullable | Badge labels shown on the card, e.g. ["Guest favorite"], ["Superhost"] or ["Luxe"]. Airbnb's flexible-date chip shares the same list and is excluded — it is a date range, not a badge, and check_in/check_out already carry it. |
price_per_night | number · nullable | Nightly rate as Airbnb states it in its own price breakdown ("5 nights x $741.37"), never total ÷ nights. When a stay discount is listed as its own line, this is the rate before that discount. |
price_total | number · nullable | Price shown on the card for the whole stay, after any discount. |
price_original_total | number · nullable | Struck-through stay total on a discounted card; null when the card is not discounted. |
price_text | string · nullable | The price exactly as printed on the card, e.g. "$3,707". |
price_qualifier | string · nullable | What the price covers, in Airbnb's words: "for 5 nights" or "night". |
nights | integer · nullable | Nights the priced stay covers. |
currency | string · nullable | ISO currency of the prices, from the symbol Airbnb printed. Airbnb prices in the exit country's currency; a bare "$" is reported as USD only on a US exit and left null elsewhere rather than guessed. |
free_cancellation | boolean | True when the card carries Airbnb's free-cancellation highlight. |
beds | integer · nullable | Beds, from the card's bed line ("3 beds", "4 double beds") — not the bedroom count. |
bedrooms | integer · nullable | Bedrooms. Null on a studio, which Airbnb states in words. |
bathrooms | number · nullable | Baths, halves included (1.5). Null when Airbnb states it in words ("Half-bath"). |
bed_info | string · nullable | The card's bed and bath line verbatim, e.g. "3 bedrooms, 3 beds, 2 baths". |
check_in | string · nullable | Check-in the price covers (YYYY-MM-DD): the date you asked for, or the one Airbnb chose for this listing when you asked for none. |
check_out | string · nullable | Check-out the price covers (YYYY-MM-DD). |
latitude | number · nullable | Airbnb's approximate map point — it publishes a fuzzed location until a booking is confirmed, not the exact address. |
longitude | number · nullable | Approximate longitude, as above. |
image | string · nullable | First photo on the card. |
photo_count | integer | Photos in the card's carousel — not the listing's full gallery. |
url | string · nullable | Listing URL, composed from the listing id. |
Inputs
The whole request. Anything you leave out falls back to the default shown in the catalog.
| Input | Type | Required | What it does |
|---|---|---|---|
location | string | yes | City, region or neighbourhood, e.g. "Rome", "Rome, Italy" or "Brooklyn, New York". Resolved by Airbnb's own search, exactly as typing it into the site would. |
checkin | string | no | Arrival date as YYYY-MM-DD. Must be given together with checkout; omit both to let Airbnb price each listing for its own suggested stay. |
checkout | string | no | Departure date as YYYY-MM-DD. Must be after checkin. |
adults | integer | no | Number of adult guests (1–16). Omit for Airbnb's default of one. |
country | string | no | ISO 3166-1 alpha-2 code — proxy exit geo and Google locale (gl). Omit for the default pool. |
max_results | integer | no | How many stays to deliver at most (1–90). You pay only for delivered stays. |
Pricing
Airbnb Scraper API pricing
$0.001 per delivered stay. A run that delivers nothing costs nothing: blocked pages, challenges and retries are on us, and the $2 monthly allowance covers about 2,000 stays before you spend anything.
Pay as you go
- $2 free credit / month
- 60 requests / min
- List unit prices
Starter
- $15 free credit / month
- 300 requests / min
- 10% off unit prices
Growth
- $50 free credit / month
- 600 requests / min
- 20% off unit prices
Scale
- $250 free credit / month
- 1,200 requests / min
- 30% off unit prices
Same wallet, same key and same $2 monthly allowance as every other Data API. Prices are launch pricing read live from the billing config — GET /v1/scraper/collectors returns the price your key actually pays.
Integration
One POST, typed rows
Base URL https://api.quanticdata.io/v1, Bearer auth, the same key as every other Data API. Endpoint: POST /v1/.
curl -X POST https://api.quanticdata.io/v1/scraper/collectors/airbnb_stays/run \
-H "Authorization: Bearer $QD_API_KEY" \
-H "Content-Type: application/json" \
-d '{"location":"Rome, Italy","max_results":18}'
What people build with the Airbnb scraper API
Three shapes of work this endpoint was designed around.
Short-term rental pricing
Price a city for a weekend a month out and again a week out: price_per_night, price_total and the pre-discount total on every row, with the coordinates to bucket by neighbourhood.
Supply mapping
Count entire homes against private rooms per area, read bedrooms and beds, and see which listings carry the Guest favorite badge — the inputs a rental-investment or tourism study actually needs.
Competitor set for a host
Pull the stays a guest sees around a given listing, with rating and review count, and re-run weekly to watch rates move.
Airbnb Scraper API versus rolling your own
The differences that actually cost time when you build this in-house.
| DIY scraper | This collector | |
|---|---|---|
| Where the rows come from | The DOM — which is empty without a browser | The page’s own hydration island, with coordinates and price breakdown |
| Duplicate listings | Delivered twice from the list and the map copies | Read from the results array only |
| Truncated pages | JSON.parse throws, zero rows | Rows brace-matched one by one; the cut row is counted, not delivered |
| Dates | Whatever the page defaults to | Your check-in and check-out, or per-listing defaults reported on the row |
What people search for
Live autocomplete demand around Airbnb stays, pulled with our own Keyword ideas collector.
Sources and standards
The platform documentation and standards this collector is built against — check any claim on this page against the primary source:
Does it need a browser?
No. The listings are in the JSON island Airbnb embeds in the server response, which a plain TLS fetch receives. The rendered cards would need a browser and would carry less: no coordinates and no price breakdown.
Why are some prices “per listing’s own dates”?
When you leave checkin and checkout out, Airbnb prices each listing for a stay of its own choosing, and the row reports those dates in check_in and check_out. Pass your dates to price one specific stay across all rows.
What does “an unclosed tail row was dropped” in the notes mean?
Airbnb streams the page and sometimes cuts the JSON before the last listing is complete. That row cannot be delivered accurately, so it is dropped and counted. The page cursor advances by rows actually read, so nothing is skipped on the next page.
Can I get reviews or host details?
Not from this collector: it reads the search results, which state rating and review count but not the reviews themselves. Host and review data live on the listing page, which is a different surface.
Is there a free Airbnb scraper API?
Every account gets $2 of credit every month with no card, which is about 2,000 delivered stays on this endpoint at $0.001 each. It renews monthly, and a run that delivers nothing is never billed — so a failed or blocked attempt does not eat the allowance.
How much does one run cost?
Multiply the rows you actually receive by $0.001. A run capped at 90 stays — the maximum for this collector — costs $0.09 if every row comes back, and less when the source has fewer. Volume tiers take up to 30% off, and GET /v1/scraper/collectors returns the price your key actually pays.
Run the Airbnb scraper API now
$2 of free credit every month, no card. Your key returns its own prices from GET /v1/scraper/collectors.