# Airbnb Listings Scraper (`superslowsloth/airbnb-listings-scraper`) Actor

Scrape Airbnb stays for any destination and dates - total price, discount, rating, review count, room and bed counts, coordinates and photos, in the currency you ask for.

- **URL**: https://apify.com/superslowsloth/airbnb-listings-scraper.md
- **Developed by:** [Superslow Sloth](https://apify.com/superslowsloth) (community)
- **Categories:** Travel, Real estate, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.05 / 1,000 listing scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Airbnb Listings Scraper

Returns Airbnb stays for any destination and any dates: what the whole stay
costs, what it cost before the discount, the rating and how many reviews it is
built on, the room and bed counts, the coordinates, the badges and every photo
on the card.

Search several destinations in one run. Set the dates, the party size and the
currency, and every row carries them, so a price in this dataset can be read
without going back to the run's input.

### A price is a price *for something*

Every figure here is what Airbnb quoted for the dates, guest count and currency
this run asked for. That is why `check_in`, `check_out`, `nights`, `adults`,
`children`, `infants`, `pets` and `currency` sit on the row itself rather than
in a run summary - a total with no stay attached to it is not a number anyone
can act on.

Two rules follow, and both are enforced rather than documented and hoped for:

- **Dates come in pairs.** Airbnb silently ignores a lone check-in and prices
  an undated stay instead. A run that asked for five nights and got undated
  prices would look completely normal and be wrong in every row, so a single
  date fails the run at the boundary.
- **Set the currency.** Left empty, Airbnb picks one from the exit address the
  run happens to use, and that is not stable between runs. Setting it is what
  makes two runs comparable.

### Every stay is delivered and charged exactly once

Airbnb re-ranks its results between requests, so the same listing genuinely
appears on more than one page - 4 of 18 listing ids were shared between page 1
and page 2 of a single search when this was measured on 2026-09-12. A stay also
legitimately matches more than one of your destinations.

De-duplication is global across the whole run, and it happens *before* the
charge. You are never billed twice for one stay.

### How deep a search goes

A page carries about 18 stays, and Airbnb offers roughly 15 pages for a
search - about 270 stays per destination, which is the site's own ceiling
rather than a setting. More destinations is usually better than a deeper walk
on one.

### Output fields

| Field | Notes |
|---|---|
| `id` | Airbnb's room id, the one in `airbnb.com/rooms/<id>`. |
| `url` | The listing on Airbnb. |
| `title` | Airbnb's own room-type-and-area heading, e.g. `Rental unit in Nakagyo-ku`. |
| `name` | The host's own name for the place. A different string from `title`. |
| `latitude`, `longitude` | Airbnb's published coordinates for the stay. |
| `rating` | Average out of 5. Null on a listing with no reviews yet. |
| `reviews_count` | How many reviews that average is built on. |
| `price_total` | Total for the whole stay, in `currency`, as Airbnb quoted it. |
| `price_original` | The struck-through total, on a discounted listing only. |
| `price_display`, `price_qualifier` | Exactly what Airbnb printed, and `for 5 nights` / `per night`. |
| `currency` | Three-letter code the quote is in. |
| `nights`, `check_in`, `check_out` | The stay the price is for. |
| `adults`, `children`, `infants`, `pets` | The party the price is for. |
| `room_facts` | Airbnb's own card text, e.g. `["1 bedroom", "2 single beds", "2 baths"]`. |
| `badges` | Labels on the card, e.g. `["Guest favorite"]`, `["Superhost"]`. |
| `image_urls` | Photos, in the order Airbnb shows them. |
| `search_location`, `search_rank` | Which of your searches produced this row, and where it sat on the page that produced it. |

### What this source does not give

Stated rather than guessed. A missing value is always `null`, never `0`,
because a zero reads as a measurement that was taken.

- **No rating on a new listing.** A stay with no reviews carries `rating: null`
  and `reviews_count: null`, never `0` - a zero would drag any average computed
  over the dataset downwards and read as "rated badly".
- **Room counts are text, not numbers.** `room_facts` is kept exactly as
  Airbnb prints it, because a card reading `4 apartments available` is a real
  value that no bedroom count describes. Inventing `bedrooms: 0` for it would
  be a lie about the listing.
- **Taxes and fees are not broken out.** `price_total` is the figure Airbnb
  shows on the search card for the stay; the final checkout total can differ
  once Airbnb applies taxes for your own account.
- **`price_original` null means no discount was shown**, not that the host has
  never discounted.
- **No host name, no amenity list, no availability calendar, no reviews.**
  Those live on the listing page, not in search results, and this actor reads
  the search.
- **`search_rank` is not a stable ranking.** Airbnb re-ranks between requests;
  it is where the listing sat on the page that produced this row.

# Actor input Schema

## `locations` (type: `array`):

Where to search, one per line, exactly as you would type it into Airbnb: "Kyoto, Japan", "Lisbon", "Big Sur, California". Each destination is searched separately and the results are merged, with any stay that matches more than one delivered and charged only once.

## `checkIn` (type: `string`):

First night, as YYYY-MM-DD. Must be given together with the check-out date: Airbnb quietly ignores a lone date and prices an undated stay instead, which would fill the price column with numbers for nobody's trip. Leave both empty to read Airbnb's undated prices.

## `checkOut` (type: `string`):

Departure day, as YYYY-MM-DD. Must be after the check-in date, and must be given together with it.

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

Guest count Airbnb should price for. It changes both the prices and which listings appear at all, so it is part of the measurement.

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

Children aged 2-12, priced as guests by many hosts.

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

Children under 2. They do not usually count towards the guest total but do filter out listings that refuse them.

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

Pets travelling with you. Filters out listings that do not allow them, and some hosts charge for them.

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

Three-letter code Airbnb should quote in, e.g. "USD", "EUR", "JPY". Leave empty to take whatever Airbnb picks for the exit address the run uses - which is not stable between runs, so setting this is what makes two runs comparable.

## `minPrice` (type: `integer`):

Cheapest nightly rate to include, in the currency above. Airbnb applies this to the nightly rate, while the price on each row is the total for the stay.

## `maxPrice` (type: `integer`):

Dearest nightly rate to include, in the currency above.

## `roomTypes` (type: `array`):

Restrict to certain kinds of stay, using Airbnb's own names: "Entire home/apt", "Private room", "Shared room", "Hotel room". Leave empty for every type.

## `maxItems` (type: `integer`):

Budget for the whole run, across every destination, not per destination. Airbnb repeats listings between pages as it re-ranks, and those repeats are delivered and charged once.

## `maxPages` (type: `integer`):

How deep to walk one destination. A page carries about 18 stays and Airbnb offers roughly 15 pages for a search, so about 270 stays is the site's own ceiling for a single destination whatever is set here. More destinations is usually better than a deeper walk on one.

## `proxyConfiguration` (type: `object`):

Optional. Airbnb answered a plain datacenter address on 2026-09-12 with no proxy at all. It does refuse an address that pages quickly, serving a human-verification page with HTTP 200, and a proxy is what gives the scraper a fresh address to retry on when that happens.

## Actor input object example

```json
{
  "locations": [
    "Kyoto, Japan"
  ],
  "adults": 2,
  "children": 0,
  "infants": 0,
  "pets": 0,
  "currency": "USD",
  "maxItems": 100,
  "maxPages": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `listings` (type: `string`):

No description

# 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 = {
    "locations": [
        "Kyoto, Japan"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/airbnb-listings-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 = {
    "locations": ["Kyoto, Japan"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/airbnb-listings-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 '{
  "locations": [
    "Kyoto, Japan"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call superslowsloth/airbnb-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,superslowsloth/airbnb-listings-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/Cmr2RsPFxXkV72ivU/builds/KPa2CkqVHLqn2zGib/openapi.json
