# Airbnb Occupancy Scraper — Calendar, Occupancy & Booking Pace (`crawloop/airbnb-occupancy-monitor`) Actor

Airbnb occupancy scraper for public availability calendars. Paste listing URLs or a city search and export occupancy %, blocked nights, min-stay, and booking-pace deltas as JSON — an Airbnb calendar API alternative for STR teams.

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

## Pricing

from $3.99 / 1,000 listing calendars

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/platform/actors/running/actors-in-store#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 Occupancy Scraper — Calendar, Occupancy % & Booking Pace

> **Disclaimer:** Unofficial tool for publicly accessible Airbnb listing calendars. **Airbnb** is a trademark of Airbnb, Inc. Not affiliated with, sponsored by, or endorsed by Airbnb. For informational, research, revenue-management, and market-analysis use only. Respect applicable terms of use and law.

**Airbnb occupancy scraper** for the public **availability calendar** — a practical **Airbnb calendar scraper**, **Airbnb availability scraper**, and **Airbnb API alternative**. Paste **listing URLs or IDs**, a **city search URL**, or a **location**. Export **occupancy %** (30 / 60 / 90 / 365 days), **blocked nights**, **min-stay**, **check-in / check-out**, optional **nightly prices**, and **booking-pace** deltas as a JSON dataset. Call from **Python**, **Node.js**, **cURL**, or **Apify MCP** / AI assistants.

Built for **STR revenue managers**, **vacation-rental investors**, **comp-set tracking**, and **short-term rental market research**. No Airbnb account required.

