# Airbnb Market Intel Scraper (`aurenic/airbnb-market-intel-scraper`) Actor

Extract Airbnb listings, prices, ratings, and occupancy data from any market. HTTP-only, no browser. Parse the SSR StaysSearch payload for prices, GPS coordinates, and optional 12-month calendars turned into occupancy and revenue estimates.

- **URL**: https://apify.com/aurenic/airbnb-market-intel-scraper.md
- **Developed by:** [Aurenic](https://apify.com/aurenic) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 results

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

## Airbnb Market Intel Scraper

Extract Airbnb listings, prices, ratings, and occupancy data from any market. HTTP-only, no browser. Parse the SSR `StaysSearch` payload for prices, GPS coordinates, and optional 12-month calendars turned into occupancy and revenue estimates.

### What does Airbnb Market Intel Scraper do?

Scrape short-term rental market data from Airbnb in two modes:

- **Search listings by market** — pass a location (`Austin, Texas`) and dates, get every listing with price (nightly + total + discount), rating, reviews, bedrooms, GPS coordinates, and badges. **Walks the search pagination** up to Airbnb's ~270-listing cap.
- **Listing detail** — pass listing URLs, get the full 365-day availability calendar turned into **occupancy 30/60/90, ADR, RevPAR, and estimated monthly/annual revenue** — AirDNA-style metrics for STR investors and property managers.

**HTTP-only, no browser.** Airbnb ships its full search response as an inline `<script id="data-deferred-state-0">` payload in the HTML — the same JSON the React app would fetch. The actor reads it directly, backed by residential proxy rotation to clear PerimeterX.

### Output fields

#### Listing (search mode)

| Field | Description |
|---|---|
| listingId | Numeric Airbnb listing ID |
| url | Direct room URL |
| name | Listing name |
| roomType / propertyType | Room and property classification |
| rating / reviewsCount | Average rating and review count |
| priceTotal | Total price for the date range |
| priceNightly | Derived nightly rate |
| priceOriginalTotal / discountPercent | Discount info |
| latitude / longitude | GPS coordinates |
| bedrooms / beds / baths / maxGuests | Capacity |
| isSuperhost | Superhost flag |
| badges | Guest favorite, etc. |
| picture | Primary photo URL |
| searchLocation / checkIn / checkOut / nights | Search context |

#### Listing Intel (detail mode)

Everything above, plus:
| Field | Description |
|---|---|
| calendar | 365-day availability array |
| occupancy30 / occupancy60 / occupancy90 | % booked in each window |
| adr | Average daily rate |
| revpar | Revenue per available room |
| estimatedMonthlyRevenue | RevPAR × 30 |
| estimatedAnnualRevenue | RevPAR × 365 |

### Who is it for?

- **STR investors** running AirDNA-style comps for acquisition underwriting
- **Property managers** benchmarking rates against the market
- **Revenue managers** tracking nightly pricing and occupancy trends
- **Market researchers** analyzing supply and pricing by neighborhood
- **Real estate developers** evaluating short-term rental yields
- **Travel platforms** enriching destination pages with market context

### Pricing

**$2.50 per 1,000 results.** No subscription.

| Results | Cost |
|---|---|
| 100 | $0.25 |
| 1,000 | $2.50 |
| 10,000 | $25.00 |

### How to use it

1. Pick a **Mode**.
2. For search: enter one or more **Locations** and set **Check-in** / **Check-out**.
3. For detail: paste **Listing URLs**.
4. Optionally set bedrooms, price, and property type filters.
5. Click **Start**.

### Output example

```json
{
  "recordType": "listing",
  "listingId": "1652957843916333450",
  "url": "https://www.airbnb.com/rooms/1652957843916333450",
  "name": "Stylish Pool Home 4BR Near Siesta Key",
  "roomType": "Entire home/apt",
  "rating": 5.0,
  "reviewsCount": 8,
  "priceTotal": 3190,
  "priceNightly": 638,
  "priceOriginalTotal": 3544,
  "discountPercent": 10,
  "latitude": 27.30754,
  "longitude": -82.52108,
  "bedrooms": 4,
  "beds": 4,
  "baths": 3,
  "maxGuests": 8,
  "isSuperhost": true,
  "badges": ["Guest favorite"],
  "searchLocation": "Siesta Key, Florida",
  "checkIn": "2026-10-15",
  "checkOut": "2026-10-20",
  "nights": 5,
  "scrapedAt": "2026-09-26T12:00:00.000Z"
}
```

### Technical details

- **Airbnb serializes its GraphQL cache as inline JSON** in `<script id="data-deferred-state-0">`. The search response lives at `niobeClientData[*][1].data.presentation.staysSearch.results.searchResults`. The actor parses that directly — no DOM scraping, no selectors that break on redesign.
- **Listing IDs are base64-encoded** in `demandStayListing.id`. Decoded → `DemandStayListing:{id}` → numeric room ID.
- **`/api/v3/StaysSearch` GraphQL is NOT called.** Persisted-query hashes rotate and require device fingerprinting. The SSR script tag carries the same response, served inline. This is the entire moat.
- **Bot check detection** — if the response lacks `data-deferred-state-0`, Airbnb served a PerimeterX shell. The actor rotates the residential proxy session and retries up to 8 times.
- **Residential proxy is mandatory.** Airbnb blocks datacenter IPs. The actor defaults to Apify RESIDENTIAL with US country.
- **~270-listing cap** per search. Airbnb paginates via `items_offset` up to 252 (15 pages × 18). For larger markets, split by neighborhood or price band and dedupe by `listingId`.
- **PDP data shape is different** — the listing page uses `StaysPdpSections`, not `StaysSearch`. The actor has a separate decoder for detail mode.

### Known limits

- **Prices are for the requested stay, not a nightly rate.** The actor derives `priceNightly` by dividing by nights. This is an approximation — Airbnb applies length-of-stay discounts.
- **Currency depends on the proxy's IP country.** The actor defaults to US residential, so prices are USD. Set `apifyProxyCountry` in code for other markets.
- **~270 listings max per search.** Larger markets need subdivision. Map-bounded searches (`search_by_map=true`) return a more precise count and allow quadtree splitting.
- **`includeCalendar` requires detail mode.** Calendar parsing walks the PDP sections array. Some listings have the calendar behind a stub section; those return `calendarDays: 0`.
- **Price and currency shift by IP location.** The actor pins US residential; results are USD. Some non-US listings may return null prices.
- **No reviews extraction.** Reviews live on a separate XHR. Planned for a future release.

### FAQ

**Do I need an Airbnb account?** No. Public data only.

**Do I need a proxy?** Yes. Airbnb blocks datacenter IPs with PerimeterX. Residential proxy is pre-configured.

**Why no browser?** Airbnb ships the full search payload inline in the HTML. Parsing that is faster and more reliable than running a headless browser.

**How do I cover a whole city that has more than 270 listings?** Split into narrower searches — by neighborhood, price band, or map bounding box — and dedupe by `listingId` across runs.

**What are occupancy and RevPAR?** Occupancy = % of nights booked in the window. ADR = average daily rate. RevPAR = ADR × occupancy. Estimated monthly revenue = RevPAR × 30. These are the standard STR investment metrics.

**How do I export data?** After a run, go to Storage → Export as JSON, CSV, Excel.

### Support

Open an issue on the Actor's page for bugs or feature requests.

# Actor input Schema

## `mode` (type: `string`):

What to fetch.

## `locations` (type: `array`):

Markets to search, e.g. 'Austin, Texas', 'Lisbon, Portugal', 'Joshua Tree, California'. The actor builds /s/{slug}/homes URLs automatically.

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

YYYY-MM-DD. Prices and availability require dates.

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

YYYY-MM-DD.

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

Number of adult guests. Affects pricing and availability.

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

Optional minimum bedroom filter.

## `maxBedrooms` (type: `integer`):

Optional maximum bedroom filter.

## `minPrice` (type: `integer`):

Optional minimum nightly price filter (USD).

## `maxPrice` (type: `integer`):

Optional maximum nightly price filter (USD).

## `propertyType` (type: `string`):

Optional Airbnb property type filter (e.g. 'Entire home/apt').

## `listingUrls` (type: `array`):

Airbnb listing URLs (https://www.airbnb.com/rooms/12345). Used in detail mode.

## `maxListingsPerLocation` (type: `integer`):

Airbnb caps search results at ~270 per query. Lower this for faster test runs.

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

When on, detail mode computes occupancy 30/60/90, ADR, RevPAR, and estimated monthly revenue from the 365-day availability calendar.

## `requestDelayMs` (type: `integer`):

Delay between requests. Residential proxy rotation costs latency; 800ms is a reasonable balance.

## Actor input object example

```json
{
  "mode": "search",
  "locations": [
    "Austin, Texas"
  ],
  "checkIn": "",
  "checkOut": "",
  "adults": 2,
  "listingUrls": [],
  "maxListingsPerLocation": 270,
  "includeCalendar": true,
  "requestDelayMs": 800
}
```

# Actor output Schema

## `results` (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 = {
    "locations": [
        "Austin, Texas"
    ],
    "listingUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("aurenic/airbnb-market-intel-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 = {
    "locations": ["Austin, Texas"],
    "listingUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("aurenic/airbnb-market-intel-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 '{
  "locations": [
    "Austin, Texas"
  ],
  "listingUrls": []
}' |
apify call aurenic/airbnb-market-intel-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,aurenic/airbnb-market-intel-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/xzt86MW57lyeIkj7c/builds/T8i3Nbze6PkbJue4V/openapi.json
