# Short-Term Rental Market Occupancy Estimator (Airbnb data) (`nimble_levi/str-market-occupancy-estimator`) Actor

Estimate Airbnb occupancy for any city or area: samples listings, reads calendars, returns monthly median occupancy % and median nightly price. STR market data.

- **URL**: https://apify.com/nimble_levi/str-market-occupancy-estimator.md
- **Developed by:** [Bogdan Glisici](https://apify.com/nimble_levi) (community)
- **Categories:** Travel, Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

## Short-Term Rental Market Occupancy Estimator (Airbnb data)

**Estimate Airbnb occupancy for a whole city or area in one run.** Enter a city (for example "Lisbon, Portugal") or a map bounding box. The actor samples active listings, reads each listing's public availability calendar, and returns the **market occupancy rate per month** (median, mean, 25th and 75th percentile) and the **median nightly price**. It's quick STR market data for investors, hosts and analysts, with no login or coding needed.

**Keywords:** airbnb occupancy rate by city, STR market data, short-term rental market analysis, vacation rental occupancy, airbnb market research, average daily rate.

### Use cases

- **Before buying an investment property:** see how busy the market really is for the next 1 to 6 months.
- **Comparing cities or neighbourhoods:** run the same input for several areas, or draw bounding boxes.
- **Hosts and property managers:** benchmark your own occupancy against the local median.
- **Market reports and dashboards:** schedule weekly runs and track booking pace.

### Input

```json
{ "location": "Brasov, Romania", "sampleSize": 36, "monthsAhead": 3 }
```

Or use a bounding box instead: `"boundingBox": {"neLat":44.46,"neLng":26.12,"swLat":44.42,"swLng":26.07}`.

### Output

- **Market summary**, in the key-value store as `MARKET_SUMMARY` (JSON) and `MARKET_SUMMARY_CSV` (CSV). Both are linked on the run's Output tab:

| month | listingsCounted | medianOccupancyPct | p25 | p75 | medianNightlyPrice |
|---|---|---|---|---|---|
| 2026-10 | 10 | 73.7 | 55.2 | 78.9 | 123.07 USD |
| 2026-11 | 10 | 20.0 | 17.5 | 36.7 | 123.07 USD |

*(Real test results for Brașov, 13 Oct 2026, 10 listings sampled.)*

- **Sampled listings** (dataset): one row per listing per month with listingId, name, lat/lng, rating, nightlyPrice, occupancyPct and blockedNights.

### How occupancy is estimated

Occupancy = blocked nights ÷ nights counted. Airbnb's public calendar does not separate booked nights from nights the host blocked, so treat it as an upper-bound estimate. Past days and months beyond a host's booking window are excluded. The nightly price is the rate shown in search for Airbnb's default sample dates.

### Pricing

**$0.03 per listing sampled**, covering all requested months. A 36-listing city snapshot costs about $1.08.

### Tips

- Use a sample of 30 to 100 listings for stable medians.
- If a run reports a bot check, wait for the automatic no-proxy retry first; use Apify **Residential** only if that still fails.
- For per-listing calendars, see **Vacation Rental Calendar & Occupancy** by nimble_levi.

### Troubleshooting

- **Bot check / "Search page returned no listing data":** Airbnb sometimes serves a soft block on Apify datacenter proxies. The actor automatically retries with **no proxy**, then (if still blocked) with **Residential**. Prefer letting that ladder run; only set `proxyConfiguration.apifyProxyGroups` to `["RESIDENTIAL"]` if no-proxy also fails (Residential costs more).
- **Empty results for a known city:** The actor tries location variants (with/without diacritics), then a **Nominatim geocode → map bounding-box** search. You can also pass `boundingBox` yourself (`neLat`/`neLng`/`swLat`/`swLng`).
- **Which proxy actually worked?** Each run logs `Proxy used` / `fallbackPath`, and writes `proxyMode`, `searchStrategy`, and `fallbackPath` into `MARKET_SUMMARY` and the `OUTPUT` key-value record (e.g. `datacenter→none` means the no-proxy fallback succeeded).
- **Proxy options:** default is Apify datacenter (`useApifyProxy: true`); `useApifyProxy: false` forces direct; Residential is last-resort only.

*Airbnb is a trademark of Airbnb, Inc. This tool is independent and not affiliated with Airbnb.*

# Actor input Schema

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

e.g. 'Brasov, Romania'. Ignored if a bounding box is given.

## `boundingBox` (type: `object`):

{"neLat":..,"neLng":..,"swLat":..,"swLng":..}

## `sampleSize` (type: `integer`):

Listings taken from search results (18 per page).

## `monthsAhead` (type: `integer`):

Calendar months to analyse, starting with the current month.

## `outputListings` (type: `boolean`):

outputListings

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

currency

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

maxConcurrency

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

proxyConfiguration

## Actor input object example

```json
{
  "location": "Brasov, Romania",
  "sampleSize": 36,
  "monthsAhead": 3,
  "outputListings": true,
  "currency": "USD",
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `marketSummary` (type: `string`):

One row per month: median/mean/p25/p75 occupancy and median nightly price.

## `marketSummaryCsv` (type: `string`):

No description

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

One row per listing per month with price, rating, coordinates and occupancy.

# 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": "Brasov, Romania"
};

// Run the Actor and wait for it to finish
const run = await client.actor("nimble_levi/str-market-occupancy-estimator").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": "Brasov, Romania" }

# Run the Actor and wait for it to finish
run = client.actor("nimble_levi/str-market-occupancy-estimator").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": "Brasov, Romania"
}' |
apify call nimble_levi/str-market-occupancy-estimator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nimble_levi/str-market-occupancy-estimator"
        }
    }
}
```

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/MiF9a7eq5YX54fC5N/builds/NvAJfNmWvnof13dqj/openapi.json