| Airbnb occupancy (STR calendars) | Idealista (long-term ES/IT/PT) | ImmobilienScout24 (DE long-term) |
| :--- | :--- | :--- |
| **Airbnb Occupancy Scraper** ◄── you are here | [Idealista Scraper](https://apify.com/crawloop/idealista-scraper) | [ImmobilienScout24 Scraper](https://apify.com/crawloop/immobilienscout24-scraper) |

### When to use this Actor

- You need an **Airbnb occupancy monitor** / **Airbnb occupancy scraper** that returns structured JSON
- You already know listing IDs (portfolio / comp set) or have a city search URL
- You want **occupancy %, blocked nights, min-stay, and booking pace** — not a generic listing dump
- You want to scrape Airbnb calendars with **Python**, **Node.js**, or **MCP** and export a dataset

### When not to use this Actor

- **Historical occupancy** — Airbnb only exposes a **forward** calendar (about 12 months)
- **Guaranteed booked vs owner-blocked** — the public calendar cannot tell them apart; this Actor labels that honestly
- **Guest PII, messages, or host inbox** — public calendar and listing fields only
- **Long-term rental listings** — use [Idealista Scraper](https://apify.com/crawloop/idealista-scraper) or [ImmobilienScout24 Scraper](https://apify.com/crawloop/immobilienscout24-scraper)
- **Whole-market 10k-listing crawls in one run** — cap with `maxListings` and schedule by neighborhood

### Key Features

- **Listing URLs or IDs** — room URLs and bare numeric IDs
- **Search / location discovery** — paste an Airbnb search URL or type `Paris, France` to take the first search page, then pull calendars
- **Forward calendar** — 1–12 months of available / bookable, check-in / check-out, min / max nights
- **Occupancy windows** — 30 / 60 / 90 / 365-day unavailable rates plus horizon totals
- **Booking pace** — schedule the Actor and get newly unavailable / newly available nights vs the previous run
- **Honest metrics** — `unavailableRate` and `occupancyEstimate` are the same calendar signal, with an explicit host-block caveat
- **ADR / RevPAR only from real prices** — never interpolated; often `null` on anonymous calendar reads
- **HTTP JSON path** — Chrome TLS impersonation + dynamic GraphQL hash; no Playwright
- **Apify Proxy ready** — US residential recommended on the platform
- **MCP / AI ready** — call from assistants via Apify MCP

### Use Cases

| Use case | What you get |
| :--- | :--- |
| **Comp-set occupancy** | Forward unavailable % for rival Airbnb listings in your market |
| **Booking pace** | Nights that flipped unavailable (or opened) since the last scheduled run |
| **Min-stay intelligence** | Most common minimum-night rule across the horizon |
| **Investment screening** | Occupancy windows + rating / capacity from the public listing page |
| **Revenue tooling** | Per-day calendar arrays into a pricing or BI pipeline |
| **Market snapshot** | First page of a city search, then calendars for each listing |

### Quick Start

**Known listings:**

```json
{
  "listings": ["35329051", "1733978701934130004"],
  "calendarMonths": 12,
  "includeCalendar": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "US"
  }
}
```

**City search (first page of listings, then calendars):**

```json
{
  "location": "Paris, France",
  "calendarMonths": 6,
  "maxListings": 20,
  "includeListingDetails": true
}
```

**Scheduled booking-pace monitor:**

```json
{
  "listings": ["35329051"],
  "calendarMonths": 12,
  "monitor": true,
  "includeCalendar": false
}
```

### Input Parameters

| Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `listings` | Array | — | Room URLs or numeric listing IDs |
| `startUrls` | Array | — | Room URLs and/or Airbnb search URLs |
| `location` | String | — | City / area used to build a search URL |
| `calendarMonths` | Integer | `12` | Forward months (1–12) |
| `maxListings` | Integer | `50` | Cap (`0` = unlimited) |
| `includeListingDetails` | Boolean | `true` | Title, location, rating, capacity, host |
| `includeCalendar` | Boolean | `true` | Per-day `calendar[]` array |
| `monitor` | Boolean | `false` | Booking-pace vs previous run |
| `currency` | String | `USD` | ISO code (prices often hidden) |
| `proxyConfiguration` | Object | US residential | Strongly recommended on Apify |

### Output Format

Each dataset item is one listing (or an `error` row if that listing failed).

| Field | Type | Description |
| :--- | :--- | :--- |
| `listingId` | String | Airbnb listing id |
| `listingUrl` | String | Room URL |
| `title` | String | Listing title |
| `city` | String | Localized area |
| `propertyType` / `roomType` | String | Property / space type |
| `rating` / `reviewsCount` | Number / Integer | Public review stats |
| `maxGuests` / `bedrooms` / `beds` / `bathrooms` | Number | Capacity when exposed |
| `unavailableRate` | Number | Unavailable ÷ counted forward nights (0–1) |
| `occupancyEstimate` | Number | Same value; labeled as an estimate |
| `occupancy30d` / `60d` / `90d` / `365d` | Number | Windowed unavailable rates |
| `availableDays` / `unavailableDays` | Integer | Horizon counts |
| `firstAvailableDate` | String | Nearest open night |
| `minNightsMode` | Integer | Most common min-stay |
| `adr` / `estimatedRevenue` / `revpar` | Number | Only from real calendar prices; else `null` |
| `bookingPace` | Object | Present when `monitor` is on |
| `calendar` | Array | Per-day availability (optional) |
| `occupancyNote` | String | Host-block caveat |
| `scrapedAt` | String | ISO timestamp |

**Example row:**

```json
{
  "type": "listing",
  "source": "airbnb",
  "listingId": "35329051",
  "listingUrl": "https://www.airbnb.com/rooms/35329051",
  "title": "Cosy apartment close to Airport Link Station",
  "city": "Khet Suan Luang",
  "unavailableRate": 0.4342,
  "occupancyEstimate": 0.4342,
  "occupancy30d": 0.7,
  "occupancy90d": 0.4342,
  "availableDays": 43,
  "unavailableDays": 33,
  "firstAvailableDate": "2026-08-24",
  "minNightsMode": 1,
  "adr": null,
  "currency": "USD"
}
```

#### How occupancy is calculated

Airbnb’s public calendar marks a night **available** or **unavailable**. An unavailable night can be a guest booking **or** a host calendar block. This Actor reports `unavailableRate` and `occupancyEstimate` as that share of upcoming nights, with `occupancyNote` on every row. It does not invent a booking-only occupancy figure.

Nightly `price` is included when Airbnb actually returns one. Anonymous calendar reads usually have `price: null`, so ADR / RevPAR stay `null` rather than a guessed market average.

### Integration examples

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('crawloop/airbnb-occupancy-monitor').call({
  listings: ['35329051'],
  calendarMonths: 12,
  proxyConfiguration: {
    useApifyProxy: true,
    apifyProxyGroups: ['RESIDENTIAL'],
    apifyProxyCountry: 'US',
  },
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.slice(0, 5));
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient(token)
run = client.actor("crawloop/airbnb-occupancy-monitor").call(
    run_input={
        "listings": ["35329051"],
        "calendarMonths": 12,
        "proxyConfiguration": {
            "useApifyProxy": True,
            "apifyProxyGroups": ["RESIDENTIAL"],
            "apifyProxyCountry": "US",
        },
    }
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item.get("listingId"), item.get("unavailableRate"), item.get("listingUrl"))
```

#### cURL

```bash
curl "https://api.apify.com/v2/acts/crawloop~airbnb-occupancy-monitor/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"listings":["35329051"],"calendarMonths":12}'
```

### MCP and AI assistants

Use this Actor from AI tools via [Apify MCP](https://docs.apify.com/platform/integrations/mcp). Connect your Apify account, then call `crawloop/airbnb-occupancy-monitor`.

Example prompts:

- "Run Airbnb Occupancy Scraper for listing 35329051 with 12 months of calendar and return unavailableRate, occupancy30d, occupancy90d, firstAvailableDate"
- "Scrape Airbnb occupancy for listings in Paris, France, max 15, and summarize 30-day occupancy estimates as JSON"
- "Monitor these Airbnb room URLs weekly for booking pace, then run Idealista Scraper for long-term rental comps in the same city"

### FAQ

**Is this an official Airbnb API?**\
No. It reads the same public GraphQL calendar the website uses and returns structured dataset rows — a practical **Airbnb API alternative** for pipelines.

**Airbnb occupancy scraper vs Airbnb listing scraper?**\
This Actor is calendar-first: occupancy %, blocked nights, min-stay, and booking pace. It is not a generic dump of amenities and photos.

**Do I need an Airbnb login?**\
No — public calendars and listing pages only.

**Can I scrape Airbnb occupancy with Python or Node.js?**\
Yes — use the Apify client examples above, or call the Actor from cURL / Apify MCP.

**Why residential proxy?**\
Airbnb often challenges datacenter IPs. Residential (US) is the reliable default on the platform.

**Is occupancy the same as booked nights?**\
No. Treat `occupancyEstimate` as **unavailable share**, including host blocks. That is the same limitation every calendar-based STR tool has.

**Can I get historical occupancy?**\
No. The calendar is forward-only. Schedule the Actor to build your own history.

**Does every listing include a nightly price?**\
Usually not on anonymous calendar reads. Occupancy still computes from availability flags.

**How many listings per search?**\
A location / search URL contributes roughly one page of listing IDs (about 18–20). Pass explicit `listings` for a known portfolio.

### Related Actors

| Actor | Focus |
| :--- | :--- |
| **Airbnb Occupancy Scraper** ◄── you are here | STR calendars, occupancy %, booking pace |
| [Idealista Scraper](https://apify.com/crawloop/idealista-scraper) | Long-term rental / sale listings (ES/IT/PT) |
| [ImmobilienScout24 Scraper](https://apify.com/crawloop/immobilienscout24-scraper) | German long-term listings |

**Suite next step:** after occupancy snapshots, run [Idealista Scraper](https://apify.com/crawloop/idealista-scraper) or [ImmobilienScout24 Scraper](https://apify.com/crawloop/immobilienscout24-scraper) for long-term rental comps in the same investment workflow.

# Actor input Schema

## `listings` (type: `array`):

Airbnb room URLs or numeric listing IDs (the number in /rooms/). One per line.

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

Room URLs and/or Airbnb search URLs (e.g. /s/Paris--France/homes). Search pages yield the first results page of listing IDs, then calendars are fetched for each.

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

City or area name used to build a search URL when you do not have listing IDs yet. Example: Paris, France or Austin, TX.

## `calendarMonths` (type: `integer`):

Forward months of availability to read (1–12). Airbnb caps the public calendar at about 12 months.

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

Hard cap on listings processed in one run. 0 = unlimited.

## `includeListingDetails` (type: `boolean`):

Add title, location, rating, capacity, and host fields harvested from the public room page.

## `includeCalendar` (type: `boolean`):

Attach the per-day availability array (date, available, check-in/out, min/max nights, price when present).

## `monitor` (type: `boolean`):

Compare this run to the previous run on the same Actor (same default KV store) and emit newly unavailable / newly available night counts. First run has no pace yet.

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

ISO currency code requested from Airbnb. Nightly calendar prices are often null for anonymous reads; occupancy does not depend on price.

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

Residential proxy is recommended. Airbnb often blocks datacenter IPs before the calendar GraphQL responds.

## Actor input object example

```json
{
  "listings": [
    "35329051"
  ],
  "calendarMonths": 12,
  "maxListings": 50,
  "includeListingDetails": true,
  "includeCalendar": true,
  "monitor": false,
  "currency": "USD",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Default dataset items.

# 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 = {
    "listings": [
        "35329051"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawloop/airbnb-occupancy-monitor").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 = {
    "listings": ["35329051"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("crawloop/airbnb-occupancy-monitor").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 '{
  "listings": [
    "35329051"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call crawloop/airbnb-occupancy-monitor --silent --output-dataset

```

## MCP server setup

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

```

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/RFXvQy7v0ArpI3AXc/builds/jnHLKVtotF9NmyBaY/openapi.json
