# Airbnb Scraper: Listings, Occupancy Rate, Availability & Prices (`codepoetry/airbnb-scraper`) Actor

Scrape Airbnb listings, prices, reviews, ratings and availability calendars with occupancy for any city or listing URL. Get the nightly rate and stay total as numbers, six rating categories, host, amenities and photos: 99 fields per short-term rental. Calendar included; failed listings are free.

- **URL**: https://apify.com/codepoetry/airbnb-scraper.md
- **Developed by:** [CodePoetry](https://apify.com/codepoetry) (community)
- **Categories:** Travel, Real estate
- **Features:** Limited permissions
- **Stats:** 32 total users, 12 monthly users, 97.9% runs succeeded, 2 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.75 / 1,000 listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Airbnb Scraper API: Listings, Prices, Reviews & Calendar

**Airbnb listings with the price for your dates, an occupancy rate and guest reviews, in one run.**

The three most-used Airbnb listing scrapers on the Apify Store each miss at least one of
these. This one returns all three:

- **An occupancy rate for every listing**, computed from up to 12 months of its calendar.
  The others don't compute one.
- **The stay price as numbers** (`price_per_night`, `total_price`) you can sort and average.
  Two of the others return text such as "$318".
- **Guest reviews in the same run.** Two of the others sell reviews as a separate actor.

It also costs at least 25% less per listing than the most-used Airbnb scraper, on every Apify
plan: $1.50 against $2.00 per 1,000 on Starter, calendar included. Search pages and failed
listings are free. [See how it compares](#how-it-compares).

Give it a city, a region or room URLs, and export to JSON, CSV or Excel, or read the results
over the API. You need no Airbnb account and no API key.

**[Run this Actor now](https://console.apify.com/actors/6nRRg66EUZxYPllQR?addFromActorId=6nRRg66EUZxYPllQR\&fpr=use-apify)**

***

### Quick start: scrape Airbnb without an API key

1. Click **Try for free**. **Locations to search** is pre-filled with Paris, France.
2. Set **Check-in** and **Check-out** so every listing is priced for that stay.
3. Click **Start**. The default run returns 20 full listings in about 22 seconds (measured
   2 Sep 2026), for $0.06 on the Free plan.
4. Open the **Listings** tab of the dataset, or export it to JSON, CSV or Excel.

Want more? Raise **How many listings**, add cities to **Locations to search**, or turn on
**Include guest reviews**. Already know the properties? Paste room URLs into `start_urls`
instead. For a fast sweep of a whole market, set `mode` to `search`. Results appear in the
dataset while the run is still going.

#### Ready-made example tasks

Each opens a copy you can run as is or edit:

- [Airbnb prices for your travel dates](https://apify.com/codepoetry/airbnb-scraper/examples/airbnb-prices-for-travel-dates?fpr=use-apify): Paris, 5 nights, 2 adults
- [Airbnb occupancy rate for a city](https://apify.com/codepoetry/airbnb-scraper/examples/airbnb-occupancy-rate-by-city?fpr=use-apify): Lisbon, 3-month calendars
- [Airbnb competitor pricing for hosts](https://apify.com/codepoetry/airbnb-scraper/examples/airbnb-competitor-pricing-for-hosts?fpr=use-apify): comparable 2-bedroom homes in Porto
- [Airbnb reviews from listing URLs](https://apify.com/codepoetry/airbnb-scraper/examples/airbnb-reviews-by-listing-url?fpr=use-apify): up to 50 reviews per listing
- [Airbnb availability calendar, 12 months](https://apify.com/codepoetry/airbnb-scraper/examples/airbnb-availability-calendar-12-months?fpr=use-apify): a year of availability per listing
- [Fast Airbnb search results sweep](https://apify.com/codepoetry/airbnb-scraper/examples/airbnb-search-results-market-sweep?fpr=use-apify): 100 Barcelona cards in search mode
- [Airbnb host and Superhost data](https://apify.com/codepoetry/airbnb-scraper/examples/airbnb-host-and-superhost-data?fpr=use-apify): hosts of 20 London listings
- [Airbnb reviews and ratings for a city](https://apify.com/codepoetry/airbnb-scraper/examples/airbnb-reviews-and-ratings-by-city?fpr=use-apify): 15 Lisbon listings, 10 reviews each
- [Export Airbnb listings to CSV or Excel](https://apify.com/codepoetry/airbnb-scraper/examples/airbnb-listings-export-csv-excel?fpr=use-apify): 50 Rome listings, every field
- [Airbnb Paris as seen from France, in EUR](https://apify.com/codepoetry/airbnb-scraper/examples/airbnb-paris-from-france-eur?fpr=use-apify): local order, French text, euro prices

### What else you get

- **Every review once.** Reviews are paged newest first, so each comes back exactly once.
  Paging Airbnb's default order by offset returned a 373-review listing as 322 distinct
  reviews, with duplicates and gaps.
- **You pay for data you can use.** Search pages are free, failed listings are free and say
  what went wrong, and a maximum cost per run is respected.
- **All six rating categories.** Accuracy, check-in, cleanliness, communication, location
  and value, plus the share of 5 to 1 star reviews.
- **Airbnb as other countries see it.** Browse from 23 markets, in 18 languages, with prices
  in 28 currencies, each checked against Airbnb.
- **A stable shape.** A field Airbnb leaves out is `null`, never dropped, and coordinates say
  whether they are the exact spot or Airbnb's privacy circle.

#### Measured on real runs

Each figure comes from one of our own runs, on the date shown.

| What | Measured | When |
| --- | --- | --- |
| Currencies | 28, each run against Airbnb and returning that currency | 2 Sep 2026 |
| Languages | 18, each run and returned translated | 2 Sep 2026 |
| Default run | 20 full listings, 22 seconds | 2 Sep 2026 |
| Listings priced for a set stay | 20 of 20 in Paris, 5 nights in July 2027 | 20 Oct 2026 |
| Billing | 3 listings and 6 reviews delivered, 3 and 6 charged | 20 Oct 2026 |

### How it compares

| What you get | This scraper | The three most-used alternatives |
| --- | --- | --- |
| Price for your dates as numbers you can sort | Yes, nightly and total | 1 of 3; the others return text such as "$318" |
| Availability calendar | Yes, up to 12 months, in the listing price | 2 of 3 |
| Occupancy rate, computed for you | Yes | None of them |
| All six rating categories | Yes | All three |
| Share of 5 to 1 star reviews | Yes | None of them |
| Guest reviews in the same run | Yes | 1 of 3; two sell reviews as a separate actor |

Tested side by side on 10 Nov 2026: the same search in all four scrapers, 3 listings in
Porto for 2 adults, 15 to 20 March 2027.

### Who uses Airbnb data, and for what

Property managers and hosts track what comparable listings nearby charge for the same
nights, and how their occupancy compares. The price for a set stay and the availability
calendar together show what a market books at.

Real estate investors screen neighbourhoods before buying by pulling every listing in an
area with occupancy rates and nightly rates attached.

Travel and booking sites build inventory feeds, comparing Airbnb prices against their own.

Researchers and journalists study short-term rental density in cities considering
regulation, using coordinates, licence numbers and host portfolios.

Anyone doing due diligence on a host can pull their full portfolio through `start_urls` and
check ratings, response rates and review history across properties.

### What Airbnb data can you extract?

Every full-detail record carries 99 fields, in eleven groups:

| Group | Fields |
| --- | --- |
| Identity | id, url, name, title, subtitle, description, description language, SEO title, thumbnail, images |
| Location | latitude, longitude, coordinates, city, country, neighbourhood, location descriptions, and whether the coordinates are the exact spot rather than Airbnb's privacy circle |
| Capacity | person capacity, bedrooms, beds, bathrooms, room type, property type, home tier |
| Price | `price_per_night` and `total_price` as numbers, currency, original and discounted price, nights, the check-in and check-out they were quoted for, and the price label and breakdown Airbnb shows. Airbnb quotes all-in prices and no longer itemises cleaning or service fees, so neither does this |
| Ratings | guest satisfaction overall, plus accuracy, check-in, cleanliness, communication, location and value, and the share of 5 to 1 star reviews |
| Host | name, id, profile URL, photo, superhost and verified status, years hosting, response rate and time, rating average and count, highlights, about (co-hosts are a separate top-level field) |
| Amenities | the complete list by category, plus direct flags for wifi, air conditioning, heating, kitchen, parking, washer, TV, pool, dedicated workspace and pets |
| Reviews | reviewer, date, rating, review text, language, highlights and the host response, up to a limit you set |
| Availability | day by day calendar, minimum and maximum nights, and from today on: days total, days available, days blocked, occupancy rate and the next available date |
| Rules and policies | house rules, cancellation policy, check-in and check-out times, self check-in, smoking, parties, commercial photography, licence number |
| Metadata | instant book, Guest Favourite, highlights, badges, scraped_at timestamp |

Search mode returns what the result card carries: id, url, name, title, subtitle, thumbnail,
images, latitude, longitude and coordinates, nightly rate, stay total and original price as
numbers, nights, the price label and breakdown, the check_in and check_out it was quoted for,
rating, review count, Superhost, badges and the scraped_at timestamp. Room type, capacity and
everything else below the card are full-detail fields.

#### Seven views, one per question

Nobody reads 99 columns at once, so the dataset arrives in seven views. Each answers one
question:

| Tab | What it answers |
| --- | --- |
| **Listings** | The whole picture: photo, name, city, type, capacity, all three prices with the stay they were quoted for, rating, review count, Guest Favourite, Superhost, occupancy and the booking terms |
| **Availability** | The day-by-day calendar, minimum and maximum nights, days free, days blocked, occupancy rate and the next free date |
| **Ratings & reviews** | All six category scores behind the star, the rating distribution, and the reviews themselves |
| **Host** | Host and co-hosts, Superhost status, licence, whether the address is verified |
| **Location** | Coordinates and whether they are exact rather than Airbnb's privacy circle, address, neighbourhood, map link |
| **Amenities & rules** | The full amenity list by category, direct flags for the ones people filter on, house rules, cancellation terms, safety features |
| **Description & photos** | The listing's own copy, highlights, sleeping arrangements, badges and every image |

Export any tab to JSON, CSV or Excel. **All fields** shows the raw record.

### Airbnb prices for your dates

Airbnb quotes by stay, so the same listing has no single price. Pass `check_in`,
`check_out` and guest counts, and every record carries the price a guest would be shown for
those nights, plus the `check_in` and `check_out` it was quoted for. A location search
without dates prices one night about a month out. Listings fetched by `start_urls` are
priced only when you give dates.

A price label tells you what a listing asks. "$663 for 5 nights" is a string; 663 and
132.55 are numbers you can sort, filter and average. Where a stay is discounted, the
pre-discount price comes too, and `available` says whether the listing can be booked for
those dates at all. Seven of eight listings sampled in one city could not be.

Ratings work the same way. An overall 4.9 hides whether guests marked a place down on
cleanliness or on value, and six category scores tell you which.

### Airbnb occupancy rate and availability calendar

Every full listing carries its day-by-day calendar for `calendar_months` months (3 by
default, up to 12), at no extra charge. From the calendar, the scraper counts the days from
today to the end of the window and reports how many are free and how many are blocked.
`occupancy_rate` is blocked days divided by that total.

The first Porto listing in the [output example](#output-example), scraped on 20 Oct 2026, had 42 days left in its window, 11 free
and 31 blocked, so its `occupancy_rate` is 0.738. Its `next_available_date` was 4 Nov 2026.

Airbnb does not say why a day is blocked. A blocked day is either a booking or the host
closing the date, so treat the rate as an upper bound on bookings rather than a count of
them. It is most useful for comparing listings and neighbourhoods measured the same way,
or for tracking one listing over time on a schedule. Nightly rates alone tell you what a
market advertises; rates with occupancy tell you what it books.

### Output example

From a run on 20 Oct 2026: three Porto listings, 2 adults, 15 to 20 March 2027.

| id | name | person_capacity | price_per_night | total_price | rating.guest_satisfaction | number_of_reviews | occupancy_rate |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 29480483 | Porto AAA - Almada Aliados Apartment | 2 | 132.55 | 663 | 4.97 | 368 | 0.74 |
| 602831143027997558 | Almada Prime with Balcony - Heart of the City | 2 | 119.09 | 563 | 4.99 | 296 | 0.62 |
| 10097660 | Oporto's heArt (PRIVATE PARKING) | 3 | 111.02 | 556 | 4.99 | 473 | 0.40 |

The first of them as JSON, cut to the fields most people use. The **All fields** view of the
dataset shows the whole record.

```json
{
  "id": "29480483",
  "url": "https://www.airbnb.com/rooms/29480483",
  "name": "Porto  AAA - Almada Aliados Apartment",
  "property_type": "Entire rental unit",
  "person_capacity": 2,
  "city": "Porto",
  "check_in": "2027-03-15",
  "check_out": "2027-03-20",
  "nights": 5,
  "price_per_night": 132.55,
  "total_price": 663,
  "currency": "USD",
  "rating": {
    "guest_satisfaction": 4.97,
    "accuracy": 4.99,
    "checkin": 4.98,
    "cleanliness": 4.98,
    "communication": 4.97,
    "location": 4.98,
    "value": 4.95
  },
  "is_guest_favorite": true,
  "host": { "name": "Teresa", "is_super_host": true, "rating_count": 1322 },
  "amenities_count": 42,
  "occupancy_rate": 0.7380952380952381,
  "next_available_date": "2026-11-04",
  "reviews": [
    { "reviewer_name": "Denise", "rating": 5, "text": "We had a wonderful stay...", "language": "en" }
  ],
  "error": null
}
```

### How much does the Airbnb scraper cost?

You pay only for the events below. Compute, proxies and storage are covered by the price.
Prices depend on your Apify plan:

| Event | Free plan | Starter | Scale | Business and above |
| --- | --- | --- | --- | --- |
| Listing, full detail with calendar | $3.00 / 1,000 | $1.50 / 1,000 | $1.10 / 1,000 | $0.75 / 1,000 |
| Search result, card only | $0.50 / 1,000 | $0.50 / 1,000 | $0.50 / 1,000 | $0.50 / 1,000 |
| Review | $0.30 / 1,000 | $0.30 / 1,000 | $0.30 / 1,000 | $0.30 / 1,000 |
| Run start | $0.0001 | $0.0001 | $0.0001 | $0.0001 |
| Search page walked | free | free | free | free |
| Failed listing | free | free | free | free |

The Free plan listing price is $3.00 per 1,000 from 22 October 2026, and $2.00 before that.
The Pricing tab of this page always shows the current prices.

Some examples:

- 1,000 full listings with a 3-month calendar, on Starter: $1.50.
- The same 1,000 listings with 20 reviews each: $1.50 + 20,000 × $0.0003 = $7.50.
- 5,000 search cards across a country's cities in search mode: $2.50.

Reviews are the one line that depends on the properties rather than on how many you asked
for. A busy listing carries a couple of hundred, so pulling all of them costs far more than
the listing itself; `max_reviews_per_listing` caps it at 50 by default. If you are budgeting
a run, this is the number to look at twice. Set a maximum cost per run in the run options
and the scraper stops before it would bill past it.

Finding listings is free. Paginating a city of 240 listings takes about 14 search pages
and costs nothing. A removed property, or one Airbnb refuses to serve, still comes back as
a record carrying the id, the url and what happened, and that record is not billed.

### Input

#### Search one city or many

Each location becomes its own search and all of them merge into a single dataset. Covering
ten cities takes one run.

```json
{
  "location_queries": ["Porto, Portugal", "Lisbon, Portugal", "Braga, Portugal"],
  "mode": "full",
  "max_listings": 500
}
```

#### Set dates, guests and prices

Guest counts change both the price and which listings appear.

```json
{
  "location_queries": ["Barcelona, Spain"],
  "check_in": "2027-03-15",
  "check_out": "2027-03-20",
  "adults": 2,
  "children": 1,
  "price_min": 80,
  "price_max": 300
}
```

#### Scrape Airbnb from another country

Airbnb ranks results and shows prices and availability differently depending on where you
browse from. A Paris search seen from France is not the same result set as the one you get
from a US connection: different ordering, different totals, sometimes different listings.

`proxy_country` picks the country to browse from, and the scraper reads that country's own
Airbnb site. 23 markets are supported:

```json
{
  "location_queries": ["Paris, France"],
  "proxy_country": "FR"
}
```

| | |
| --- | --- |
| **Europe** | United Kingdom, France, Germany, Spain, Italy, Portugal, Netherlands, Poland, Sweden, Denmark, Austria, Ireland, Greece, Turkey |
| **Americas** | United States, Canada, Brazil, Mexico |
| **Asia-Pacific** | Japan, South Korea, India, Singapore, Australia |

Leave it empty and the market follows the language you chose. Set both when you want them
to differ, for example an English-speaking buyer researching the French market. China and
Russia are not offered: Airbnb withdrew from both, and a search from either returns
nothing. Russian and Chinese are still offered as languages, and left to follow the
language they browse the United States.

#### Scrape specific listings

Skip search entirely when you already know the properties. `start_urls` accepts room URLs
and bare listing ids in the same list. Add `check_in` and `check_out` to price them.

```json
{
  "start_urls": [
    "https://www.airbnb.com/rooms/29480483",
    "https://www.airbnb.com/rooms/602831143027997558",
    "10097660"
  ],
  "check_in": "2027-03-15",
  "check_out": "2027-03-20",
  "mode": "full"
}
```

#### Filter what comes back

```json
{
  "location_queries": ["Lisbon, Portugal"],
  "room_types": ["Entire home/apt"],
  "property_types": ["Apartment", "Loft"],
  "min_bedrooms": 2,
  "min_bathrooms": 1,
  "min_rating": 4.8
}
```

#### Scrape Airbnb reviews and the availability calendar

The calendar comes with every full listing. Reviews are opt-in and billed per review. Both
arrive nested inside the listing record, so a property and its history stay together.

```json
{
  "location_queries": ["Madrid, Spain"],
  "include_reviews": true,
  "max_reviews_per_listing": 20,
  "calendar_months": 3
}
```

Set `max_reviews_per_listing` to 0 to take every review a listing has.

#### All input options

| Option | Type | What it does |
| --- | --- | --- |
| `location_queries` | array | Locations to search. Each becomes its own search, merged into one dataset. |
| `start_urls` | array | Room URLs or bare listing ids to fetch directly, skipping search. Give this or `location_queries`, not both. |
| `mode` | string | `full` opens every property page. `search` reads results pages only. |
| `check_in`, `check_out` | string | Stay dates, so prices reflect a real booking. |
| `adults`, `children`, `infants`, `pets` | integer | Guest counts. These change price and availability. |
| `price_min`, `price_max` | integer | Nightly price bounds. |
| `min_beds`, `min_bedrooms`, `min_bathrooms` | integer | Size filters. |
| `room_types` | array | Entire home/apt, private room, shared room, hotel room. |
| `property_types` | array | Keep only listings matching these property types. |
| `min_rating` | number | Drop listings rated below this. |
| `max_pages` | integer | Search pages to walk per location. Usually leave empty; `max_listings` already bounds the run. |
| `max_listings` | integer | How many listings to return. Defaults to 20; 0 takes every listing found. |
| `include_reviews` | boolean | Fetch guest reviews. Off by default; billed per review. |
| `max_reviews_per_listing` | integer | Reviews per property, at most. Defaults to 50; 0 fetches every one. |
| `calendar_months` | integer | Months of availability to pull, from today, up to 12. 0 skips the calendar. |
| `calendar_start_month`, `calendar_start_year` | integer | Start the calendar somewhere other than today. Defaults to the current month and year. |
| `currency` | string | Prices converted to this. 28 options, each checked against Airbnb. |
| `locale` | string | Language for review dates, house rules and cancellation terms. 18 options. |
| `proxy_country` | string | Country to browse Airbnb from. 23 markets; empty follows `locale`. |

### Use it from code

Get your API token from the Apify Console under **Settings → Integrations**, and treat it like
a password.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("codepoetry/airbnb-scraper").call(
    run_input={
        "location_queries": ["Lisbon, Portugal"],
        "check_in": "2027-03-15",
        "check_out": "2027-03-20",
        "adults": 2,
        "max_listings": 50,
    }
)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item.get("error"):
        continue
    print(item["name"], item["price_per_night"], item["occupancy_rate"])
```

#### JavaScript / Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('codepoetry/airbnb-scraper').call({
    location_queries: ['Lisbon, Portugal'],
    check_in: '2027-03-15',
    check_out: '2027-03-20',
    adults: 2,
    max_listings: 50,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
    if (item.error) continue;
    console.log(item.name, item.price_per_night, item.occupancy_rate);
}
```

n8n, Make, Zapier and plain `curl` work too, and AI agents can call it as a tool through
[Apify's MCP server](https://docs.apify.com/platform/integrations/mcp?fpr=use-apify). To run it on a
schedule or get a webhook when a run finishes, use the **Schedules** and **Integrations**
tabs on this page.

#### API and schema links

- [Python API](https://apify.com/codepoetry/airbnb-scraper/api/python?fpr=use-apify)
- [JavaScript API](https://apify.com/codepoetry/airbnb-scraper/api/javascript?fpr=use-apify)
- [HTTP API](https://apify.com/codepoetry/airbnb-scraper/api?fpr=use-apify)
- [MCP API](https://apify.com/codepoetry/airbnb-scraper/api/mcp?fpr=use-apify)
- [Input schema](https://apify.com/codepoetry/airbnb-scraper/input-schema?fpr=use-apify)
- [Output schema](https://apify.com/codepoetry/airbnb-scraper/output-schema?fpr=use-apify)

### How the Airbnb scraper handles blocks and failures

A listing that cannot be fetched still comes back as a record. It carries the
id and url you asked for, plus an `error` array explaining what happened:

```json
{
  "id": "999999999999999",
  "url": "https://www.airbnb.com/rooms/999999999999999",
  "error": [
    {
      "scope": "listing",
      "type": "listing.state_missing",
      "message": "the detail page carried no listing state, so every field below the search card is null"
    }
  ]
}
```

The run carries on and finishes normally. One removed property does not cost you the other
499, and error records are not charged.

Problems that affect the whole run, such as a location Airbnb does not recognise, appear in
the run summary.

### Is there an Airbnb API?

Not a public one. Airbnb's API is closed to approved partners, such as channel managers and
property-management software, and there is no key you can sign up for as a developer.
Searching for an Airbnb API key, or for free Airbnb API access, turns up partner
application forms.

This is the practical substitute. Give it a location and it walks Airbnb's search results,
opens each property page, and returns one record per listing through a REST API you already
have credentials for. There is no Airbnb login or partner application, and no rate limit to
negotiate.

It runs two ways. Full detail opens every property page and returns everything above.
Search mode reads only the results pages and returns the card-level fields, billed per
search result. Sweep a whole market in search mode, then go deep on the properties that
matter.

### When another tool fits better

- **Revenue and RevPAR estimates.** This returns the raw inputs, the price for a stay and
  the calendar, and leaves the modelling to you. It does not estimate revenue the way
  AirDNA or similar market-data products do.
- **Airbnb Experiences.** Only stays are scraped.
- **Host emails and phone numbers.** Airbnb does not publish them, and this does not try
  to find them.

### Frequently asked questions

**Do I need an Airbnb API key?**
No. There is no public Airbnb API to get a key for; it is restricted to approved partner
integrations. This reads the same public pages a browser does, so there is nothing to apply
for and no quota to negotiate.

**Do I need an Airbnb account?**
No. The scraper reads public listing pages and needs no login or cookies.

**How much does it cost to scrape 1,000 Airbnb listings?**
$1.50 on the Starter plan, with the price for your dates and a 3-month availability calendar
on every listing. It is $3.00 on the Free plan and $0.75 on Business. Reviews, if you turn
them on, add $0.30 per 1,000.
Failed listings and search pages are free.

**How is the occupancy rate calculated?**
Blocked days divided by the days from today to the end of the calendar window. Airbnb does
not separate bookings from days the host closed, so the rate counts both. Set
`calendar_months` for a longer window.

**Why are prices different from what I see on Airbnb?**
Usually because the stay is different. Without `check_in` and `check_out`, a search prices
one night about a month out and says which night on every record. Pass your own dates and
guest counts and the numbers match what a guest is shown.

**Can I call it from Python, n8n or an AI agent?**
Yes. It is an ordinary Apify Actor, so anything that can make an HTTP request can start a
run and read the dataset: the Python and JavaScript clients, n8n, Make, Zapier, or plain
`curl`. AI agents can call it as a tool through Apify's MCP server. See [Use it from code](#use-it-from-code)
for working examples.

**Can I get every listing in a city?**
Airbnb caps how deep its own search goes, so no scraper can return literally every property
from one query. Splitting a city into neighbourhoods or price bands and passing them as
separate `location_queries` reaches more of the inventory.

**How many reviews can I get?**
As many as a listing has, up to `max_reviews_per_listing`: 50 by default, or 0 for every
one. Reviews add time, so cap it when you are sweeping a whole market.

**What does search mode leave out?**
Everything that only exists on the property page: room type and capacity, the availability
calendar, reviews, the full amenity list, host details and house rules. Search mode gives you
the card: id, url, title, prices, rating, review count, coordinates, thumbnail and images.

**Can I run this on a schedule?**
Yes. Schedule it like any other Actor and each run writes a fresh dataset. The `scraped_at`
field on every record tells you which run it came from, so a weekly schedule on the same
listings gives you a price and occupancy history.

**Is it legal to scrape Airbnb?**
This reads only pages Airbnb shows to any visitor without logging in. Whether a given use
is allowed depends on where you are and what you do with the data, especially the personal
data in host profiles and reviews. Check with a lawyer if you are unsure.

### More actors from CodePoetry

- **[YouTube Transcript Scraper Pro](https://apify.com/codepoetry/youtube-transcript-ai-scraper?fpr=use-apify)**: transcripts from videos, playlists and channels, with AI speech-to-text when a video has no captions. JSON, text, SRT, VTT or LLM-ready.
- **[Markdown RAG Chunker](https://apify.com/codepoetry/markdown-rag-chunker?fpr=use-apify)**: split PDF, Word, HTML and Markdown documents into header-aware chunks with stable IDs and exact token counts, LangChain-ready, pay per chunk.

### Notes

This is an unofficial scraper. It is not affiliated with, authorised by, sponsored by or
endorsed by Airbnb, and "Airbnb" is used only to say which public website it reads.

Prices, availability and ratings change constantly. A record is a snapshot at `scraped_at`,
not a standing fact.

Review counts and calendar depth are the two settings that drive run length. A market sweep
with reviews off and `calendar_months` at 1 finishes far quicker than the same sweep with
every review and a year of availability.

### Start scraping

Type a city into **Locations to search**, set **Check-in** and **Check-out**, and run it, or
open one of the [example tasks](#ready-made-example-tasks).

**[Run this Actor now](https://console.apify.com/actors/6nRRg66EUZxYPllQR?addFromActorId=6nRRg66EUZxYPllQR\&fpr=use-apify)**

# Changelog

This Actor's version history is a separate document: https://apify.com/codepoetry/airbnb-scraper/changelog.md

# Actor input Schema

## `location_queries` (type: `array`):

Cities, regions or neighbourhoods, e.g. \["Porto, Portugal", "Lisbon, Portugal"]. Each one is searched and the results land in the same dataset.

## `start_urls` (type: `array`):

Scrape these listings directly and skip the search. Airbnb room URLs or bare listing ids. Use this instead of a location, not as well as: a run given both stops before scraping anything and says so.

## `max_listings` (type: `integer`):

Stop after this many. 20 by default, which is a complete run of every field on a real market in about twenty seconds. Raise it for a full sweep, or set 0 to take every listing the search finds — a big city is thousands of them, so that is a deliberate choice rather than something to inherit.

## `mode` (type: `string`):

Full opens every listing's own page for the complete record. Search only reads the result cards — much faster, but most fields come back empty. Each is billed as its own event; the Pricing tab shows both.

## `currency` (type: `string`):

Prices come back converted to this. Every option here was checked against Airbnb and returns that currency; the list is what it accepts, not every ISO code.

## `check_in` (type: `string`):

YYYY-MM-DD. Defaults to the night before check-out when only check-out is given, otherwise to about a month from the run.

## `check_out` (type: `string`):

YYYY-MM-DD, at least one night after check-in; a run given a check-out on or before check-in stops and says so. Defaults to the night after check-in.

## `adults` (type: `integer`):

Guest count sent to Airbnb's search, which affects both availability and price.

## `children` (type: `integer`):

Children in the party. Counts toward occupancy and can change the price.

## `infants` (type: `integer`):

Infants in the party. Most listings do not count them toward occupancy.

## `pets` (type: `integer`):

Pets in the party. Some listings price these separately, others refuse them.

## `price_min` (type: `integer`):

In the currency chosen above.

## `price_max` (type: `integer`):

In the currency chosen above.

## `min_beds` (type: `integer`):

Keep only listings with at least this many beds.

## `min_bedrooms` (type: `integer`):

Keep only listings with at least this many bedrooms.

## `min_bathrooms` (type: `integer`):

Keep only listings with at least this many bathrooms.

## `min_rating` (type: `number`):

Drop listings rated below this, out of 5. A brand-new listing has no rating yet and is dropped too.

## `property_types` (type: `array`):

Empty keeps all. These four are the whole set Airbnb's own filter panel offers.

## `room_types` (type: `array`):

Empty keeps all.

## `include_reviews` (type: `boolean`):

Off by default because reviews bill per review. Turn it on and you get every review a listing has, up to the cap below.

## `max_reviews_per_listing` (type: `integer`):

Only used when "Include guest reviews" is on. 50 by default; the busiest listing measured carried 537, so this is what stops one popular property dominating a run. Set 0 for every review, however many that is.

## `calendar_months` (type: `integer`):

How far forward the day-by-day calendar goes, counted from today. Three months covers the booking window most analysis uses; raise it to 12 for a full year, or set 0 to skip the calendar and make the run faster.

## `calendar_start_month` (type: `integer`):

1-12. Defaults to the month the run happens in, which is almost always what you want.

## `calendar_start_year` (type: `integer`):

Defaults to the year the run happens in. Set it together with the month above to look at a window that starts later than this month; a window starting before this month is refused, since every day in it has already happened.

## `max_pages` (type: `integer`):

Usually leave empty — "How many listings" already bounds the run, and search pages are free. About 18 listings per page.

## `locale` (type: `string`):

The language Airbnb writes review dates, house rules and cancellation terms in. It does not change which listings come back.

## `proxy_country` (type: `string`):

Which country to search Airbnb from. Airbnb ranks listings, converts prices and shows availability differently depending on where the visitor is, so a Paris search seen from France is not the same result set you get from the United States — different ordering, different totals, sometimes different listings.

Pick the country your buyers browse from. The scraper reads that country's own Airbnb site (airbnb.de for Germany, airbnb.co.uk for the UK) and returns what a visitor there actually sees.

Leave it empty and it follows the language above, so choosing German browses Germany. Set both when they should differ — an English-speaking analyst researching the German market, for example.

China and Russia are not listed: Airbnb withdrew from both in 2022 and a search from either returns nothing. So Russian and Chinese, left to follow the language, browse the United States; pick a country here to browse somewhere else.

## Actor input object example

```json
{
  "location_queries": [
    "Paris, France"
  ],
  "start_urls": [],
  "max_listings": 20,
  "mode": "full",
  "currency": "USD",
  "min_rating": 0,
  "property_types": [],
  "include_reviews": false,
  "max_reviews_per_listing": 50,
  "calendar_months": 3,
  "max_pages": 0,
  "locale": "en-US",
  "proxy_country": ""
}
```

# Actor output Schema

## `records` (type: `string`):

The scraped records, one row each.

## `summary` (type: `string`):

Run-level fields: source, the run instant, any run-level errors, and `run` — how many records were delivered, how many were rejected before delivery, how many the platform itself refused, and `failuresDatasetId`, the dataset holding the rejected records themselves.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "location_queries": [
        "Paris, France"
    ],
    "max_listings": 20,
    "mode": "full",
    "currency": "USD"
};

// Run the Actor and wait for it to finish
const run = await client.actor("codepoetry/airbnb-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "location_queries": ["Paris, France"],
    "max_listings": 20,
    "mode": "full",
    "currency": "USD",
}

# Run the Actor and wait for it to finish
run = client.actor("codepoetry/airbnb-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "location_queries": [
    "Paris, France"
  ],
  "max_listings": 20,
  "mode": "full",
  "currency": "USD"
}' |
apify call codepoetry/airbnb-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,codepoetry/airbnb-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6nRRg66EUZxYPllQR/builds/5V809rMjS6ZuwOhfN/openapi.json
