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

Scrape Airbnb listings and return structured data including listing names, nightly rates, stay totals, ratings, bedroom and bathroom details, badges, coordinates and photos. Add guest and date filters, search locations or map areas, and optionally retrieve public host details from listing pages.

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

## Pricing

from $2.98 / 1,000 results

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 Listings Scraper

**Returns:** one row per Airbnb listing with name, title, pricePerNight, totalPrice, rating, reviewCount, bedrooms, hostName, latitude, longitude and photos.
**Input:** `{"locations": ["Lisbon, Portugal"], "adults": 2, "maxItems": 50}`
**Best for:** short-term rental market research, competitor price monitoring, travel and investment lead lists.

```json
{
  "id": "32422325",
  "sourceUrl": "https://www.airbnb.com/rooms/32422325",
  "name": "Brand new apartment right in the heart of Alfama.",
  "title": "Apartment in Santa Maria Maior",
  "pricePerNight": 124.95,
  "rating": 4.82,
  "reviewCount": 478,
  "hostName": "BB Lisbon"
}
```

### What does Airbnb Listings Scraper do?

Airbnb Listings Scraper is an Airbnb scraper and unofficial Airbnb API for search results. You give it one or more places (for example "Lisbon, Portugal" or "Austin, TX"), optional check-in and check-out dates, the number of guests and a price range. It returns the listings Airbnb shows for that search as clean, structured rows that you can export to JSON, CSV, Excel or HTML, or read through the Apify API.

For every listing you get the host's listing name, the card title (property type and area), the nightly rate, the stay total, any strikethrough original price, the average rating and review count, bedrooms, beds and bathrooms, the host type, coordinates and a list of photo URLs. With host details switched on, the scraper also opens each listing page to add the public host name, host id, Superhost and verified flags, guest capacity, room type and the six rating sub-scores.

You can search by place name, paste full Airbnb search URLs (including map-area URLs with bounding-box coordinates), or paste a single listing URL. The scraper works without an Airbnb account and without logging in. It only reads public pages that anyone can open in a browser.

This tool is an independent project. It is not affiliated with, endorsed by or connected to Airbnb.

### What data can you get?

Each dataset row describes one listing. Fields that Airbnb does not show for a listing are returned as `null`.

| Field | Type | Description |
|---|---|---|
| `id` | string | Airbnb numeric listing id, unique within a run |
| `sourceUrl` | string | Link to the listing page |
| `name` | string | Listing name chosen by the host |
| `title` | string | Card title, property type and area |
| `pricePerNight` | number | Nightly rate in the chosen currency |
| `totalPrice` | number | Stay total for the nights shown |
| `originalTotalPrice` | number | Total before discount, when Airbnb shows a strikethrough price |
| `nights` | integer | Number of nights the price is quoted for |
| `currency` | string | Currency code of all prices |
| `priceLabel` | string | Raw price text from the card |
| `rating` | number | Average guest rating out of 5 |
| `reviewCount` | integer | Number of guest reviews |
| `bedrooms` | integer | Bedrooms, 0 for studios |
| `beds` | integer | Number of beds |
| `bathrooms` | number | Bathrooms, 0.5 for a half bath |
| `bathroomLabel` | string | Raw bathroom text |
| `hostType` | string | Business host or Individual host |
| `hostName` | string | Public host name (host details on) |
| `hostId` | string | Airbnb host id (host details on) |
| `hostIsSuperhost` | boolean | Superhost flag (host details on) |
| `hostIsVerified` | boolean | Verified host flag (host details on) |
| `hostPhoto` | string | Host profile picture URL (host details on) |
| `personCapacity` | integer | Maximum guests (host details on) |
| `roomType` | string | Room type such as Entire home/apt (host details on) |
| `description` | string | Full listing description as plain text (host details on) |
| `amenities` | array | Amenities the listing offers, such as Wifi or Kitchen (host details on) |
| `checkInTime` | string | House-rule check-in window (host details on) |
| `checkOutTime` | string | House-rule check-out time (host details on) |
| `subRatings` | object | Accuracy, checkin, cleanliness, communication, location and value scores (host details on) |
| `badges` | array | Card badges such as Guest favorite |
| `latitude` | number | Approximate latitude of the listing pin |
| `longitude` | number | Approximate longitude of the listing pin |
| `photos` | array | Up to 8 listing photo URLs |
| `thumbnail` | string | First photo URL |
| `searchLocation` | string | The location or URL that produced the row |
| `position` | integer | Rank of the listing within its search |
| `checkIn` | string | Requested check-in date, null when Airbnb default dates were used |
| `checkOut` | string | Requested check-out date, null when Airbnb default dates were used |
| `scrapedAt` | string | ISO timestamp of extraction |

