# Airbnb Calendar & Occupancy Scraper: Occupancy Rate, Revenue (`thelastscraper/airbnb-calendar-occupancy`) Actor

Airbnb availability calendar (12-13 months), occupancy rate and revenue estimates for listing URLs/IDs or a whole area. One flat row per listing plus day-by-day calendar. Charged per listing, not per day.

- **URL**: https://apify.com/thelastscraper/airbnb-calendar-occupancy.md
- **Developed by:** [The Last Scraper](https://apify.com/thelastscraper) (community)
- **Categories:** Travel, Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 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/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 Calendar & Occupancy Scraper

Get the **availability calendar**, the **occupancy rate** and **revenue estimates** of Airbnb
listings: paste listing URLs or IDs, or type a whole area ("Dubai Marina, Dubai"). You get one
flat row per listing, ready for Excel or Google Sheets, plus a day-by-day calendar.

- **Charged per listing and month, not per day.** A listing with its occupancy row and 12
  months of daily rows costs $0.0055 on the Free plan ($0.0042 on Gold), or $0.0025 ($0.0012)
  with the occupancy row only. Calendar Actors that charge per day cost about $1.10 per listing
  and year.
- **Occupancy you can defend.** Two methods, never mixed: the share of unavailable days in the
  next 30/60/90 (and 365) days, an upper bound because Airbnb does not tell bookings from host
  blocks, and the reviews-based "San Francisco model" used by Inside Airbnb. Each comes with its
  confidence.
- **Revenue estimates** from the asked daily rate (a real price quote for your dates) times each
  occupancy figure, clearly labelled as estimates.
- **Whole areas** with the neighborhood's real boundary, no 270-result cap.
- **Every listing, not only the free ones.** An Airbnb search with dates only returns the homes
  still free on those nights, so the busiest ones go missing and area occupancy comes out too
  low. By default this Actor finds every active listing with a search without dates and then
  quotes each one for your dates (booked ones come with `available_on_quote_dates = false` and
  no quote).
  "Only listings available on your dates" is the cheaper, biased alternative.

### How to use it

1. **Listings or area:** listing URLs/IDs, places or Airbnb search URLs, one per line.
2. **Calendar months:** 12 (one request per listing; the 365-day window stays empty, because
   Airbnb's calendar starts on the 1st of the current month) or 13 (one more small request, full
   365-day window).
3. **Daily calendar rows** (on by default): one row per listing and day in the calendar
   dataset. Turn it off for the occupancy rows only, at less than half the price.
4. Optional: dates and guests for the price quote (empty dates = 30 days from today, 5 nights;
   children, infants and pets like on airbnb.com), filters for areas (bedrooms, bathrooms, beds,
   type of place, amenities, free cancellation), and **Also deliver the full listing record**
   (no extra charge).

```json
{ "where": ["Dubai Marina, Dubai"], "calendarMonths": "12", "bedroomsExact": 2, "currency": "AED", "maxListings": 100 }
```

### What you get

- **Default dataset, one row per listing:** title, URL, neighborhood, bedrooms, rating, review
  count; quote dates, total and per night; calendar horizon; available/unavailable days for the
  next 30/60/90/365 days; next available date; minimum nights; `occupancy_calendar_30/60/90/365`;
  `occupancy_reviews_model`; `adr`; monthly and annual revenue estimates; RevPAR.
- **calendar dataset** (Daily calendar rows): one row per listing and day: available,
  check-in/check-out allowed, minimum and maximum nights.
- **listings dataset** (optional): the full listing record.

### Price

Pay-per-event prices per 1,000 events, by Apify plan:

| Event | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
| `listing-details`: per listing (its occupancy row is built from the listing page and price quote; the full record too if you ask for it) | $1.50 | $1.30 | $1.00 | $0.70 |
| `calendar`: per listing with its calendar and occupancy row | $1.00 | $0.75 | $0.60 | $0.50 |
| `calendar-days`: per listing and month of daily rows (Daily calendar rows, on by default) | $0.25 | $0.25 | $0.25 | $0.25 |

Example: 500 listings with their 12-month calendar, occupancy rows and daily rows: $2.75 on the
Free plan, $2.10 on Gold ($1.25 / $0.60 without the daily rows). By area or by URL, the same
price. Listings that fail are not charged.

### Related Actors

- [Airbnb Scraper](https://apify.com/thelastscraper/airbnb-scraper): everything in one run, with a
  free cost estimate.
- [Airbnb Reviews Scraper](https://apify.com/thelastscraper/airbnb-reviews): guest reviews, $0.50 per
  1,000.
- [Airbnb Listing Details Scraper](https://apify.com/thelastscraper/airbnb-listing-details): full
  listing data and price by URL.

Public data only, no login. Not affiliated with Airbnb.

# Actor input Schema

## `actorVariant` (type: `string`):

Internal: which Store Actor this is (do not change).

## `where` (type: `array`):

One per line: a listing URL (https://www.airbnb.com/rooms/123) or ID, a place as you would type it on Airbnb ("Dubai Marina, Dubai") or an Airbnb search URL. Places are resolved with their real OpenStreetMap boundary.

## `calendarMonths` (type: `string`):

12 months = one request per listing: the next 30/60/90 days are complete and the 365-day window stays empty (Airbnb's calendar starts on the 1st of the current month). 13 months = one more small request (~16 KB) and the full 365-day window.

## `calendarDays` (type: `boolean`):

One row per listing and day in the 'calendar' dataset (about 365 per listing): available, check-in/check-out allowed, minimum and maximum nights. Charged as calendar-days: $0.25 per 1,000 listing-months, so $3.00 per 1,000 listings for 12 months. Off: only the occupancy row per listing.

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

Every occupancy row is built from the listing's page and price quote, so each listing is charged as listing details plus calendar. On: the full listing record too (description, amenities, host, rules, permit, price breakdown) in the 'listings' dataset, at no extra charge.

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

YYYY-MM-DD. Used to quote the price that feeds the revenue estimate (ADR). Empty = automatic dates (30 days from today, 5 nights). For an area, the default 'Which listings' (All active listings) searches without dates and quotes every listing for these dates; with 'Only listings available on your dates', the search uses these dates and returns only the homes still free on those nights.

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

YYYY-MM-DD, after the check-in date. Empty with an empty check-in = automatic dates (each record says so in scrape.dates_auto).

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

Adult guests. Airbnb keeps the listings that accommodate at least this many people (4 also brings listings for 5, 6 or more guests) and quotes each price for exactly this party. 0 = any number of guests: no capacity filter, each price quoted for one guest (cannot be combined with Children).

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

Ages 2-12. They count toward the listing's capacity like adults and pay the extra-guest fee in the quote.

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

Under 2. They do not count toward capacity and stay free.

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

Only pet-friendly listings are returned, and the quote includes the host's pet fee (folded into the nightly rate).

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

ISO 4217 code (default USD). All amounts are returned as numbers in this currency; it also replaces the currency of an Airbnb search URL.

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

Stop after this many listings (areas can have thousands). 0 = no limit.

## `coverage` (type: `string`):

All listings (default): every active listing in the area, found with a search without dates and quoted for your dates; homes already booked on your dates are included, which is what keeps occupancy unbiased. Only available: a search with your dates (fewer listings, cheaper), but it misses exactly the homes that are booked, so area occupancy comes out too low.

## `bedroomsExact` (type: `integer`):

Keep only listings with exactly this many bedrooms. Airbnb only filters by minimum, so the Actor asks Airbnb for at least this many and checks the exact number on each search card or, when the card does not show it (in Europe a search without dates shows the host type there instead), on the listing page. Listings that do not match are not delivered or charged.

## `minBedrooms` (type: `integer`):

Airbnb's own filter ("N or more").

## `minBathrooms` (type: `number`):

Airbnb's own filter ("N or more"); half bathrooms count as 0.5.

## `minBeds` (type: `integer`):

Airbnb's own filter ("N or more").

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

Leave empty for any type.

## `amenities` (type: `array`):

Keep only listings with ALL the amenities picked (Airbnb's own filter). With listing URLs or IDs the Actor checks them on the listing page; what the page cannot confirm is kept with a FILTER_UNVERIFIED warning. Amenity ids of other markets work inside an Airbnb search URL (amenities\[]=...).

## `freeCancellation` (type: `boolean`):

Keep only listings with free cancellation for your dates (Airbnb's own filter; with listing URLs or IDs, checked on the cancellation policy).

## `proxyStrategy` (type: `string`):

Auto (recommended): starts with Apify datacenter proxies and switches to residential proxies only if Airbnb starts blocking (2 blocks in the last 50 requests: a request blocked on 2 datacenter IPs makes its third attempt through residential); after 300 clean requests on residential it tries datacenter once more. If residential proxies are not available to the run, it slows down instead. Datacenter / Residential: always that kind. Proxy traffic is not billed to you separately: the event prices include it. The log, the status message and the OUTPUT record show requests, blocks and estimated traffic per proxy level.

## `proxyCountry` (type: `string`):

Optional 2-letter country code for residential proxies. Empty = US, like the datacenter proxies: Airbnb shows totals before taxes to visitors outside the EU, so every run's prices mean the same. An EU country (e.g. DE) makes Airbnb show totals with taxes (the taxes column fills in). Prices are always in the selected currency.

## `omitPersonalData` (type: `boolean`):

Only matters with 'Also deliver the full listing record' (the occupancy rows have no host or reviewer fields): host and co-host names, photos and bios are set to null and the host's name is replaced with "the host" in Airbnb-generated texts. GDPR-friendly. Business data (ratings, Superhost, years hosting, license numbers) stays.

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

Listings scraped at the same time, each through its own Apify Proxy IP with its own pause (a listing's price quote, policies and calendar are requested together with its page, as a browser loads it). 20 to 32; the default, 32, scrapes about 5 listings a second with the default 4 GB of memory. The minimum keeps a run's duration, which the event prices include, bounded. With your own proxy URLs or without a proxy (one IP), the pause is shared and more parallel listings are not faster.

## `delaySeconds` (type: `integer`):

Minimum seconds between two requests from the same IP (plus up to 1 s of random jitter); a listing's quote, policies and calendar go out with its page. 1 (the default, the fastest) or 2. If Airbnb blocks, the Actor slows down and changes proxies by itself.

## `maxRequests` (type: `integer`):

Hard cap on requests to airbnb.com for the whole run (retries included). 0 = no cap.

## Actor input object example

```json
{
  "actorVariant": "calendar-occupancy",
  "where": [
    "Dubai Marina, Dubai"
  ],
  "calendarMonths": "12",
  "calendarDays": true,
  "includeListingDetails": false,
  "adults": 2,
  "children": 0,
  "infants": 0,
  "pets": 0,
  "currency": "AED",
  "maxListings": 3,
  "freeCancellation": false,
  "proxyStrategy": "auto",
  "omitPersonalData": false,
  "maxConcurrency": 32,
  "delaySeconds": 1,
  "maxRequests": 0
}
```

# Actor output Schema

## `occupancy` (type: `string`):

One row per listing.

## `calendar` (type: `string`):

One row per listing and day (Daily calendar rows, on by default).

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

Only with 'Also deliver the full listing record'.

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

OUTPUT record: what was scraped, charged events, proxy levels and why the run stopped.

# 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 = {
    "where": [
        "Dubai Marina, Dubai"
    ],
    "currency": "AED",
    "maxListings": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("thelastscraper/airbnb-calendar-occupancy").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 = {
    "where": ["Dubai Marina, Dubai"],
    "currency": "AED",
    "maxListings": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("thelastscraper/airbnb-calendar-occupancy").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 '{
  "where": [
    "Dubai Marina, Dubai"
  ],
  "currency": "AED",
  "maxListings": 3
}' |
apify call thelastscraper/airbnb-calendar-occupancy --silent --output-dataset

```

## MCP server setup

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

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/Cdgj0U3s1qR3txd7I/builds/QrNUX8W3WQ58KvvN3/openapi.json
