# Airbnb Market Snapshot: Listings, Prices & Occupancy (`engraved_sugilite/airbnb-market-snapshot`) Actor

Every Airbnb listing in a city or map area, past Airbnb's ~270-result search cap, with the price for your dates and a calendar-based occupancy estimate for the next 30/60/90 days, plus a market summary. Listing data only, no personal data.

- **URL**: https://apify.com/engraved\_sugilite/airbnb-market-snapshot.md
- **Developed by:** [Miguel Jardim](https://apify.com/engraved_sugilite) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 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.

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 Market Snapshot

Get **every Airbnb listing in a city or map area**, with the **price for your dates** and an **occupancy estimate for the next 30, 60 and 90 days**, plus a ready-made **market summary** (median nightly price, median occupancy, rating, property mix).

Built for short-term-rental investors, property managers and analysts who want AirDNA-style numbers for a specific area without a monthly subscription.

### Why this Actor

- **Full coverage, not the first 270 results.** Airbnb stops returning results after ~15 pages per search. This Actor splits the map into smaller tiles until each tile fits under that cap, so a whole city is covered. Duplicates are removed.
- **Occupancy from the public calendar.** For each listing it reads the public availability calendar and reports unavailable nights and an occupancy estimate for the next 30/60/90 days.
- **A market summary in one place.** The run writes a `SUMMARY` record to the key-value store: listing count, median nightly price, median occupancy (30 and 90 days), median rating and reviews, share of "Guest favourite" listings and the property-type mix.
- **No personal data.** Output contains listing data only (no host names, profiles or contact details).

### Input

| Field | What it does |
|---|---|
| `location` | City or area, e.g. `Lisbon, Portugal`. The area's boundaries are looked up on OpenStreetMap. |
| `checkIn` / `checkOut` | Dates for pricing (default: 30 days from today, 3 nights). |
| `adults` | Guests (default 2). |
| `currency` | Price currency (default EUR). |
| `maxListings` | Stop after this many listings (default 500). |
| `includeOccupancy` | Read each listing's calendar for occupancy (default on). |
| `minPrice` / `maxPrice`, `roomTypes` | Optional Airbnb filters. |
| `neLat`, `neLng`, `swLat`, `swLng` | Optional custom map area instead of `location`. |

### Output (one row per listing)

`listingId`, `url`, `name`, `propertyType`, `area`, `latitude`, `longitude`, `bedrooms`, `beds`, `baths`, `isStudio`, `rating`, `reviewsCount`, `isNew`, `isGuestFavorite`, `hostCategory` (e.g. "Individual host"), `checkin`, `checkout`, `nights`, `adults`, `currency`, `totalPrice` (whole stay incl. fees and taxes), `nightlyPrice` (total ÷ nights, i.e. what a guest really pays per night), `listedNightlyRate` (the host's nightly rate before discounts, fees and taxes, when shown), `freeCancellation`, `photoUrl`, and with occupancy on: `unavailableNights30/60/90`, `occupancyEstimate30/60/90`, `minNights`.

Example row:

```json
{
  "listingId": "19926030",
  "propertyType": "Apartment",
  "area": "Santa Maria Maior",
  "bedrooms": 1, "beds": 1, "baths": 1,
  "rating": 4.54, "reviewsCount": 109,
  "nightlyPrice": 82.33, "totalPrice": 247, "currency": "EUR",
  "occupancyEstimate30": 0.767, "occupancyEstimate90": 0.3, "minNights": 2
}
```

### How to read the occupancy numbers

- They are **forward-looking** ("on the books" today): the share of the next N nights that are not available. Far-away windows are naturally lower because fewer nights are booked yet.
- The public calendar does not distinguish **booked** nights from nights **blocked by the host**, so the estimate is an **upper bound** on real occupancy.
- Listings with incomplete calendar data get `null` rather than a guess.

### Tips

- To get a representative market picture, set `maxListings` high enough to cover the whole area. With a low cap the Actor returns the first tiles it visits, not a random sample.
- Prices depend on the dates and number of guests you choose; run the same area for different dates to see seasonality.

### Pricing

Pay per event: one charge per listing saved, and one per listing whose occupancy was computed. You never pay for listings you don't receive, and you can cap spending per run in Apify Console.

### Notes

This Actor collects publicly visible listing information. You are responsible for using the data in line with applicable laws and Airbnb's terms. Built by Miguel Jardim with the help of AI tools (Claude); every release is tested against live data before publishing.

# Actor input Schema

## `location` (type: `string`):

City or area, e.g. "Lisbon, Portugal". Its map area is looked up on OpenStreetMap and fully covered. Leave empty if you give a bounding box below.

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

YYYY-MM-DD. Default: 30 days from today.

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

YYYY-MM-DD. Default: check-in + 3 nights.

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

Number of adult guests used for availability and pricing.

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

Currency code for prices, e.g. EUR, USD, GBP.

## `maxListings` (type: `integer`):

Stop after this many listings.

## `includeOccupancy` (type: `boolean`):

Read each listing's public availability calendar and estimate occupancy for the next 30/60/90 days (unavailable nights / nights). Host-blocked nights count as unavailable, so this is an upper bound.

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

Optional minimum nightly price filter (in the chosen currency).

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

Optional maximum nightly price filter (in the chosen currency).

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

Optional Airbnb room types, e.g. "Entire home/apt", "Private room".

## `neLat` (type: `string`):

North-east corner latitude of a custom map area. Use together with the other three corner fields.

## `neLng` (type: `string`):

North-east corner longitude of a custom map area.

## `swLat` (type: `string`):

South-west corner latitude of a custom map area.

## `swLng` (type: `string`):

South-west corner longitude of a custom map area.

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

Proxy used for requests to Airbnb. Apify datacenter proxy works for Airbnb; switch to residential only if you see blocks.

## `requestDelaySecs` (type: `number`):

Average pause between requests. Higher is gentler and more reliable; lower is faster.

## `maxConcurrency` (type: `integer`):

How many listing calendars are read at the same time. Higher is faster; lower is gentler.

## Actor input object example

```json
{
  "location": "Lisbon, Portugal",
  "adults": 2,
  "currency": "EUR",
  "maxListings": 500,
  "includeOccupancy": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "requestDelaySecs": 1,
  "maxConcurrency": 4
}
```

# Actor output Schema

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

One row per listing: price for your dates, rating, rooms, coordinates and occupancy estimates.

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

Area-level summary: listing count, median nightly price, median occupancy (30/90 days), median rating, guest-favourite share, property mix.

# 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": "Lisbon, Portugal"
};

// Run the Actor and wait for it to finish
const run = await client.actor("engraved_sugilite/airbnb-market-snapshot").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": "Lisbon, Portugal" }

# Run the Actor and wait for it to finish
run = client.actor("engraved_sugilite/airbnb-market-snapshot").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": "Lisbon, Portugal"
}' |
apify call engraved_sugilite/airbnb-market-snapshot --silent --output-dataset

```

## MCP server setup

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

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/lnuLITCQBF9oLVL2i/builds/hRgqqjdlx4idXnvgD/openapi.json