Some notes on how the values behave:

- Prices depend on the dates, currency and number of guests you choose. When you give no dates, Airbnb quotes its own default stay, and `nights` tells you how many nights that is.
- `pricePerNight` is the nightly rate Airbnb shows in the price breakdown. Taxes and fees are part of `totalPrice` where Airbnb includes them.
- Coordinates are the obfuscated pin Airbnb publishes, accurate to roughly a hundred metres, not an exact address.
- Hotels and some room types have no bedroom line on the card, so `bedrooms` can be null.
- New listings without reviews have a null `rating`.

### How to use

1. Open the Actor in Apify Console and go to the Input tab.
2. Enter one or more places in **Locations**, for example `Lisbon, Portugal`. You can add several; results are merged and de-duplicated by listing id.
3. Optionally set check-in and check-out dates, adults, children, infants and pets. Dates must be in the future and use the format YYYY-MM-DD.
4. Optionally set a minimum and maximum nightly price and a currency.
5. Choose **Max listings**. The limit counts all locations together.
6. Leave **Include host details** on if you need host names and sub-ratings. Switch it off for a faster run that makes one request per page of 18 listings instead of one per listing.
7. Click Start. Results appear in the Output tab while the run is going.

Airbnb returns at most 270 listings per search (15 result pages of 18). For a large city, split the search into neighbourhoods ("Alfama, Lisbon") or use map-area URLs from the Airbnb website to cover the city in pieces. Each piece can return its own 270 listings.

If the place name is not recognised, Airbnb would normally show unrelated listings from around the world. The scraper detects this, skips that location, logs a warning and returns nothing for it, instead of filling your dataset with the wrong places. The run still ends successfully and the status message names the location that was not found.

### Input

| Field | Type | Description |
|---|---|---|
| `locations` | array of strings | Places to search, for example `Lisbon, Portugal` |
| `startUrls` | array | Airbnb search URLs or single listing URLs |
| `checkIn` | string | Check-in date, YYYY-MM-DD |
| `checkOut` | string | Check-out date, YYYY-MM-DD, after check-in |
| `adults` | integer | Adults, 1-16, default 2 |
| `children` | integer | Children, 0-16, default 0 |
| `infants` | integer | Infants, 0-5, default 0 |
| `pets` | integer | Pets, 0-5, default 0 |
| `minPrice` | integer | Minimum nightly price in the chosen currency |
| `maxPrice` | integer | Maximum nightly price in the chosen currency |
| `currency` | string | USD, EUR, GBP, CAD, AUD, JPY, CHF, MXN, BRL or INR |
| `maxItems` | integer | Maximum listings in total, 1-1000, default 50 |
| `includeHostDetails` | boolean | Open each listing page for host fields, default true |
| `proxyConfiguration` | object | Apify Proxy settings |

Example input:

