# Airbnb Occupancy & Dynamic Pricing Monitor (`laced_kirtan/airbnb-occupancy-pricing`) Actor

Reads public Airbnb listing/search HTML for calendar availability, blocked-date proxy occupancy, nightly prices, and cleaning fees.

- **URL**: https://apify.com/laced\_kirtan/airbnb-occupancy-pricing.md
- **Developed by:** [Shwetanshu Mehta](https://apify.com/laced_kirtan) (community)
- **Categories:** Real estate, Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 listing occupancy records

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?

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 & Dynamic Pricing Monitor

This Actor reads public Airbnb listing/search HTML and the public calendar request used by the listing page. It returns availability observations, currency-aware nightly pricing, cleaning fees, blocked dates, and price shifts. Because a blocked date may be an owner block, maintenance, or a booking, confirmed occupancy and revenue remain `null`; the Actor reports defensible minimum/maximum ranges instead.

### Input

```json
{
  "location": "Scottsdale, Arizona",
  "monthsToLookAhead": 3,
  "includeBlockedDates": true,
  "currency": "USD",
  "locale": "en-US",
  "maxRetries": 2,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

You can instead provide `listingIds`, explicit public `startUrls`, or `geo` coordinates plus a radius; `location` is no longer required when one of those inputs is present. `currency` is sent to Airbnb as a display preference; values are not converted locally. Explicit same-origin pagination links are followed up to `maxPages`. Failed or challenged page/calendar requests get at most `maxRetries` retries. Proxying is opt-in; when enabled, each attempt uses a fresh proxy session. Public-site markup and anti-bot behavior can change; challenge pages are detected, retries are bounded, and CAPTCHAs are never solved or bypassed. Unexpected empty listing/calendar responses are reported as bounded, query-stripped warnings in `RUN_SUMMARY` instead of being silently treated as healthy. The Actor does not use private accounts or invent availability.

### Output

Each record contains `listingId`, `title`, `avgDailyRate`, `currency`, pricing/calendar provenance, next-30-day calendar coverage, blocked rates, `occupancyEstimateRangePct`, `estimatedMonthlyRevenueRange`, cleaning fee, availability counts, blocked dates, price range, quality score, `pricingDataAvailable`, and charge status. USD aliases are populated only when the currency is explicitly USD. Partial calendar coverage widens the upper bound instead of pretending unobserved nights are available.

The `listing-record` paid event is emitted only when at least 21 of the next 30 dates have explicit availability and the record also has an explicit nightly rate plus ISO currency. Calendar-only observations remain in the dataset for diagnosis but are not charged; `chargeabilityReason` explains why.

`occupancyRateNext30Days` and `estimatedMonthlyRevenueUsd` intentionally remain `null`: public availability cannot distinguish a reservation from a host block. For example, 8 blocked nights across 30 observed days produces an occupancy range of 0–26.7%, not a claim of 26.7% occupancy.

### Resource controls

- Listing maps are capped before detail fetches; one page is fetched at a time.
- Response bodies are streamed with hard timeouts and byte limits.
- Calendar entries are capped at 600 per listing and deduplicated by date.
- Optional proxy dispatchers are short-lived and closed after each request attempt.
- Records are emitted immediately after each listing is computed.

### Monetization

The manifest declares `listing-record` at $0.0025 per useful record ($2.50 per 1,000). Records with fewer than 21 observed next-30-day calendar dates, or without explicit rate/currency data, are returned for transparency but not charged.

### Local development

```bash
npm install
npm test
npm run check
apify validate-schema .actor/input_schema.json
apify run --purge
```

# Actor input Schema

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

Search location such as Scottsdale, Arizona.

## `monthsToLookAhead` (type: `integer`):

Calendar horizon used to observe pricing changes and calculate a next-30-day blocked-date upper bound.

## `includeBlockedDates` (type: `boolean`):

Include the bounded list of unavailable dates exposed by public calendar data. These dates are not asserted to be bookings.

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

Three-letter ISO currency requested from public search and calendar responses. Values are not converted locally.

## `locale` (type: `string`):

Language or language-region code used for public Airbnb responses, such as en-US or fr-FR.

## `listingIds` (type: `array`):

Optional direct listing IDs. When provided, direct public listing pages are processed.

## `geo` (type: `object`):

Use latitude/longitude and radius to create a public Airbnb search URL when a location string is not precise enough.

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

Public Airbnb search or listing URLs to use instead of the generated location URL.

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

Hard cap on listing records retained and emitted.

## `maxPages` (type: `integer`):

Hard cap on public search/listing pages fetched before listing detail processing.

## `maxRetries` (type: `integer`):

Bounded retries after failed or challenged public page/calendar requests. A fresh proxy session is used for each attempt when proxying is enabled; CAPTCHAs are detected but never solved or bypassed.

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

Optional Apify Proxy or custom proxy URLs for public Airbnb page and calendar requests. Residential proxy access can improve availability but adds proxy traffic cost.

## `requestTimeoutSecs` (type: `integer`):

Timeout per public search or listing page request.

## `maxResponseBytes` (type: `integer`):

Reject oversized public pages before embedded-data parsing.

## Actor input object example

```json
{
  "location": "Scottsdale, Arizona",
  "monthsToLookAhead": 1,
  "includeBlockedDates": true,
  "currency": "USD",
  "locale": "en-US",
  "listingIds": [],
  "geo": {},
  "startUrls": [],
  "maxListings": 1,
  "maxPages": 1,
  "maxRetries": 1,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "requestTimeoutSecs": 15,
  "maxResponseBytes": 6000000
}
```

# Actor output Schema

## `records` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

# 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 = {
    "monthsToLookAhead": 1,
    "maxListings": 1,
    "maxPages": 1,
    "maxRetries": 1,
    "proxyConfiguration": {
        "useApifyProxy": false
    },
    "requestTimeoutSecs": 15
};

// Run the Actor and wait for it to finish
const run = await client.actor("laced_kirtan/airbnb-occupancy-pricing").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 = {
    "monthsToLookAhead": 1,
    "maxListings": 1,
    "maxPages": 1,
    "maxRetries": 1,
    "proxyConfiguration": { "useApifyProxy": False },
    "requestTimeoutSecs": 15,
}

# Run the Actor and wait for it to finish
run = client.actor("laced_kirtan/airbnb-occupancy-pricing").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 '{
  "monthsToLookAhead": 1,
  "maxListings": 1,
  "maxPages": 1,
  "maxRetries": 1,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "requestTimeoutSecs": 15
}' |
apify call laced_kirtan/airbnb-occupancy-pricing --silent --output-dataset

```

## MCP server setup

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

```

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/6rmEcULpAgVbTYHhJ/builds/12VkddZ1fdke6kJd4/openapi.json
