# 📅 Airbnb Availability & Rate Scraper (`simpleapi/airbnb-occupancy-scraper`) Actor

Monitor Airbnb occupancy and availability across listings or cities. Retrieve booked nights, seasonal trends, and pricing signals. Designed for researchers, investors, and revenue teams needing trusted data.

- **URL**: https://apify.com/simpleapi/airbnb-occupancy-scraper.md
- **Developed by:** [SimpleAPI](https://apify.com/simpleapi) (community)
- **Categories:** Travel, Lead generation, Automation
- **Stats:** 10 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$19.99/month + usage

To use this Actor, you pay a monthly rental fee to the developer. The rent is subtracted from your prepaid usage every month after the free trial period. You also pay for the Apify platform usage, which gets cheaper the higher Apify subscription plan you have.

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

## 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 Availability Scraper — Rates, Calendar and Booking Status

Pull the forward-looking availability calendar for any Airbnb listing straight from Airbnb's own `PdpAvailabilityCalendar` endpoint: per-day `availableForCheckin`, `availableForCheckout`, `bookable`, `minNights`, `maxNights`, and the nightly `price` when Airbnb actually exposes one. From those real values the actor derives an honestly-labeled `unavailableRate`, plus `adr`, `estimatedRevenue`, and `revpar` — computed only from real calendar prices, never a guess. Revenue managers, short-term-rental investors, and market analysts use it to track pricing and booking-window patterns across a portfolio of known listings. No Airbnb account or login is required.

### What is Airbnb Availability Scraper?

Airbnb Availability Scraper is an [Apify Actor](https://apify.com/simpleapi/airbnb-availability-scraper) that takes a list of Airbnb listing URLs or numeric room IDs and returns their availability calendar and, where present, nightly pricing — as structured JSON rows in an Apify dataset. It does not search or discover new listings; you supply the listings you already know about, and it fetches each one's calendar directly from Airbnb's GraphQL API, bypassing the need for a browser.

- **Discovery is by listing, not by search.** Input is a plain list of Airbnb room URLs (`https://www.airbnb.com/rooms/35329051`) or bare numeric IDs (`35329051`) — both are accepted in the same list.
- **Core calendar fields returned per day:** `availableForCheckin`, `availableForCheckout`, `bookable`, `minNights`, `maxNights`, and `price` (a real number or `null`, never a placeholder value).
- **Secondary derived data:** an honestly-labeled `unavailableRate` (host-blocked *and* booked nights combined — see the honesty note below), plus `adr`, `estimatedRevenue`, and `revpar`, all `null` when no real calendar price exists for the window.
- **Temporal fields:** `date`, `dayOfWeek`, `isWeekend` on every day row, and `windowStart` / `windowEnd` / `totalDays` on the listing summary row.
- **Real filters exposed:** a `startDate` / `endDate` calendar window, a `billingMode` that controls cost granularity, and three on/off toggles (`includeDays`, `includeListingDetails`, `includeHostProfile`) that shape which rows and fields come back.
- **Export formats:** every Apify dataset — including this actor's — can be downloaded from the Apify Console or API as JSON, CSV, Excel (XLSX), XML, RSS, or an HTML table.

### What data can I extract with Airbnb Availability Scraper?

The actor writes two row types into the same dataset, distinguished by the `type` field (`"listing"` or `"day"`) and the `isChild` boolean. Every field below is read directly from `src/main.py` and `src/helpers.py` — several exist in the underlying data but are **not** in the dataset's default view (36 columns), so open "API → Dataset items" or download the raw JSON to see all of them.

| Field | Row type | In default view? | Example value | Use case |
| --- | --- | --- | --- | --- |
| `type` | both | yes | `"listing"` / `"day"` | Split parent summaries from day-level detail |
| `isChild` | both | yes | `false` / `true` | Programmatic filter for row type |
| `roomId` | both | yes | `"35329051"` | Join listing and day rows |
| `listingUrl` | both | yes | `"https://www.airbnb.com/rooms/35329051"` | Canonical link back to the listing |
| `scrapedAt` | both | yes | `"2026-07-26T14:03:00Z"` | Freshness check on every row |
| `currency` | both | yes | `"USD"` (listing) / `"USD"` or `null` (day) | Pair with any price field |
| `parentId` | day | **no** | `"35329051"` | Same as `roomId` on day rows; kept for explicit parent-child joins |
| `date` | day | yes | `"2026-08-01"` | Calendar day key |
| `dayOfWeek` | day | yes | `"Saturday"` | Weekday pricing/demand analysis |
| `isWeekend` | day | yes | `true` | Weekend-vs-weekday segmentation |
| `available` | day | yes | `false` | Raw Airbnb availability flag (see honesty note) |
| `availableForCheckin` | day | yes | `false` | Whether a stay can start this day |
| `availableForCheckout` | day | yes | `true` | Whether a stay can end this day |
| `bookable` | day | yes | `false` | Airbnb's own bookability flag for the day |
| `minNights` | day | yes | `2` | Minimum stay length enforced that day |
| `maxNights` | day | yes | `365` | Maximum stay length enforced that day |
| `price` | day | yes | `128.5` or `null` | Real nightly price when Airbnb returns one |
| `windowStart` / `windowEnd` | listing | yes | `"2026-08-01"` / `"2026-10-31"` | The resolved date range actually scraped |
| `totalDays` | listing | yes | `92` | Denominator for every rate below |
| `availableDays` / `unavailableDays` | listing | yes | `40` / `52` | Raw day counts behind `unavailableRate` |
| `unavailableRate` | listing | yes | `0.5652` | Host-blocked + booked days ÷ counted days |
| `priceCoverage` | listing | yes | `"40/92"` | How many of the window's days actually carried a real price |
| `pricedDays` | listing | **no** | `40` | Numerator of `priceCoverage`, kept as its own field |
| `adr` | listing | yes | `128.5` | Average of real nightly prices only |
| `minPrice` / `maxPrice` | listing | yes | `110.0` / `210.0` | Price spread across priced days |
| `estimatedRevenue` | listing | yes | `6682.0` | ADR × unavailable days — an upper bound, see honesty note |
| `revpar` | listing | yes | `72.63` | ADR × unavailable-day rate — also an upper bound |
| `title` | listing (opt-in) | yes | `"Modern Loft Near Downtown"` | Listing display name |
| `starRating` | listing (opt-in) | yes | `4.87` | Parsed from the page's star display, `null` if absent |
| `roomType` / `propertyType` | listing (opt-in) | yes | `"Entire home"` / `"Apartment"` | Property classification |
| `personCapacity` | listing (opt-in) | yes | `4` | Guest capacity |
| `bedrooms` | listing (opt-in) | **no** | `1` | Parsed from capacity text or embedded state |
| `beds` / `bathrooms` | listing (opt-in) | yes | `2` / `1` | Room counts |
| `latitude` / `longitude` | listing (opt-in) | **no** | `40.7128` / `-74.006` | Approximate, jittered pre-booking coordinates |
| `coordinatesApproximate` | listing (opt-in) | **no** | `true` | Always `true` — flags that the coordinates above are Airbnb's jittered pre-booking values, not exact |
| `hostIsSuperhost` | listing (opt-in) | yes | `true` | Superhost badge status |
| `hostName` | listing (opt-in) | **no** | `"Maria"` | Best-effort host display name |
| `hostResponseRate` | listing (opt-in) | **no** | `"100%"` | As shown on the listing page |
| `hostSince` | listing (opt-in) | **no** | `null` | Present in the schema, currently always returned `null` — Airbnb's public room page does not expose it in the embedded state this actor parses |

#### Revenue and demand metrics

`adr`, `estimatedRevenue`, `revpar`, and `unavailableRate` are the fields most buyers of this data actually want, and they are computed only from real calendar prices — never a regional average or a search-page estimate. `adr` is the mean of every real nightly `price` found in the window; when a listing exposes no price at all in its calendar, `adr` is `null` and so are `estimatedRevenue` and `revpar`. `estimatedRevenue` and `revpar` additionally *assume every unavailable night is a paid booking*, which makes them an upper bound — they intentionally include host-blocked nights, and the field names and this document say so rather than presenting them as realized revenue. A revenue manager pulling a 90-day window across ten listings can rank them by `revpar` to spot underpriced or over-blocked units without ever seeing a number that wasn't in Airbnb's own calendar payload.

#### Booking-window and constraint fields

`minNights`, `maxNights`, `availableForCheckin`, and `availableForCheckout` are the fields readers segment on to answer "can a guest actually book this stretch of dates." A day can be `available` yet not `availableForCheckin` if it only works as a mid-stay night under the listing's minimum-stay rule — these three fields, read together per day, are what tell you whether a specific arrival date is workable, not just whether the night is open.

### Why not build this yourself?

Airbnb has no public, self-serve API for third-party developers — there is no documented signup flow or published rate-limit page to build against, so there is no official API to compare this actor to. What exists instead is Airbnb's internal, undocumented GraphQL calendar endpoint, and reaching it reliably from your own code runs into three separate problems that this actor's source code is built specifically to handle:

- **TLS fingerprinting.** Airbnb sits behind Akamai/PerimeterX, which blocks plain `requests`/`aiohttp` traffic at the TLS (JA3) handshake layer before a request ever reaches the application. This actor uses `curl_cffi` with Chrome impersonation (`transport.py`) so every request replays a genuine Chrome TLS handshake.
- **A persisted-query hash that Airbnb rotates without notice.** The calendar call requires a `sha256Hash` value tied to the `PdpAvailabilityCalendar` operation. The actor ships a known-good hash and, if Airbnb rotates it, self-heals by scanning the room page's JS bundles and then the full asyncRequire chunk manifest (`discover_hash` / `scan_chunks_for_hash`) for a fresh one — a non-trivial reverse-engineering step to reproduce and keep maintained.
- **Soft-block detection.** An airlock, CAPTCHA, or empty response shell has to be told apart from a legitimate "no availability" response, or you silently harvest garbage. `detect_html_block` and `detect_calendar_block` key on the presence of expected bootstrap markers plus explicit block signatures, and the actor escalates to a fresh residential-proxy session on every soft block, retrying up to `4` bootstrap attempts and `3` calendar-fetch attempts per listing before giving up on it.

Build it yourself if you need a bespoke pipeline and have the engineering time to track Airbnb's endpoint changes indefinitely. Use this actor when you want the calendar data now, with the anti-bot and self-healing work already done.

### How to use data extracted from Airbnb?

#### Revenue managers and short-term-rental hosts

Point the actor at your own listing IDs with a 12-month `startDate`/`endDate` window and `includeDays: true`. The day rows give you every future `price` and `bookable` flag Airbnb currently shows guests, so you can catch pricing gaps (a stretch of days with `price: null` where a competitor's calendar is fully priced) or spot nights sitting `available` with no price set at all — a common symptom of a forgotten pricing rule.

#### Property management and STR agencies

Run the same actor across a client portfolio with `billingMode: "per_listing"` so the run's cost scales with listing count, not window length. Feed `roomId`, `unavailableRate`, and `revpar` from the parent rows into a recurring client report that benchmarks each managed unit against the others on the same schedule — weekly or monthly, on an Apify Schedule.

#### Market research and intelligence

Set `includeListingDetails: true` to pull `roomType`, `propertyType`, and `personCapacity` alongside the pricing metrics, then group `adr` and `revpar` by property type or capacity band across a sample of listings in a submarket to see which configurations command the highest realized asking rates — useful groundwork before an acquisition or a new-listing pricing strategy.

#### AI agents and automated pipelines

Because the actor is a standard Apify Actor invoked over `apify_client`, an agent framework can call it as a tool: pass a list of `listings` and a date window, get back typed JSON with `price`, `bookable`, and `unavailableRate` per listing, and feed that directly into a pricing-recommendation or booking-availability agent without any scraping code of its own.

### 🔼 Input sample

| Parameter | Required | Type | Description | Example value |
| --- | --- | --- | --- | --- |
| `listings` | **yes** | array | One listing per line — full room URL or bare numeric ID. | `["https://www.airbnb.com/rooms/35329051", "769824007018240779"]` |
| `startDate` | no | string | First calendar day to keep. Absolute (`2026-08-01`) or relative (`"7 days"`, `"1 month"`). Past dates are clamped to today since Airbnb's calendar is forward-only. Empty = today. | `"2026-08-01"` |
| `endDate` | no | string | Last calendar day to keep. Absolute or relative (`"3 months"`, `"1 year"`). Empty = `startDate` + 30 days. Airbnb serves up to roughly 12 months ahead. | `"2026-11-30"` |
| `billingMode` | no | string, enum `per_listing` | `per_day`, default `"per_listing"` | `per_listing` charges once per listing regardless of window length (recommended). `per_day` charges once per calendar-day row. Day rows are always produced either way — this only controls what is billed. | `"per_listing"` |
| `includeDays` | no | boolean, default `true` | When on, each calendar day is emitted as its own child row. Turn off to keep only the parent listing summary row. | `true` |
| `includeListingDetails` | no | boolean, default `false` | Adds title, room/property type, guest capacity, bedrooms/beds/bathrooms, and approximate coordinates to the parent row — best-effort, `null` when not exposed. | `false` |
| `includeHostProfile` | no | boolean, default `false` | Adds superhost flag, host name, and response rate to the parent row — best-effort, `null` when not exposed. | `false` |
| `proxyConfiguration` | no | object | Your proxy choice is honored as-is. Defaults to Apify residential proxy, which is strongly recommended — datacenter IPs are frequently blocked by Airbnb. | `{ "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }` |

```json
{
  "listings": ["https://www.airbnb.com/rooms/35329051", "769824007018240779"],
  "startDate": "2026-08-01",
  "endDate": "2026-11-30",
  "billingMode": "per_listing",
  "includeDays": true,
  "includeListingDetails": true,
  "includeHostProfile": false,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

**Common pitfall:** leaving `billingMode` on the default `per_listing` is deliberate — the input schema's own description warns that `per_day` on a 12-month window bills roughly 365 events per listing instead of one. Switch to `per_day` only when you specifically need to pay per calendar-day row rather than per listing. Separately, an in-the-past `startDate` is not an error: it is silently clamped to today with a warning logged to the run console, since `PdpAvailabilityCalendar` cannot return historical dates.

### 🔽 Output sample

Output is typed, normalized JSON with a consistent schema per row type, downloadable from the Apify Console or API as JSON, CSV, Excel, XML, RSS, or an HTML table. Day rows are also mirrored into a separate per-run dataset named `days-<runId>` when `includeDays` is on, in addition to the default dataset.

**Parent — `type: "listing"`** (one row per target, always produced):

```json
{
  "type": "listing",
  "isChild": false,
  "roomId": "35329051",
  "listingUrl": "https://www.airbnb.com/rooms/35329051",
  "windowStart": "2026-08-01",
  "windowEnd": "2026-10-31",
  "totalDays": 92,
  "availableDays": 40,
  "unavailableDays": 52,
  "unavailableRate": 0.5652,
  "adr": 128.5,
  "priceCoverage": "40/92",
  "pricedDays": 40,
  "estimatedRevenue": 6682.0,
  "revpar": 72.63,
  "minPrice": 110.0,
  "maxPrice": 210.0,
  "currency": "USD",
  "scrapedAt": "2026-07-26T14:03:00Z"
}
```

**Child — `type: "day"`** (one row per calendar day, only when `includeDays` is on):

```json
{
  "type": "day",
  "isChild": true,
  "parentId": "35329051",
  "roomId": "35329051",
  "listingUrl": "https://www.airbnb.com/rooms/35329051",
  "date": "2026-08-01",
  "dayOfWeek": "Saturday",
  "isWeekend": true,
  "available": false,
  "availableForCheckin": false,
  "availableForCheckout": true,
  "bookable": false,
  "minNights": 2,
  "maxNights": 365,
  "price": null,
  "currency": null,
  "scrapedAt": "2026-07-26T14:03:00Z"
}
```

`price` is always a real number or `null` — never `0` used as a stand-in for "no price." `unavailableRate`, `adr`, `estimatedRevenue`, and `revpar` follow the same rule on the parent row.

### How do you target specific Airbnb listings and date windows?

This actor doesn't discover new listings by category or search — you supply the `listings` you already know, and the real targeting happens in how you shape the calendar pull for each one:

1. **Listing identification.** Both full room URLs and bare numeric IDs work in the same `listings` array, so you can mix a scraped list of URLs with hand-typed IDs without normalizing them first.
2. **Window precision.** `startDate` and `endDate` accept either an absolute date or a relative offset (`"7 days"`, `"3 months"`, `"1 year"`), so a monitoring pipeline can request `"today"` through `"90 days"` on every run without hardcoding dates.
3. **Cost granularity, not just row volume.** `billingMode` is itself a targeting lever: `per_listing` keeps run cost proportional to your listing count regardless of how far out you look, while `per_day` ties cost to the number of calendar days actually returned — useful if you only care about a handful of pricing spot-checks.
4. **Row-shape control.** `includeDays` toggles whether you get per-day granularity at all; `includeListingDetails` and `includeHostProfile` add optional enrichment fields to the parent row without touching the day rows.

**A 90-day pricing snapshot, minimal cost:**

```json
{ "listings": ["35329051"], "startDate": "", "endDate": "90 days", "billingMode": "per_listing" }
```

**A full 12-month revenue-modeling pull, same per-listing cost as the snapshot above:**

```json
{ "listings": ["35329051"], "startDate": "today", "endDate": "1 year", "billingMode": "per_listing", "includeListingDetails": true }
```

**A bulk portfolio scan with only summary rows, no per-day detail:**

```json
{ "listings": ["35329051", "769824007018240779"], "includeDays": false, "includeListingDetails": true, "includeHostProfile": true }
```

### ▶️ Want to try other listing and marketplace scrapers?

This is currently the only Airbnb scraper published under the SimpleAPI catalogue. The closest comparable marketplace/listing scrapers in this catalogue:

| Scraper | What it extracts |
| --- | --- |
| [Amazon Best Sellers Scraper](../Amazon-Best-Seller-%26-Products-Scraper) | Amazon best-seller and product listing data, including pricing |
| [Amazon Seller Data Extractor Plus](../amazon-seller-data-extractor) | Amazon marketplace seller and listing data |

### How to extract Airbnb data programmatically

Every run is a standard Apify Actor call — one API call with your Apify token, structured JSON back. There is no separate Airbnb credential to manage; the actor authenticates to Airbnb's own calendar endpoint internally.

#### Python example

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run_input = {
    "listings": ["https://www.airbnb.com/rooms/35329051"],
    "startDate": "today",
    "endDate": "3 months",
    "billingMode": "per_listing",
}

run = client.actor("simpleapi/airbnb-availability-scraper").call(run_input=run_input)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item["type"] == "listing":
        print(item["roomId"], item["adr"], item["unavailableRate"])
```

#### Export to spreadsheets or CRM

Download the dataset as CSV directly from the Apify Console (or via the API's `?format=csv` dataset export) and import it into Google Sheets or a CRM. Map `roomId` and `listingUrl` as the join key, `date`/`price`/`bookable` for a per-night pricing sheet, or `roomId`/`adr`/`unavailableRate`/`revpar` for a one-row-per-listing revenue summary.

### Is it legal to scrape Airbnb?

Scraping publicly accessible Airbnb calendar and pricing data is generally lawful in most jurisdictions — this data is not behind a login and exists specifically to be shown to prospective guests. This actor returns listing and calendar data, which is business/product data rather than personal data, so it is governed primarily by Airbnb's Terms of Service and database-rights considerations rather than GDPR or CCPA. The exception is the optional `includeHostProfile` fields (`hostName`, `hostIsSuperhost`, `hostResponseRate`), which can include an identifiable individual's name — treat that subset with normal data-minimization care if you store or resell it, since it may fall under GDPR/CCPA depending on how you use it. Consult legal counsel for commercial applications involving bulk storage of personal data.

### ❓ FAQ

#### What happens if a listing is removed or delisted?

The actor doesn't emit a row with nulled-out fields for a delisted or blocked listing — it omits the listing entirely from the dataset and logs its `roomId` in the run's "Failed/blocked" summary line instead. Check the run log if a listing you submitted is missing from the output.

#### Can I get pricing data along with availability?

Yes, by default. Every day row already carries `price` (a real number or `null`), and the parent listing row carries `adr`, `minPrice`, `maxPrice`, `estimatedRevenue`, and `revpar`, all derived only from real calendar prices found in the window — no interpolation or regional averaging.

#### How accurate is the availability and pricing data?

The actor returns exactly what Airbnb's own calendar API returns at the moment of the request — the same data a browser would show a guest checking dates on that listing. Airbnb calendars change as bookings and host edits happen, so treat the data as a point-in-time snapshot and re-run the actor close to the dates you care about if freshness matters.

#### How many calendar days can I get per run?

There is no `maxItems`-style cap in the input schema on the number of listings or days. The practical ceiling is Airbnb's own calendar horizon — it serves availability roughly 12 months ahead — and the actor's internal request cap, which fetches at most 12 calendar months per listing per run (`months_span`, capped at `12` in `helpers.py`) to match what Airbnb's endpoint accepts in a single request.

#### What's the most useful targeting control here?

`billingMode` combined with the date window: setting `billingMode` to `"per_listing"` keeps cost tied to how many listings you track rather than how far out you look, which is the difference between a cheap monthly monitoring run and one that scales badly with a 12-month window. See "How do you target specific Airbnb listings and date windows?" above.

#### Why are there two row types, `listing` and `day`, in one dataset?

The parent `listing` row carries the window-level summary and derived metrics; the child `day` rows carry the per-day detail. Only the row type matching your `billingMode` is charged — under `per_listing`, day rows are still pushed to the dataset but generate no charge, and vice versa under `per_day`. Filter on `type` to work with either level independently.

#### Does Airbnb Availability Scraper work with Claude, ChatGPT, and AI agent frameworks?

It has no dedicated MCP server integration published for this actor. It is callable as a standard Apify Actor via `apify_client` or the Apify REST API from any agent framework that can make an HTTP call, so an agent can invoke it as a tool and parse the returned JSON directly.

#### How does Airbnb Availability Scraper compare to other Airbnb scrapers?

As observed on the Apify Store on 2026-07-26, `agenscrape/airbnb-availability-calendar` documents a single-listing-per-run input (`listingUrl`) with an `enrichWithPricing` toggle that adds tax and instant-book fields, and lists export integrations including Google Sheets, Zapier, Make, Slack, and webhooks; `oneary/airbnb-hotel-price-scraper` documents search-based discovery by location with filters for check-in/out dates, guests, and price range, returning up to a `maxListings` cap per its own schema; `rigelbytes/airbnb-availability-calendar` documents a single-URL input with a raw availability output and is billed as a flat monthly subscription rather than pay-per-event, per its own listing. This actor differs by accepting a batch `listings` array of URLs or bare IDs in one run, deriving `adr`/`estimatedRevenue`/`revpar` from real calendar prices rather than only surfacing per-day rates, and billing per listing regardless of window length by default.

#### Can I use Airbnb Availability Scraper without an Airbnb account or API key?

Yes. The actor needs only an Apify account and token to run — it fetches Airbnb's public room page and calendar endpoint the same way a signed-out browser would, with no Airbnb login, cookie, or developer credential required.

### Conclusion

Airbnb Availability Scraper turns a list of listing URLs or IDs into a structured, honestly-labeled availability and pricing calendar — real per-day fields from Airbnb's own API, derived revenue metrics that are `null` rather than faked when no price exists, and a billing mode that keeps cost predictable across any window length. It's built for revenue managers, STR agencies, and market researchers who need calendar data at scale without maintaining their own anti-bot pipeline against Airbnb's Akamai/PerimeterX defenses. Start a run from the [Apify Console](https://apify.com/simpleapi/airbnb-availability-scraper) or call it with `apify_client` using the Python example above.

# Actor input Schema

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

One listing per line. Full room URLs and bare numeric IDs both work. Example: \["https://www.airbnb.com/rooms/35329051", "769824007018240779"].

## `startDate` (type: `string`):

First calendar day to keep. Absolute (2026-08-01) or relative ("7 days", "1 month"). Airbnb's calendar is forward-only — past dates are clamped to today. Empty = today.

## `endDate` (type: `string`):

Last calendar day to keep. Absolute (2026-11-30) or relative ("3 months", "1 year"). Empty = start + 30 days. Airbnb serves up to ~12 months ahead.

## `billingMode` (type: `string`):

per\_listing = charged once per listing (recommended — avoids billing shock from ~30-365 per-day charges). per\_day = charged per calendar day row. Day rows are always produced; this only controls what is billed.

## `includeDays` (type: `boolean`):

When on (default), each calendar day is emitted as a child row (availableForCheckin/checkout, bookable, min/max nights, nightly price or null). Turn off to keep only the parent listing summary row.

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

Add title, room/property type, guest capacity, bedrooms/beds/bathrooms and approximate coordinates to the parent listing row (best-effort; null when not exposed).

## `includeHostProfile` (type: `boolean`):

Add host superhost flag / name / response rate to the parent listing row (best-effort; null when not exposed).

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

Your choice is honored. Defaults to Apify residential proxy (recommended). Datacenter IPs are frequently blocked by Airbnb.

## Actor input object example

```json
{
  "listings": [
    "35329051"
  ],
  "billingMode": "per_listing",
  "includeDays": true,
  "includeListingDetails": false,
  "includeHostProfile": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

All scraped items in the Actor's default dataset.

# 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"
    ],
    "startDate": "",
    "endDate": "",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

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

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

```

## MCP server setup

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