```json
{
  "locations": ["Lisbon, Portugal", "Porto, Portugal"],
  "checkIn": "2027-03-12",
  "checkOut": "2027-03-15",
  "adults": 2,
  "currency": "EUR",
  "minPrice": 50,
  "maxPrice": 300,
  "maxItems": 100,
  "includeHostDetails": true,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

You can also pass full URLs:

```json
{
  "startUrls": [
    { "url": "https://www.airbnb.com/s/Barcelona--Spain/homes?adults=2" },
    { "url": "https://www.airbnb.com/rooms/32422325" }
  ],
  "maxItems": 25
}
```

Search URLs keep the filters already in the link, and the Actor fills in anything missing from your input. A listing URL returns that one listing; its price fields are null because a listing page alone carries no quote for a stay.

### Output

Results are stored in the default dataset. The Overview view shows photo, name, title, price per night, currency, rating, reviews, bedrooms, beds, bathrooms, host name, host type, coordinates and link. A real record from a test run:

```json
{
  "id": "32422325",
  "sourceUrl": "https://www.airbnb.com/rooms/32422325",
  "name": "Brand new apartment right in the heart of Alfama.",
  "title": "Apartment in Santa Maria Maior",
  "pricePerNight": 124.95,
  "totalPrice": 401.88,
  "originalTotalPrice": 470,
  "nights": 3,
  "currency": "USD",
  "rating": 4.82,
  "reviewCount": 478,
  "bedrooms": 1,
  "beds": 2,
  "bathrooms": 1,
  "bathroomLabel": "1 bath",
  "hostType": "Business host",
  "badges": [],
  "hostName": "BB Lisbon",
  "hostIsVerified": true,
  "personCapacity": 4,
  "roomType": "Entire home/apt",
  "description": "<full plain-text description of the listing>",
  "amenities": ["Wifi", "Kitchen", "Air conditioning"],
  "checkInTime": "Check-in after 3:00 PM",
  "checkOutTime": "Checkout before 12:00 PM",
  "subRatings": {
    "accuracy": 4.75,
    "checkin": 4.73,
    "cleanliness": 4.69,
    "communication": 4.71,
    "location": 4.62,
    "value": 4.46
  },
  "latitude": 38.71167,
  "longitude": -9.12559,
  "thumbnail": "https://a0.muscache.com/im/pictures/7410b1e6-ec06-45c6-87ff-2346cea9fe5f.jpg",
  "searchLocation": "Lisbon, Portugal",
  "position": 2,
  "checkIn": null,
  "checkOut": null,
  "scrapedAt": "2026-10-03T12:00:00.000Z"
}
```

Every run also writes a `RUN_SUMMARY` record to the key-value store with the number of listings, the locations that were not recognised and the final status message.

### How much does it cost?

You are charged per result, which means per listing pushed to the dataset. The unit price is shown on the Pricing tab of this Actor, and Apify platform usage such as compute and proxy traffic is billed according to your plan. The number of results is capped by `maxItems`, so you can always limit what a run can spend by setting a lower value. Turning host details off reduces run time and platform usage.

### Use with AI agents (MCP)

You can call this Actor from any MCP-compatible assistant through the Apify MCP server. Add this to your client configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=axiomworks/airbnb-listings-scraper"
    }
  }
}
```

Example prompts:

- "Find 30 Airbnb listings in Lisbon for two adults and list name, price per night and rating."
- "Scrape Airbnb stays in Austin, TX from 2027-03-12 to 2027-03-15 for four guests and show the five best rated."
- "Compare the nightly price of Airbnb homes in Tulum and Hallstatt between 50 and 400."

The input field descriptions are written so that an agent can fill them in without further help.

### Integrations and API

