# Airbnb Listings Scraper — Prices, Ratings & Changes (`northbell/airbnb-listings-tracker`) Actor

Airbnb search results for any place: price per night and total for your dates, rating, reviews, bedrooms, beds, baths, Guest favourite and Superhost badges, coordinates and photo. Run it again or on a schedule to get new listings, price changes and rank moves since the last run. No login.

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

## Pricing

from $1.60 / 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 Listings Scraper — Prices, Ratings & Changes

Give it a place — `Lisbon, Portugal`, `Kyoto, Japan` — and optionally your check-in and check-out dates, and get one clean row per Airbnb listing: **price per night and total for your dates, rating and review count, bedrooms, beds, baths, Guest favourite and Superhost badges, coordinates and a photo**. **$2 per 1,000 listings**, no login, no API key.

Run it again — or put it on a daily schedule — and every row also tells you **what changed since the last run**: which listings are new, the **price change per night**, and how far each listing moved up or down the results. Airbnb only shows you today's price; this keeps yesterday's.

### What you get

| Field | What it is |
|---|---|
| `location`, `resolvedLocation` | the place you typed, and the place Airbnb actually searched (for example `Lisbon, Portugal`) |
| `rank` | position in Airbnb's results for this search (1 = first) |
| `listingId`, `url`, `title` | the listing, its `airbnb.com/rooms/…` link, and the title its host gave it |
| `roomType`, `area` | Apartment, Room, Hotel, Cottage…; and the neighbourhood label Airbnb prints under it |
| `pricePerNight`, `priceTotal`, `currency`, `nights` | the price for the stay as Airbnb shows it, fees included. Exact to the cent where Airbnb's price breakdown allows (the page itself rounds up to whole units). `pricePerNight` is `priceTotal` ÷ `nights` |
| `originalPrice` | the crossed-out price, when the listing is discounted |
| `priceMonthly` | only for stays of 28 nights or more: Airbnb shows a monthly price instead of a total. `priceTotal` is then `null` and `pricePerNight` is the monthly price ÷ 30 |
| `checkIn`, `checkOut`, `adults` | the stay the price is for |
| `rating`, `reviewCount` | Airbnb's average rating and number of reviews (`null` for listings marked New) |
| `bedrooms`, `beds`, `bathrooms` | as printed on the search card |
| `guestFavourite`, `superhost`, `badges`, `freeCancellation` | the badges and the free-cancellation note on the card. `superhost` is a badge only; no host is identified |
| `lat`, `lng` | the approximate coordinates Airbnb shows |
| `thumbnailUrl` | first photo, 720 px wide |
| `isNewSinceLastRun`, `previousRank`, `rankChange`, `previousPricePerNight`, `priceChange`, `priceChangePercent`, `previousRunAt` | the change since your previous run of the same search (`null` on the first run). `rankChange` is positive when the listing moved up; `priceChange` is positive when it got more expensive |
| `firstSeenAt` | the first time any run of this search saw the listing |

### Use it for

- **Pricing your own place** — see what comparable listings charge for your dates, and when they cut prices
- **Market scans** — compare price, rating and size across neighbourhoods or cities, then export to Sheets or your BI tool
- **Deal watching** — schedule a search for your trip dates and look at `priceChange`
- **Competitor tracking for hosts and property managers** — see new listings and who is moving up the results

### Input

```json
{
  "locations": ["Lisbon, Portugal", "Porto, Portugal"],
  "checkIn": "2026-11-10",
  "checkOut": "2026-11-13",
  "adults": 2,
  "currency": "EUR",
  "maxListingsPerLocation": 100,
  "maxPrice": 200
}
```

You can also paste an `airbnb.com/s/…` search link as a location; the place is taken from it. `minPrice` / `maxPrice` are per night, in the chosen currency, and are applied by Airbnb on its own nightly price, so `pricePerNight` (which includes fees) can land a little outside the range. 41 currencies are supported (see the input form).

The previous run is remembered per search (place + dates + guests + currency + price range) in a named key-value store in your Apify account, so the second run of the same search already shows changes. Schedule it (Apify → Schedules) for a daily history.

### Pricing

**$2.00 per 1,000 listings**, plus $0.01 per run. Error rows (a place Airbnb does not recognise, no results, a blocked page) are free. The $0.01 run-start fee is the one charge every run pays, even one that returns nothing.

### Notes

