# Airbnb Availability Calendar Scraper - Prices, Listings (`snow_leo_data/airbnb-scraper`) Actor

Airbnb scraper past the 270-row search ceiling: 1916 unique listings where flat pagination returns 257, measured in 117 seconds. The paginated reviews route returns all 105 reviews of a listing where the older route returns 7. 12-month availability calendar. Airbnb occupancy rate data.

- **URL**: https://apify.com/snow\_leo\_data/airbnb-scraper.md
- **Developed by:** [Snow Leo Data](https://apify.com/snow_leo_data) (community)
- **Categories:** Travel, Real estate, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.90 / 1,000 listings

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 Scraper — listings, prices, availability calendar and reviews

Airbnb's own search hands out at most **270 rows per query**: the response
carries exactly 15 page cursors of 18 rows, and those 270 rows contain **227
distinct listings**, because the same card is repeated across pages. That is the
ceiling every Airbnb scraper hits, and the largest competitor says so in its own
README: *"up to 240 results for one search query"*.

This Actor goes past it with an adaptive map grid. Measured on 2026-09-13,
query `Paris, France`, this Actor's own crawler:

| Mode | Queries | Unique listings |
|---|---|---|
| Flat pagination (`gridSplit: off`) | 7 | 257 |
| Adaptive map grid (`gridSplit: auto`) | 63 | **1 916** |

**7.46x more listings** in 117 seconds.

Everything else rides in the same row: listing page details, the day-by-day
availability calendar with occupancy rates, and every review. One dataset row
per listing, whether that row carries 0 reviews or 200.

#### What you get

A single flat row per listing. A full run produced **108 top-level columns**
and **164 leaf paths** (arrays expanded one level) on 2026-09-13. The dataset
schema declares 133 fields in total, because some of them only exist when the
source publishes them.

Core identity and location: `listing_id`, `url`, `android_url`, `ios_url`,
`name`, `title`, `seo_title`, `meta_description`, `latitude`, `longitude`,
`location_subtitle`, `location_is_exact`, `location_descriptions`.

Property shape: `room_type` ("Entire home/apt", "Private room"),
`property_type`, `space_type`, `home_tier`, `person_capacity`,
`max_guest_capacity`, `bedrooms`, `beds`, `baths`, `overview_title`,
`overview_items`, `sleeping_arrangements`, `is_new_listing`, `is_luxe`,
`is_hotel_property`, `structured_content`.

Price: `price_label`, `price_amount`, `price_per_night`, `price_currency`,
`price_nights`, `price_qualifier`, `price_original_label`,
`price_original_amount`, `price_is_discounted`, `price_breakdown`,
`available_dates_label`. Set `checkIn` and `checkOut` and the price becomes the
real total for those dates instead of an estimate.

Quality: `rating`, `reviews_count`, `rating_label`, `rating_accuracy`,
`rating_checkin`, `rating_cleanliness`, `rating_communication`,
`rating_location`, `rating_value`, `badges`, `is_guest_favorite`.

Amenities and rules: `amenities` (grouped, with icon and availability flag),
`amenity_names`, `amenities_count`, `amenities_unavailable`, `house_rules`,
`house_rules_additional`, `check_in_after`, `check_out_before`,
`self_check_in`, `max_guests_rule`, `smoking_allowed`, `parties_allowed`,
`pets_allowed`, `pets_allowed_rule`, `max_pet_count`, `safety_items`,
`accessibility_features`, `highlights`, `cancellation_policies`.

Host: `host_id`, `host_name`, `host_title`, `host_is_superhost`,
`host_is_verified`, `host_photo`, `host_rating`, `host_reviews_count`,
`host_rating_count`, `host_years_hosting`, `host_months_hosting`,
`host_highlights`, `host_about`, `host_response_rate`, `host_response_time`,
`host_is_airbnb_managed`, `host_can_be_messaged`, `cohosts`.

Text and photos: `description_text`, `description_html`,
`description_sections`, `description_language`, `images` (with Airbnb's own
photo tags such as `Living_room`), `images_count`, `search_images`, `thumbnail`.

Availability: `calendar_days` (date, available, bookable, check-in allowed,
check-out allowed, minimum and maximum nights), `calendar_days_scanned`,
`calendar_first_date`, `calendar_last_date`, `available_days_30`,
`available_days_60`, `available_days_90`, `available_days_365`,
`occupancy_rate_30`, `occupancy_rate_60`, `occupancy_rate_90`,
`occupancy_rate_365`, `min_nights_median`, `next_available_date`,
`next_blocked_date`.

Reviews: `reviews` (id, rating, full text, date, language, reviewer name, photo,
profile link, tenure, host response), `reviews_total`, `reviews_returned`,
`reviews_average_returned`, `review_languages`, `review_topics`,
`latest_review_at`.

Run bookkeeping: `change_type` in incremental mode, `locale`, `currency`,
`scraped_at`.

#### How the ceiling is broken

The search endpoint accepts a map rectangle (`ne_lat`, `ne_lng`, `sw_lat`,
`sw_lng`) instead of a text query, and each rectangle gets its own 270-row
budget. So the Actor takes the rectangle Airbnb itself reports for your
location, splits it, and walks the cells.

The split is adaptive rather than fixed. A cell is divided again only when it
**filled its own budget** and **brought listings that were not seen before**.
Splitting an empty cell would spend queries on nothing, and splitting a cell
whose listings were all duplicates would spend them on rows you already have.
Cells go three levels deep at most.

The rectangle itself is not guessed. Airbnb returns a `mapBoundsHint` with the
answer, but that hint is narrower than the real city — for Paris it gives
48.827–48.901 while the listings actually run 48.806–48.904. So the Actor takes
the union of the hint and the bounding box of the listings that came back, and
pads it. The bounds used are written into `REPORT.grid_bounds` so you can check
them.

Duplicates are removed by listing id before anything is written, and the count
of repeats the source sent is reported as `duplicates_from_source`. On the Paris
measurement the source sent 571 repeats inside 1 916 unique listings.

You can turn the grid off (`gridSplit: off`) when you only need a quick sample,
or force a side (`2` to `6`) when you know the area.

#### Reviews without the 7-review trap

The old public endpoint `/api/v2/homes_pdp_reviews` still answers HTTP 200 and
looks like a full review feed. It is not. Measured on listing
`1431944184823200762`, which has 105 reviews: it returns **7** reviews and
ignores `_offset` entirely — offset 0 and offset 7 return the same seven rows.
A scraper built on it silently caps every listing at seven reviews and reports
success.

This Actor uses the paged reviews query that the listing page itself uses:
24 rows on the first page, 50 on the next, zero overlap between them, all 105
reachable. It also returns `review_topics`, Airbnb's own topic tags with
counts (`Location 58`, `Hospitality 58`, `Cleanliness 37` on that listing),
which no competitor in the niche exposes.

Reviews live inside the listing row. Fifty reviews cost exactly as much as
zero, because you are charged per listing.

#### Availability and occupancy

`includeCalendar` adds the day-level calendar, up to 12 months — 12 is the
source's own cap per request, read out of its JavaScript. Each day carries
`available`, `bookable`, `available_for_checkin`, `available_for_checkout`,
`min_nights` and `max_nights`.

From those days the Actor computes occupancy rates for 30, 60, 90 and 365 days.
A window is only reported when the calendar actually covers it: asking for 3
months will not produce a "365-day occupancy" figure computed from 91 days,
because such a number looks annual and is not.

This is what makes the Actor usable for short-term-rental market research:
`occupancy_rate_90` plus `price_per_night` over a whole city is a revenue
estimate, and it comes from the source rather than from a model.

#### Filters, and where each one runs

Filters that Airbnb itself understands are sent to Airbnb, so non-matching
listings are never collected and never charged: `priceMin`, `priceMax`,
`minBedrooms`, `minBeds`, `minBathrooms`, `roomTypes`, `propertyTypes`,
`amenities` (36 ids), `hostLanguages` (70 languages), `guestFavoriteOnly`,
`instantBookOnly`, `checkIn`/`checkOut` and the guest counts. The amenity and
language lists were read out of Airbnb's own filter panel rather than typed by
hand, so the ids match the site exactly.

Filters Airbnb does not accept run here, after collection: `minRating`,
`minReviewsCount`, `minPricePerNight`, `maxPricePerNight`, `nameContains`,
`excludeKeywords`, `requiredAmenities`, `superhostOnly`, `maxOccupancy30`,
`minAvailableDays30`.

Two rules govern them, and both exist because breaking them has cost real
buyers real money:

**A missing field is not a mismatch.** A listing with no rating yet passes
`minRating`. Measured: with `minPricePerNight: 900000` on Lisbon, 34 of 37
listings were dropped and 3 survived — the three that publish no nightly price.
Dropping them would have been a silent lie about the data.

**`maxItems` counts delivered rows, not scanned ones.** Filters run before the
count, so asking for 20 listings with a filter returns 20 listings, not an empty
dataset.

Filters that depend on the listing page or the calendar are applied in two
stages: whatever the search result can already decide is decided **before** the
listing page is fetched, so the Actor does not pay for a page it is about to
throw away.

#### Monitoring mode

`onlyNew` makes the Actor remember what earlier runs delivered, in a named key
value store that survives between runs. The next run writes only listings that
are new or whose price, nightly price, rating, review count, occupancy or
availability changed, and stamps each row with `change_type`
(`NEW` / `UPDATED` / `UNCHANGED`).

The description is deliberately not part of the change fingerprint: the source
edits invisible details in it, and every listing would look "updated" every day.

A monitoring run that finds nothing new is supposed to return zero rows — that
is the point, you do not pay twice for the same row. So the Actor **names** the
reason instead of leaving a silent empty dataset.

#### Named reasons for an empty dataset

A green run with an empty dataset is the worst kind of failure: the buyer pays
for the start, receives nothing and cannot tell why. `REPORT.empty_reason` is
always set when the dataset is empty, to one of six values:

- `contradictory-input` — the input could not return rows whatever the source
  answered. Detected **before the first network request**, so nothing is
  downloaded and nothing beyond the run start is charged. Example:
  `superhostOnly` with `includeDetails: false` — the superhost flag lives on the
  listing page, so every row would be dropped for a field that was never
  fetched. The exact sentences are in `REPORT.input_problems`.
- `charge-limit-reached` — your spending limit for the run was already used up.
- `filtered-out` — listings were collected and your filters removed all of them.
  `REPORT.filtered_out` says which filter removed how many.
- `nothing-changed` — incremental mode, everything had already been delivered.
- `source-returned-nothing` — Airbnb returned no listings for this search.
- `nothing-collected` — listings were seen but none survived to the dataset.

#### Reliability

Airbnb's GraphQL operations are addressed by a signature that changes with every
frontend release. Hardcoding one turns a scraper into a time bomb. This Actor
pins the current signatures, and when Airbnb rejects one it reads the fresh
signature out of the site's own JavaScript bundles and retries once. Proved by
setting the search signature to 64 zeros: the run recovered in 35.7 seconds and
`REPORT.operation_hashes` showed `bundle` instead of `pinned`.

Rows are written to the dataset **before** they are marked as delivered, so an
interrupted run never loses rows; the leftovers arrive on the next run.

#### Input examples

Whole city, everything on:

```json
{
  "locationQueries": ["Austin, Texas"],
  "maxItems": 1000,
  "includeDetails": true,
  "includeCalendar": true,
  "calendarMonths": 12,
  "includeReviews": true,
  "maxReviews": 50
}
```

Daily price monitor for a set of listings:

```json
{
  "startUrls": [
    "https://www.airbnb.com/rooms/1431944184823200762",
    "https://www.airbnb.com/rooms/20669368"
  ],
  "includeCalendar": true,
  "calendarMonths": 3,
  "onlyNew": true
}
```

Market scan with source-side filters only:

```json
{
  "locationQueries": ["Lisbon, Portugal"],
  "maxItems": 500,
  "roomTypes": ["Entire home/apt"],
  "minBedrooms": 2,
  "amenities": ["4", "5", "7"],
  "priceMax": 250,
  "includeDetails": false,
  "compactOutput": true
}
```

#### FAQ

**How many listings can I get from one city?**
More than the 270 Airbnb's own search will show you. Measured on Paris: 1 916
unique listings in 63 queries and 117 seconds. Bigger orders keep splitting the
map until either the order is filled or the query budget runs out; the budget
and how it was spent are in `REPORT`.

**Do reviews cost extra?**
No. Reviews are part of the listing row, so a listing with 200 reviews is one
dataset row, same as a listing with none.

**Why did I get fewer rows than `maxItems`?**
Either the area genuinely has fewer listings, or your filters removed them.
`REPORT.filtered_out` names the filter and the count; `REPORT.targets` gives the
unique listings collected per target and the queries spent.

**Do I need proxies?**
No. The Actor uses no proxies and no browser. It was verified from Apify's own
cloud IPs before a line of it was written, because a source that answers from a
laptop does not always answer from a datacenter.

**Which currency are prices in?**
The one you pick in `currency` (30 supported). Without it, prices come back in
the currency Airbnb picks for the run's IP address, which makes rows from
different runs incomparable.

**Can I scrape a single listing I already have the URL for?**
Yes. Put it in `startUrls`, or put the numeric id in `listingIds`.

**Does it work for hotels on Airbnb?**
Yes. Hotel rooms are returned with `is_hotel_property: true`; some of them
publish no nightly price, and those rows carry `price_per_night: null` rather
than a guess.

**How fresh is the availability calendar?**
It is read live at run time. `calendar_first_date` and `calendar_last_date` show
the exact window, and `scraped_at` timestamps the row.

#### Limitations, named honestly

**No separate service fee or "total before taxes".** The largest competitor
returns `price.breakDown.serviceFee` and `price.breakDown.totalBeforeTaxes`.
Measured 2026-09-13 with check-in and check-out set: the search response now
carries only the "N nights x rate" line plus any resort fee, and the listing page
returns `structuredDisplayPrice: null` until a separate booking query runs in the
browser. Airbnb moved to all-in nightly display pricing. This Actor reports what
the source returns and does not invent the split.

**Prices for direct listing URLs are the listing-page price.** When you pass a
room URL or a listing id without a location search, the dated price breakdown
that the search response carries is not available, because that breakdown only
exists in search results. Pass a location query with `checkIn`/`checkOut` if you
need dated totals.

**Exact coordinates are approximate before booking.** Airbnb publishes an offset
location for most listings; `location_is_exact` tells you which ones are exact.

**A made-up place name does not fail — it fuzzy-matches.** Measured: searching
`Zzqqxxnotaplaceatall, Nowhere` returns a full page of 40 real listings rather
than an error. Check `location_subtitle` on the rows if you are unsure whether
the spelling was understood.

**Search results are not stable between runs.** Airbnb reshuffles the order, so
two runs with a small `maxItems` will not return the same listings. Use
`listingIds` or `startUrls` when you need a fixed set.

**The 365-day occupancy needs a 12-month calendar.** With `calendarMonths: 3`
the 365-day figures are simply absent rather than extrapolated.

**Review text is returned in the language it was written in**, plus Airbnb's
translation when the source provides one. `review_languages` lists what came
back.

#### What else is this called?

Names buyers use: Airbnb scraper, Airbnb availability calendar, Airbnb occupancy data, short-term rental occupancy, STR data, Airbnb reviews scraper. The calendar covers twelve months ahead, and the occupancy shares are computed from it.

Other names for the fields: cleaning fee and price breakdown (`price_breakdown`), occupancy rate for a short-term rental (`occupancy_rate_30`, `occupancy_rate_90`), superhost dataset (`host_is_superhost`), pet friendly rentals data (`pets_allowed`), nightly rate history (`price_per_night`). Those occupancy and price fields are the raw data people use for rental arbitrage research; the Actor returns the numbers, it does not do the analysis.

# Actor input Schema

## `locationQueries` (type: `array`):

Places to search, written the way you would type them into Airbnb: "Paris, France", "Austin, Texas". Airbnb's own search stops at 270 rows per query; anything larger is split into a map grid automatically.

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

Paste Airbnb search URLs (filters in the URL are read and reused) or room URLs (https://www.airbnb.com/rooms/123...).

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

Numeric Airbnb listing ids, if you already have them.

## `maxItems` (type: `integer`):

How many listings to write to the dataset. Filters below are applied BEFORE this count, so you get what you asked for, not what was scanned. 0 runs as a 20-listing trial.

## `gridSplit` (type: `string`):

How to get past Airbnb's 270-row search ceiling. Auto splits only when the flat pages run out; a fixed number forces that grid side.

## `includeDetails` (type: `boolean`):

Amenities, house rules, host profile, ratings by category, description, photos, accessibility. One extra request per listing.

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

Day-by-day availability with minimum and maximum nights, plus occupancy rates for 30/60/90/365 days computed from it.

## `calendarMonths` (type: `integer`):

1 to 12. Airbnb's own calendar query caps at 12 months per request.

## `includeReviews` (type: `boolean`):

Full review text, ratings, reviewer and host response. The old public endpoint stops at 7 reviews per listing; this uses the paged query instead.

## `maxReviews` (type: `integer`):

Reviews arrive 50 at a time. Reviews do not cost extra — they ride in the listing row.

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

YYYY-MM-DD. Prices become the real total for these dates. Must be given together with check-out.

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

YYYY-MM-DD.

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

Number of adults the price should be quoted for.

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

Number of children (2-12) the price should be quoted for.

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

Number of infants (under 2) the price should be quoted for.

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

Number of pets. Listings that do not accept pets drop out on Airbnb's side.

## `priceMin` (type: `integer`):

Per night, in the currency below. Sent to Airbnb.

## `priceMax` (type: `integer`):

Per night, in the currency below. Sent to Airbnb.

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

Sent to Airbnb, so smaller listings are never collected.

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

Sent to Airbnb, so smaller listings are never collected.

## `minBathrooms` (type: `integer`):

Sent to Airbnb, so smaller listings are never collected.

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

Leave empty for all.

## `propertyTypes` (type: `array`):

Ids read out of Airbnb's own filter panel. Leave empty for all.

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

36 amenity filters read out of Airbnb's own filter panel. Sent to Airbnb, so non-matching listings are never charged.

## `hostLanguages` (type: `array`):

70 languages, taken from Airbnb's filter panel.

## `guestFavoriteOnly` (type: `boolean`):

Only listings Airbnb marks as a guest favourite. Sent to Airbnb.

## `instantBookOnly` (type: `boolean`):

Only listings that can be booked without host approval. Sent to Airbnb.

## `minRating` (type: `integer`):

Airbnb has no rating filter, so this one runs on our side after collection. Listings with no rating yet are kept, not dropped.

## `minReviewsCount` (type: `integer`):

Runs on our side. Listings with no reviews yet are kept, not dropped.

## `minPricePerNight` (type: `integer`):

Runs on our side. Listings that publish no nightly price are kept.

## `maxPricePerNight` (type: `integer`):

Runs on our side. Listings that publish no nightly price are kept.

## `nameContains` (type: `array`):

Matched against title, subtitle and description.

## `excludeKeywords` (type: `array`):

Matched against title, subtitle and description. Any hit drops the row.

## `requiredAmenities` (type: `array`):

Free text, matched against the listing page amenities. Needs listing page details on.

## `superhostOnly` (type: `boolean`):

Needs listing page details on — the flag lives on the listing page.

## `maxOccupancy30` (type: `integer`):

Needs the availability calendar on.

## `minAvailableDays30` (type: `integer`):

Needs the availability calendar on.

## `onlyNew` (type: `boolean`):

Remembers what earlier runs delivered in a named store and writes only listings that are new or whose price, rating, review count or occupancy changed. Made for daily monitoring: you do not pay twice for the same row.

## `emitUnchanged` (type: `boolean`):

Only meaningful together with the option above.

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

Prices are returned in this currency. Without it Airbnb picks one from the run's IP address, which makes runs incomparable.

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

Language for titles, descriptions and amenity names.

## `compactOutput` (type: `boolean`):

17 core columns instead of the full record — for AI agents and quick market scans.

## `excludeEmptyFields` (type: `boolean`):

Drop keys whose value is null or empty from every row.

## Actor input object example

```json
{
  "locationQueries": [
    "Paris, France"
  ],
  "maxItems": 20,
  "gridSplit": "auto",
  "includeDetails": true,
  "includeCalendar": false,
  "calendarMonths": 3,
  "includeReviews": false,
  "maxReviews": 20,
  "adults": 1,
  "children": 0,
  "infants": 0,
  "pets": 0,
  "guestFavoriteOnly": false,
  "instantBookOnly": false,
  "superhostOnly": false,
  "onlyNew": false,
  "emitUnchanged": false,
  "currency": "USD",
  "locale": "en",
  "compactOutput": false,
  "excludeEmptyFields": false
}
```

# Actor output Schema

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

All collected rows

# 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 = {
    "locationQueries": [
        "Paris, France"
    ],
    "maxItems": 20,
    "includeDetails": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("snow_leo_data/airbnb-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 = {
    "locationQueries": ["Paris, France"],
    "maxItems": 20,
    "includeDetails": True,
}

# Run the Actor and wait for it to finish
run = client.actor("snow_leo_data/airbnb-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 '{
  "locationQueries": [
    "Paris, France"
  ],
  "maxItems": 20,
  "includeDetails": true
}' |
apify call snow_leo_data/airbnb-scraper --silent --output-dataset

```

## MCP server setup

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