Run the Actor from code with the Apify client libraries or the REST API.

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("axiomworks/airbnb-listings-scraper").call(run_input={
    "locations": ["Lisbon, Portugal"],
    "adults": 2,
    "maxItems": 50,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["name"], item["pricePerNight"], item["currency"])
```

**JavaScript**

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('axiomworks/airbnb-listings-scraper').call({
    locations: ['Lisbon, Portugal'],
    adults: 2,
    maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length);
```

**cURL**

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~airbnb-listings-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"locations": ["Lisbon, Portugal"], "adults": 2, "maxItems": 20}'
```

You can also connect the dataset to Google Sheets, Make, Zapier, n8n or a webhook, and schedule runs to track prices over time.

### FAQ

**How many listings can I get per search?**
Airbnb shows up to 270 listings per search. To go beyond that, run several narrower searches, such as neighbourhoods or map-area URLs.

**Why is `bedrooms` or `hostType` sometimes null?**
Airbnb's search cards show only some of these lines for a given search. The Actor fills gaps from the listing page when host details are on, but hotels and some rooms simply have no bedroom count.

**Why do I get different prices than on the website?**
Airbnb prices depend on dates, guests, currency and the visitor's region. Set the same dates, guests and currency in the input to get comparable numbers. Without dates Airbnb quotes its own default stay.

**What happens with past dates?**
They are dropped with a warning and Airbnb's default stay is used, so the run does not fail.

**Do I need an Airbnb account?**
No. The Actor reads public pages only and never logs in.

**What if Airbnb blocks requests?**
Requests that are blocked are retried a few times on a fresh proxy session with a pause. If the datacenter proxy is not enough, switch the proxy setting to residential.

**Can I scrape a single listing?**
Yes. Put the listing URL in `startUrls`. You get that listing's name, title, rating, bedrooms, host and sub-rating fields.

**Does it return reviews or calendars?**
No. This Actor returns search-result listings. Availability calendars are a separate tool.

### Is it legal to scrape Airbnb?

The Actor collects data that is publicly visible without logging in. Host names are public profile names shown on listing pages. Laws differ by country and by what you do with the data. Personal data, such as a host's name, falls under privacy law like the GDPR in many places, so keep only what you need and have a lawful reason to use it. Airbnb's terms of service restrict automated access, and you are responsible for using the data in line with the rules that apply to you. This is general information, not legal advice; ask a lawyer if you are unsure.

### Feedback

If a field is missing, a search returns something unexpected, or you need an extra field, open an issue from the Actor page in Apify Console. Include the input you used and the run link so the problem can be reproduced.

# Actor input Schema

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

Places to search, one per entry, e.g. \['Lisbon, Portugal', 'Austin, TX']. Use 'City, Country' or 'City, State'. Each search returns at most 270 listings. Leave empty if you use startUrls.

## `startUrls` (type: `array`):

Optional full Airbnb URLs: search pages (https://www.airbnb.com/s/Paris--France/homes, map-bounds URLs work too) or a single listing (https://www.airbnb.com/rooms/12345). Other sites are ignored.

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

Check-in date as YYYY-MM-DD, e.g. '2027-03-12'. Needs checkOut. Past or invalid dates are dropped with a warning and Airbnb quotes its own default stay.

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

Check-out date as YYYY-MM-DD, must be after checkIn, e.g. '2027-03-15'.

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

Number of adult guests, 1-16, default 2.

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

Number of children (2-12 years), 0-16, default 0.

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

Number of infants under 2, 0-5, default 0.

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

Number of pets, 0-5, default 0.

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

Only listings at or above this nightly price in the chosen currency, e.g. 50. Leave empty for no minimum.

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

Only listings at or below this nightly price in the chosen currency, e.g. 400. Leave empty for no maximum.

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

Currency for all prices: USD, EUR, GBP, CAD, AUD, JPY, CHF, MXN, BRL or INR. Default USD.

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

Maximum number of listings to return in total across all locations and URLs, 1-1000, default 50. Airbnb caps each search at 270.

## `includeHostDetails` (type: `boolean`):

If true (default), opens each listing page to add host name, host id, superhost flag, guest capacity, room type and sub-ratings. This doubles requests and run time. If false those fields are null.

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

Apify Proxy settings. Datacenter proxy works by default; switch to RESIDENTIAL if Airbnb blocks requests.

## Actor input object example

```json
{
  "locations": [
    "Lisbon, Portugal"
  ],
  "adults": 2,
  "children": 0,
  "infants": 0,
  "pets": 0,
  "currency": "USD",
  "maxItems": 10,
  "includeHostDetails": true,
  "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": [
        "Lisbon, Portugal"
    ],
    "maxItems": 10,
    "includeHostDetails": true,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/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": ["Lisbon, Portugal"],
    "maxItems": 10,
    "includeHostDetails": True,
    "proxyConfiguration": { "useApifyProxy": True },
}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axiomworks/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/5HhGVA8KYTymloWD8/builds/woERlVMPO5nUtNvOn/openapi.json