- Public data only: what anyone sees on an Airbnb search page without signing in. No host names, host IDs, host photos or reviewer names are returned.
- **Give dates when you want to compare prices.** With check-in and check-out every listing is priced for the same stay. Without dates Airbnb picks a different 5-night window for each listing (shown in `checkIn` / `checkOut`), and `priceChange` is only given when a listing shows the same window as last time. Dates must be today or later.
- Airbnb returns at most about 270 results per search (15 pages of 18), and a few repeat between pages, so one search gives up to roughly 200–250 different listings. For a big city, search a neighbourhood (`Alfama, Lisbon`) or add a price range to split it up. Asking for more than Airbnb has left just ends the list.
- **Airbnb's ranking moves between requests.** In a big city about a third of a 200-listing list is different even minutes later, so `isNewSinceLastRun` and `rankChange` are noisy there; `priceChange` is not, and `firstSeenAt` tells a listing that is new to your history from one that came back. Small markets and narrowed searches are steadier. Keep *Max listings per place* the same between runs.
- Some fields are empty by design: `rating` / `reviewCount` for listings marked New; `bedrooms`, `beds` and `bathrooms` only when the search card prints them (hotels print none; rooms, studios and many apartments print beds but no bedrooms; some cards print no baths) — they are never guessed; `originalPrice` unless the listing is discounted; `priceMonthly` unless the stay is 28 nights or more; `priceTotal` only for stays under 28 nights. The change fields (`isNewSinceLastRun`, `previousRank`, `rankChange`, `previousPricePerNight`, `priceChange`, `priceChangePercent`, `previousRunAt`) are `null` on the first run of a search.
- `area` is the label Airbnb prints and hosts fill in, so it can be off (a Lisbon flat labelled with another city happens). `resolvedLocation` is what Airbnb really searched; Airbnb sometimes widens a neighbourhood to its city (`Brooklyn, NY` is searched as `New York City, NY`), so check it.
- Airbnb does not recognise some names, especially non-English ones such as `東京`; it then shows unrelated listings from all over the world. The Actor returns an error row instead of keeping them. Use the English name with the country (`Tokyo, Japan`).
- The price is the one on the search card. Airbnb's checkout can still differ (for example taxes).
- If Airbnb shows a bot check, the row is an error row and nothing is stored for that search, so your history is kept. If a later page fails halfway, the rows already read are kept, a free error row says where it stopped, and the saved history is left as it was, so the next run does not call everything new. A run that could read nothing at all fails.
- Places that cannot be read at all (for example a link that is not an `airbnb.com/s/…` search) are refused before the run starts, which costs nothing.

### For AI agents

`{"locations": ["Lisbon, Portugal"], "checkIn": "2026-11-10", "checkOut": "2026-11-13", "maxListingsPerLocation": 20}` returns up to 20 rows with price per night and total for those dates, rating, beds and the changes since the last run. Rows have `type`: `listing` or `error`.

# Actor input Schema

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

One place per line, in English with the country: "Lisbon, Portugal", "Kyoto, Japan", "Alfama, Lisbon". You can also paste an airbnb.com/s/… search link. Airbnb returns at most about 270 listings per place, so for a big city search a neighbourhood or add a price range.

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

Optional, YYYY-MM-DD (today or later). Give both dates to get every listing priced for the same stay, which is what you need to compare prices and track price changes. Leave both empty and Airbnb picks a 5-night window per listing.

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

Optional, YYYY-MM-DD, after the check-in date. Stays of 28 nights or more come back with a monthly price (priceMonthly) instead of a total.

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

Number of adults the search is priced for (1 to 16).

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

Currency of the prices. Airbnb converts for you.

## `maxListingsPerLocation` (type: `integer`):

How many listings to read for each place, in Airbnb's order (18 per page). Airbnb stops at about 270 per search. Keep it the same between runs so the changes since the last run are comparable.

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

Optional. Only listings from this price per night, in the chosen currency. Applied by Airbnb.

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

Optional. Only listings up to this price per night, in the chosen currency. Applied by Airbnb.

## Actor input object example

```json
{
  "locations": [
    "Lisbon, Portugal"
  ],
  "adults": 2,
  "currency": "USD",
  "maxListingsPerLocation": 50
}
```

# Actor output Schema

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

Price per night and total for your dates, rating, bedrooms, beds, baths, badges and the changes since the last run.

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("northbell/airbnb-listings-tracker").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"] }

# Run the Actor and wait for it to finish
run = client.actor("northbell/airbnb-listings-tracker").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"
  ]
}' |
apify call northbell/airbnb-listings-tracker --silent --output-dataset

```

## MCP server setup

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

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/fg7ZBASGCeNGqJ95v/builds/XaET7b9ve9tJg5z6j/openapi.json
