# Airbnb Scraper: Listings, Prices, Fees, Calendar & Reviews (`thelastscraper/airbnb-scraper`) Actor

Scrape Airbnb listings by location, map area, search URL or listing URL. Exact stay prices as numbers with breakdown, host ratings, permit numbers, availability calendar, occupancy estimates and reviews.

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

## Pricing

from $0.25 / 1,000 search results

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 Scraper: Listings, Prices, Fees, Calendar & Reviews

Scrape **Airbnb listings** for any city, neighborhood, map area, search URL or listing URL,
and get **exact stay prices as numbers** (nightly rate, subtotal, discounts, total, per
night, and whether cleaning and service fees are included), full listing details,
**host ratings**, **registration / permit numbers**, an optional **availability calendar
with occupancy estimates** and **guest reviews**: all in one run, with no login and no
browser.

- **Three questions, no manual.** Where (a neighborhood, a city, an Airbnb URL or listing
  IDs), when (or leave it empty: automatic dates so there is always a price) and how much
  detail, from a free estimate to everything. Pay only for the level you pick.
- **Know the cost before you pay.** The free **Estimate** level counts the listings in your
  area in seconds and tells you what each level would cost, before you pay anything.
- **The whole market of an area in one run.** Search results, listing pages, 12-month
  calendar with occupancy, and every review, for a few dollars: Dubai Marina, the 635
  two-bedroom apartments free on our test dates, with calendar and 8,925 reviews, costs
  **$6.69** on the Free plan ($3.15 on Gold), plus $0.50 if you keep the market report on,
  versus ~$750 combining the other Airbnb Actors.
- **Every listing, not only the free ones.** An Airbnb search with dates only shows the homes
  still free on those nights, so the busiest homes, already booked, are missing and the area
  looks emptier than it is. From Details up the Actor finds every active listing with a search
  without dates and then quotes each one for your dates: booked homes come with
  `price.is_available: false` and no price, and their calendar and reviews still count.
- **Spreadsheet-ready by default.** One flat row per listing with 98 curated columns in a
  useful order: the listing link first, `listing_id` as text (long ids survive), prices as
  numbers, key amenities as true/false, estimates marked `est_`. Download as Excel, CSV or JSON.
  Developers can switch **Output format** to Full JSON for the complete nested record.
- **Prices you can put in a spreadsheet.** `total`, `price_per_night`, `nightly_rate`,
  `discounts_total` and an ISO `currency` (in Full JSON: `price.total`,
  `price.price_per_night`...), never "$1,234" text. Every line Airbnb shows is kept and
  typed, and `fees_included_in_rate` tells you that cleaning and service fees are inside the
  nightly rate (how Airbnb shows prices today).
- **The same price meaning on every run and every row.** Airbnb shows totals with taxes to
  visitors from the EU and before taxes to everyone else, so the same listing can look like two
  prices. The Actor always asks as a visitor from the US, and `total` is **before taxes** on
  every row, comparable from one run to the next. Even to US visitors Airbnb itemizes the taxes
  of some listings (about 15 % of the Dubai quotes in our runs): that amount goes to the `taxes`
  column and stays out of `total` (total + taxes = what the guest pays). Want the taxes of every
  listing? Set **Proxy strategy: Residential only** and **Proxy country** to an EU country: the
  `taxes` column fills in. In Full JSON, `price.total` is Airbnb's Total line as shown (with the
  taxes it itemized) and `price.total_before_taxes` is always before taxes.
- **No 270-result cap.** Airbnb never shows more than ~270 results for one search. The
  Actor counts the listings in the map area and splits it into smaller areas until each part
  is under the cap, then removes duplicates. The run summary shows how many listings Airbnb
  announced and how many were collected.
- **Same area every run.** Locations are resolved with OpenStreetMap boundaries (Airbnb's own
  map area changes from one request to the next), so scheduled runs are comparable.
- **Compliance data.** The registration or permit number shown on the listing (e.g. Dubai
  DET/DTCM holiday home permits) as its own field, with a format check and duplicates across
  listings.
- **Honest estimates.** Occupancy, revenue and cleaning fee are labeled as estimates, each
  with its method, assumptions and a confidence level.

### What data can I get from Airbnb?

| Group | Fields |
|---|---|
| Listing | ID, URL, app links (iOS and Android), title, description (text and HTML), property type, type of place, guests, bedrooms, beds, bathrooms, sleeping arrangements; optionally title, description, amenities and house rules in one of Airbnb's 66 languages |
| Location | Coordinates (Airbnb blurs most of them, flagged by `coordinates_exact`), neighborhood, city, country, area text, inside-the-searched-area flag |
| Price (with dates) | Nightly rate, subtotal, discounts, total (before taxes: see above), original (struck-through) total, per night, per guest and per bedroom, typed line items, fees-included flag; for your adults, children, infants and pets; why a listing cannot be booked for your dates ("Minimum stay is 3 nights") |
| Ratings | Overall rating, review count, the six category ratings, Guest favorite, review tags |
| Host | Superhost, verified, host rating, host's total reviews, years hosting, response rate and time, co-hosts, languages, "lives in", work and business label (when the listing page shows them), professional-host signals, and from the host's profile the total number of listings on Airbnb (free) or the whole profile: years on Airbnb, sign-up month, verifications (names and photos can be omitted) |
| Rules | Check-in and check-out times, max guests, pets, smoking, events, min/max nights (from Revenue up: they come with the calendar), instant book, cancellation policy |
| Amenities | Every amenity with a stable key and its group, plus a boolean map of key amenities (pool, parking, kitchen, washer...) |
| Photos | Photo URLs with room and caption: the whole gallery or a quick preview (**Photos**), never image files |
| Compliance | Registration / permit / license number, jurisdiction, format check, listings sharing the same number (annotations dataset or Delivery: end) |
| Calendar (Revenue, Everything) | Summary per listing: available/unavailable days for the next 30/60/90 days (and 365 with Everything), next available date. With **Daily calendar rows**, per day: available, check-in allowed, check-out allowed, bookable, minimum and maximum nights |
| Reviews (Everything) | Text, original text and language, translation flag, date, stars, reviewer tenure, stay type, host response. Summary per listing: reviews per month, last 12 months, languages, host response rate |
| Estimates | ADR, occupancy (calendar and reviews methods, kept apart), monthly and annual revenue, RevPAR, cleaning fee (optional), Dubai tax breakdown (only with totals with taxes, from an EU proxy country), price and rating vs. the other listings of the run |

### How do I scrape Airbnb listings?

1. Click **Try for free**.
2. **Where?** Type one or more places (`Dubai Marina, Dubai`), paste Airbnb search URLs or
   listing URLs, or listing IDs, one per line, in the same box. The Actor detects which is
   which.
3. **When and who?** Pick check-in and check-out dates and the guests (adults, children,
   infants and pets, like on airbnb.com), or leave the dates empty: the Actor uses automatic
   dates (30 days from today, 5 nights) so Airbnb quotes a price, and every record says so
   (`scrape.dates_auto`). Guests work like Airbnb's filter: 4 adults brings every listing for 4
   or more people (5, 6, 8...), each priced for 4. **Adults 0** = any number of guests: no
   capacity filter, each listing priced for one guest.
4. **How much detail?** Choose a level: **Estimate** (free count and cost), **Snapshot**
   (search results), **Details** (full listing page), **Revenue & occupancy** (+ calendar),
   **Everything** (+ all reviews) or **Find management leads** (ranked leads for property
   managers). Add filters if you want: bedrooms (minimum or exact),
   bathrooms, beds, type of place, property type, amenities, price range, free cancellation,
   only available on your dates, minimum rating, Superhosts only. Pick a **Language** to also
   get the listing texts in it.
5. Click **Start** and download the results as JSON, CSV, Excel or HTML, or read them through
   the API. Not sure about the cost? Run **Estimate** first: it is free and takes seconds.

### How pricing works

**Start with the free Estimate.** Set the level to **Estimate**: in a few seconds the run
counts the listings in your area and shows what each level would cost on your plan, without
charging anything. Then pick the level and run it for real.

**You only pay for delivered results.** Listings that fail, listings your filters drop and
duplicates are not charged; there is no subscription and no platform usage on top. Set a
**maximum cost per run** in the run options and the Actor stops cleanly before going over it,
keeping everything collected so far.

Typical runs, in USD (Free plan / Gold plan):

| run | what you get | cost |
|---|---|---|
| 100 listings in a neighborhood, level Details | full listing page and exact price for your dates | $0.25 / $0.10 |
| 1,000 listings, level Revenue & occupancy | + 12-month calendar, occupancy and revenue estimates | $3.50 / $1.45, + $0.50 for the market report |
| Dubai Marina, the 635 two-bedroom homes free on our test dates, level Everything | + all 8,925 reviews | $6.69 / $3.15, + $0.50 for the market report |
| A daily monitor of 600 listings, level Revenue & occupancy | first run, then every daily run | $2.10 / $0.87, then $0.90 / $0.42 a day |
| 10 specific listings by URL, level Details | full page and price | $0.015 / $0.007 |

By level of detail, per 1,000 listings found by a search:

| Level | What you get | Free plan | Gold plan |
|---|---|---|---|
| **Estimate** | how many listings match and what each level would cost | **free** | **free** |
| **Snapshot** | search card: price for your dates, rating, capacity, location, photos | $1.00 | $0.25 |
| **Details** | + full listing page: price breakdown, cancellation, host, amenities, rules, permit | $2.50 | $0.95 |
| **Revenue & occupancy** | + 12-month availability calendar, occupancy and revenue estimates; when your dates are booked part of the time, an indicative price per night of their free periods | $3.50 | $1.45 |
| **Everything** | + every guest review and a 13-month calendar | $3.50 + $0.50 per 1,000 reviews | $1.45 + $0.25 per 1,000 reviews |
| **Find management leads** | Revenue & occupancy + the lead score, ranked, and the LEADS table (reviews read, not charged) | $3.50 | $1.45 |

Listings given by URL or ID have no search card: Details, Revenue and Everything cost $1.00
less per 1,000 (Free plan). **Daily calendar rows** (one row per listing and day, off by
default; the occupancy and revenue estimates come without them) add $0.25 per 1,000
listing-months on every plan: $3.00 per 1,000 listings for 12 months.

**Free periods of a stay that is booked part of the time.** From Revenue & occupancy up, when
your dates are not available because some nights are booked (say 1-30 November, booked the 1st
to the 9th), the Actor quotes each free period inside them on its own (10-30 November) and gives
an indicative price per night of those free nights, before taxes (`free_price_per_night`, with
`free_nights_quoted`; each period in the full record's `price.free_periods`). The same when the
nights are free but the listing does not accept your check-in or check-out day, or that many
nights: the bookable stay inside your dates is quoted. Airbnb shows no price per day, so it is
the average of each free period: a short period carries its whole cleaning fee, and a host can
price a single night far above the rest, so look at the periods themselves when one matters. No
extra charge. In monitoring, a listing gets them the first time it is delivered, not on its
re-checks. The run's status says how many of the listings booked on your dates have such a
price.

Under the hood these are pay-per-event prices per 1,000 events, by Apify plan (Pricing tab;
Platinum and Diamond pay the Gold price):

| Event | When it is charged | Free | Bronze | Silver | Gold |
|---|---|---|---|---|---|
| `listing` | each unique listing found by a search | $1.00 | $0.60 | $0.40 | $0.25 |
| `listing-details` | each listing with its full page and price quote | $1.50 | $1.30 | $1.00 | $0.70 |
| `calendar` | each listing with its availability calendar | $1.00 | $0.75 | $0.60 | $0.50 |
| `calendar-days` | **Daily calendar rows** only: each month of a listing's daily rows (12 months = 12 events) | $0.25 | $0.25 | $0.25 | $0.25 |
| `review` | each review | $0.50 | $0.40 | $0.30 | $0.25 |
| `host-profile` | **Host profile: Full** only: the host's whole public profile, once per unique host in a run (the default listing count of the host is free) | $1.00 | $0.80 | $0.60 | $0.50 |
| `listing-update` | monitoring only: each listing already delivered by the same monitor and checked again in a later run, changed or not | $1.50 | $1.30 | $1.00 | $0.70 |
| `market-report` | the market report of a run (on by default for Revenue & occupancy, Everything and Find management leads) | $0.50 per report | $0.50 | $0.50 | $0.50 |

**A real example.** Dubai Marina, every 2-bedroom entire home available for 5 nights in
November 2026 (635 listings) with the full listing page, the availability calendar and all
8,925 reviews (level Everything): **$6.69 on the Free plan, $3.15 on Gold**, plus $0.50 for
the market report (on by default at this level; set **Market report** to Off to skip it).
With the default **Which listings: All active listings**, the same run also returns the
2-bedroom homes already booked on those nights: more listings, so a higher cost (the free
Estimate shows both counts). The same data with the most popular Airbnb
Actors (the leading listing scraper plus its reviews Actor, plus a calendar Actor that charges
per day and per listing) costs about **$749 / $723**, almost all of it for the calendar.

| Same 635 listings | This Actor (Free / Gold) | Other Airbnb Actors on the Store (Free / Gold) |
|---|---|---|
| Search results only | $0.64 / $0.16 | $1.59 / $0.79 |
| Full listing pages | $1.59 / $0.60 | $2.54 / $0.64 |
| + 12-month calendar, 365 daily rows per listing | $4.13 / $2.83 | ~$704 / ~$702 (calendar charged per day) |
| + 8,925 reviews | $8.59 / $5.06 | ~$749 / ~$723 |

The market report ($0.50 per run, on by default for Revenue & occupancy, Everything and Find
management leads) is not
included in this comparison: the other Actors do not offer one.

To be fair: the leading listing scraper costs less than this one on the Platinum and Diamond
plans for listing pages ($0.75 and $0.50 against $0.95 per 1,000) and has a much longer track
record; one calendar Actor quotes a price for each
day, which this Actor does not (Airbnb's public calendar has no daily prices without a login);
and one all-in-one Actor bundles calendar and reviews for less per row, with a naive occupancy
figure. Competitor prices as published on the Apify Store on 2026-10-14.

Listings that fail, and listings dropped by your filters, are not returned and not charged.
Duplicates are charged once. With a **maximum cost per run**, the Actor estimates the cost of
each listing before fetching it, stops cleanly when the next one would not fit, and keeps
everything collected so far.

### Input example

```json
{
  "where": ["Dubai Marina, Dubai"],
  "checkIn": "2026-11-10",
  "checkOut": "2026-11-15",
  "adults": 2,
  "dataLevel": "revenue",
  "currency": "AED",
  "roomTypes": ["Entire home/apt"],
  "minBedrooms": 2,
  "bedroomsExact": 2,
  "maxListings": 700,
  "omitPersonalData": true
}
```

First, how many and how much? (free):

```json
{
  "where": ["Dubai Marina, Dubai"],
  "dataLevel": "estimate",
  "bedroomsExact": 2,
  "currency": "AED"
}
```

Specific listings and a search URL in the same box, everything, automatic dates:

```json
{
  "where": [
    "https://www.airbnb.com/rooms/614178316141803089",
    "23491570",
    "https://www.airbnb.com/s/Paris/homes?min_bedrooms=2"
  ],
  "dataLevel": "everything",
  "maxReviewPages": 2,
  "minRating": 4.8,
  "photos": "full"
}
```

### Output example

**Spreadsheet (default).** One flat row per listing in the default dataset, always the same
98 columns in the same order (`null` when unknown; with a **Language** picked, two more right
after `title`: `title_localized` and `description_localized`), so a sheet or a CSV import keeps
working from run to run. Real output for a Dubai Marina listing (5 nights, 2 adults, AED, level
Revenue & occupancy, `omitPersonalData` on), abridged:

```json
{
  "url": "https://www.airbnb.com/rooms/614178316141803089",
  "listing_id": "614178316141803089",
  "title": "Stunning Marina View | High Floor Apartment",
  "property_type": "serviced_apartment",
  "property_type_label": "Entire serviced apartment",
  "room_type": "entire_home",
  "city": "Dubai",
  "building": "Al Murjan Tower",
  "guests": 4, "bedrooms": 2, "beds": 2, "bathrooms": 2.0,
  "check_in": "2026-11-10", "check_out": "2026-11-15", "nights": 5,
  "currency": "AED",
  "nightly_rate": 1286.65,
  "price_per_night": 1286.65,
  "price_per_night_before_taxes": 1286.65,
  "taxes": null,
  "total": 6433.27,
  "total_original": 8334,
  "fees_included_in_rate": true,
  "is_available": true,
  "rating": 4.76, "review_count": 21,
  "rating_cleanliness": 4.71, "rating_location": 4.86, "rating_value": 4.62,
  "superhost": false,
  "host_id": "<host id>",
  "host_name": null,
  "cancellation_policy": "non_refundable",
  "instant_book": true,
  "license_number": "DUB-AL-HDTDQ",
  "has_pool": true, "has_gym": true, "has_parking": true, "has_marina_view": true,
  "photo_count": 21, "photos_complete": true,
  "available_days_30": 11, "available_days_90": 66,
  "est_occupancy_calendar_30": 0.6333,
  "est_adr": 1286.65,
  "est_revenue_monthly_calendar": 24771,
  "warning_codes": "LOCATION_TEXT_HIDDEN | NO_TAX_LINE | PERSONAL_DATA_OMITTED",
  "scraped_at": "2026-10-14T11:23:23Z",
  "record_type": "listing"
}
```

**Full JSON** (`outputFormat: full_json`). The complete record: 200+ fields grouped in blocks,
and **every key is always present** (`null` when unknown). Real output for the same listing
(5 nights, 2 adults, AED, level Everything, `estimateCleaning` on, `omitPersonalData` on):

```json
{
  "record_type": "listing",
  "listing_id": "614178316141803089",
  "url": "https://www.airbnb.com/rooms/614178316141803089",
  "identification": {
    "title": "Stunning Marina View | High Floor Apartment",
    "property_type_label": "Entire serviced apartment",
    "room_type": "entire_home",
    "home_tier": 1
  },
  "location": {
    "lat": 25.0854,
    "lng": 55.1494,
    "coordinates_exact": true,
    "neighborhood": null,
    "city": "Dubai",
    "country_code": "AE",
    "inside_search_area": null
  },
  "capacity": {
    "guests": 4,
    "bedrooms": 2,
    "beds": 2,
    "bathrooms": 2.0
  },
  "price": {
    "currency": "AED",
    "check_in": "2026-11-10",
    "check_out": "2026-11-15",
    "nights": 5,
    "adults": 2,
    "is_available": true,
    "nightly_rate": 1286.65,
    "subtotal_nights": 6433.27,
    "discounts_total": 0,
    "taxes_total": null,
    "total": 6433.27,
    "total_display_original": 8334,
    "price_per_night": 1286.65,
    "fees_included_in_rate": true,
    "line_items": [
      {
        "type": "nightly_subtotal",
        "label": "5 nights x ﺩ.ﺇ 1,286.65",
        "amount": 6433.27,
        "currency": "AED",
        "raw": "ﺩ.ﺇ 6,433.27"
      }
    ]
  },
  "quality": {
    "rating": 4.76,
    "review_count": 21,
    "category_ratings": {
      "cleanliness": 4.71,
      "accuracy": 4.81,
      "checkin": 4.76,
      "communication": 4.76,
      "location": 4.86,
      "value": 4.62
    },
    "is_guest_favorite": false
  },
  "host": {
    "host_id": "<host id>",
    "name": null,
    "is_superhost": false,
    "is_verified": true,
    "rating": 4.59,
    "total_reviews": 5315,
    "years_hosting": 12,
    "response_rate": 0.96,
    "listings_count": null
  },
  "rules": {
    "check_in_start": "16:00",
    "checkout_time": "11:00",
    "max_guests": 4,
    "pets_allowed": true,
    "min_nights": 1,
    "instant_book": true,
    "cancellation_policy": "non_refundable"
  },
  "regulatory": {
    "license_number": "DUB-AL-HDTDQ",
    "jurisdiction": "AE-DU",
    "license_format_valid": true,
    "license_source": "description_registration_section"
  },
  "availability": {
    "calendar_start": "2026-10-01",
    "calendar_end": "2027-09-30",
    "available_days_30": 10,
    "unavailable_days_90": 25,
    "next_available_date": "2026-10-16",
    "min_nights_today": 1
  },
  "reviews_summary": {
    "reviews_fetched": 50,
    "last_review_date": "2026-09-26",
    "reviews_last_12m": 40,
    "avg_rating_fetched": 4.9
  },
  "estimates": {
    "cleaning_fee_estimated": {
      "value": 340.05,
      "method": "regression_subtotal_vs_nights",
      "confidence": "low"
    },
    "occupancy": {
      "calendar": {
        "unavailable_rate_30": 0.6667,
        "unavailable_rate_90": 0.2778,
        "method": "calendar_unavailable_share",
        "confidence": "low"
      },
      "reviews": {
        "value": 0.6575,
        "method": "inside_airbnb_san_francisco",
        "confidence": "medium"
      }
    }
  },
  "scrape": {
    "scraped_at": "2026-10-14T09:00:00Z",
    "mode": "full",
    "tiers": [
      "details",
      "pdp_quote",
      "..."
    ],
    "currency": "AED",
    "dataset_annotations_pending": true,
    "dates_auto": false
  }
}
```

Review rows go to the **reviews** dataset and, with **Daily calendar rows** on, calendar rows
to the **calendar** dataset (join by `listing_id`), or inside each listing with
`outputLayout: "nested"`, or all in the default dataset with `outputLayout: "single_dataset"`:

```json
{
  "schema_version": "1.0.0",
  "record_type": "review",
  "review_id": "<review id>",
  "listing_id": "614178316141803089",
  "created_at": "2026-09-26",
  "created_at_label": "2 weeks ago",
  "rating": 5,
  "text": "Thank you so much for your great hospitality",
  "text_original": "Thank you so much for your great hospitality",
  "language": "en",
  "is_translated": false,
  "reviewer": {
    "id": "<reviewer id>",
    "name": null,
    "location": null,
    "picture_url": null,
    "profile_url": null,
    "tenure_label": "2 years on Airbnb"
  },
  "stay_context": "Stayed a few nights",
  "host_response": null,
  "highlight": null
}
```

```json
{"schema_version": "1.0.0", "record_type": "calendar_day", "listing_id": "614178316141803089", "date": "2026-11-10", "available": true, "available_for_checkin": true, "available_for_checkout": true, "bookable": true, "min_nights": 2, "max_nights": 99, "price": null, "currency": null, "previous_available": null, "changed": null}
```

The **OUTPUT** record in the key-value store summarizes the run: per-search coverage
(listings announced vs. collected, map cells split), counts, events charged and why the run
stopped if it stopped early: `stoppedCode` is `done`, `max_listings`, `spending_cap` (Max
charge per run), `request_cap` (Max requests), `aborted`, `timeout` (the run's timeout was near: it
stops itself about 90 seconds before, keeping everything delivered), `blocked` or
`api_changed` (Airbnb changed its API: report it in Issues), a fixed value you can
check in code, with the reason in words in `stoppedReason`. **MARKET_SUMMARY** adds the market view of the run: median,
p25 and p75 price per night (before taxes) by bedrooms and by neighborhood + bedrooms,
rating distribution, hosts with several listings and license numbers shared by several
listings.

### When do results appear?

As they are scraped. With the default **Delivery: Automatic** (incremental, except Find
management leads, which delivers at the end so the dataset comes ranked), each listing (with
its reviews and calendar) is saved and charged the moment it is complete, so you can watch the
dataset grow and nothing is lost if the run stops early.

A few fields compare a listing with the rest of the run: how many listings the same host has
in this run (`host.listings_count_in_dataset`), other listings showing the same license number
(`regulatory.license_shared_with`), price and rating vs. similar listings
(`estimates.price_vs_market_pct`, `estimates.rating_vs_market`) and suspected duplicates
(`estimates.duplicate_group_id`). Their value is only known when the run ends, so in each
listing they are `null` and `scrape.dataset_annotations_pending` is `true`, instead of a
misleading partial value. At the end the Actor writes them to the **annotations** dataset
(one row per listing, join by `listing_id`) and summarizes the market in **MARKET_SUMMARY**.

Prefer complete records? Set **Delivery** to **All at the end**: those fields come filled in
each listing, but nothing appears until the run finishes and an unexpected crash loses the
results.

### Why is there no cleaning fee or service fee line?

Airbnb now shows the **total price**: cleaning and service fees are folded into the nightly
rate in every market we checked (Dubai, Paris, New York area, London, Buenos Aires, Tokyo), so
`fees_included_in_rate` is `true` and there is no separate line to read. Turn on **Estimate the
cleaning fee** and the Actor asks for two more quotes with different stay lengths and
estimates the fixed per-stay part (`estimates.cleaning_fee_estimated`, labeled as an estimate).

### How is occupancy calculated?

Airbnb publishes **availability**, not occupancy: a blocked day can be a booking, a host
block, a booking on another platform, or a gap too short to book. This Actor never gives you
one unlabeled number:

1. **Calendar** (`unavailable_rate_30/60/90/365`): the share of unavailable days. Named
   honestly: it is an upper bound, inflated by host blocks.
2. **Reviews** (the "San Francisco model" used by Inside Airbnb): reviews in the last 12
   months divided by an assumed review rate, times the average stay, capped at 70 %. The
   assumptions are in the output.

### Why do some listings have no price?

Airbnb only quotes a price for specific dates and guests, and a listing has no price when it
is not available for your dates (`price.is_available: false`). By default (**Which listings:
All active listings**) those booked listings are delivered too, so you see the whole market:
details, calendar and reviews, with the price fields `null` rather than a price for other
dates. Turn on **Only available on my dates** to drop them (they are not charged). With
**Search without dates** (Advanced) nothing is quoted: each card's price is for dates Airbnb
picks per listing (`price.quote_source: search_no_dates`), so it is not comparable between
listings. Airbnb's calendar itself has no daily prices.

### Which listings: all active ones or only the available ones?

| | All active listings (default from Details up when the field is empty) | Only listings available on your dates (default for Snapshot; the Store form starts with it) |
|---|---|---|
| How | Search without dates (every active listing), then one exact quote per listing for your dates | One search with your dates, like on airbnb.com |
| Booked homes | Included: `price.is_available: false`, no price | Missing |
| Price range filter | Applied by the Actor to each quote (the price per night before taxes, fees included); booked homes are kept unless **Only available on my dates** | Airbnb's own filter |
| Listings per area | More (the whole market) | Fewer |
| Good for | Market size, occupancy, revenue, investment analysis | A price snapshot of what can be booked now |

Every record says which one was used in `scrape.coverage` (`all` or `available`). With **All
active listings** the search card's price (for dates Airbnb picks) is never used: the price
always comes from the quote for your dates.

The form starts with **Only available** so that a first run shows prices. For market analysis
choose **All active listings**: without dates Airbnb ranks popular homes first, and those are
often booked, so with a small **Max listings** many of the listings you get can be booked and
have no price. The run says how many, in the status message ("4 of 5 are booked or blocked on
your dates and have no price") and in `availabilityOnDates` in the OUTPUT record.

### How many listings can I scrape, and how fast?

As many as Airbnb has in the area: big searches are split into smaller map areas so the
\~270-result limit of a single search does not cut your data. Use **Max listings** to cap a run
(default 200, about $0.50 at Details on the Free plan; 0 = no limit). If the area has more
listings than that, the run tells you, in the status message and in the OUTPUT record:
"Found ~1,120 listings in the area (all of them at this level: about $2.80); delivered 200
because Max listings = 200. Raise it, or use Estimate to see the full cost." When Airbnb only
says "Over 1,000 homes" for the map area, the run says that instead of guessing a number, and
points you to Estimate for the real count.

The Actor scrapes 32 listings at a time (**Parallel listings**), each through its own proxy IP
with its own pause (1 to 2 seconds between two of its pages), and requests a listing's price
quote, cancellation policy and calendar together with its page, as a browser loads it.
Snapshot reads 40 listings per request. A listing in Details takes 3 requests (page, price
quote, cancellation policy), plus 1 with **Photos: Full gallery** when Airbnb sends the page
with only 5 photos (the full set then comes from the listing's web page; at busy times this is
most regular homes); Revenue
adds 1 (12-month calendar) and Everything 2 (13 months) plus 1 per 50 reviews. With the
default **Host profile: Count** there is also one small request per unique host. Measured
on Apify with the defaults (4 GB of memory, 32 parallel listings), Dubai Marina, 5 nights:
**20 listings in Details in 9-13 seconds, 100 in 18-24 seconds, 1,000 in about 3 minutes**,
100 in Revenue (with their 12-month calendars) in 37 seconds, 20 in Everything (all 715
reviews and full photo galleries) in 23 seconds. Listings start as soon as the search finds
them. With less memory the Actor is slower (it has less CPU). If Airbnb starts
blocking, the Actor moves to residential proxies and slows down on its own (Proxy strategy:
Auto); if your runs still get blocked, lower **Parallel listings** (down to 20) or raise **Pause
between requests** to 2 seconds. Those limits keep a run's duration, which the prices include,
bounded.

### How many listings are there, and what will it cost? (free estimate)

Choose the level **Estimate**. The Actor resolves your area, asks Airbnb how many homes there
are in the map area (exact below 1,000; the map is split into smaller cells only when Airbnb
says "Over 1,000 homes") and works out how many match your filters: **exactly N bedrooms** from
Airbnb's own counts (homes with at least N minus homes with at least N+1, cell by cell), the
**neighborhood boundary** cell by cell (cells inside count whole, cells outside count nothing,
cells the boundary crosses count the share of their listings inside it), and filters Airbnb
does not apply (minimum rating, superhost, property type) from the search cards. Then it
returns the count and the price of each level, for your plan. It does not open any listing and
charges nothing. With dates (yours or the automatic ones) it counts twice: **every active
listing** (search without dates) and **the ones available on your dates**, so you also see how
much of the market a dated search misses. Every level is priced on the **Which listings**
choice you make in the form (it starts with "Only listings available on your dates"), and the
message adds what Details and up would cost with **All active listings**, the choice for
market analysis. A neighborhood takes a few requests and seconds; all the 2-bedroom homes of Dubai
Marina take 50 requests and about a minute and a quarter. Checked against a complete count of
that market: within 1-3 %. A real run on Apify (Dubai Marina, entire homes with exactly 2
bedrooms, 14-19 November) said (the Gold amounts at today's prices):

"Estimate: Dubai Marina, Dubai (OpenStreetMap polygon): 1,870 in the map area, ~1,085 active
listings matching, ~639 of them available on your dates. Free plan: Snapshot $0.64 · Details
$2.71 · Revenue and leads $3.80 · Everything ~$17.79 with ~28,008 reviews (Gold: $0.16 / $1.03
/ $1.57 / ~$8.58) (Snapshot priced on the available listings, Details and up on all active
ones). 50 requests, 73.6 s, nothing charged."

The full breakdown (area used, both counts, sample, notes, cost with your Max listings) is in
the OUTPUT record.

### Market report

With **Market report** on (Auto, the default, turns it on for Revenue & occupancy, Everything
and Find management leads; choose On or Off to decide yourself), every run also saves a ready-to-share HTML
report of its listings as `MARKET_REPORT` in the key-value
store (Storage tab, or the "Market report" link in the Output tab): prices by bedrooms and by
building, occupancy from the calendar and from reviews (never mixed), demand, quality, hosts
with several listings, amenities that move the price, cancellation policies, permit numbers
and a price map, plus the methodology. One file, no scripts or external assets: open it in a
browser, send it, or print it to PDF. It costs $0.50 per run and is charged only if the report
was created. With **Omit personal data** it shows no host names or listing titles.

### Find management leads (for property managers)

Choose the level **Find management leads**. Every listing in the area is scored from 0 to 100
on how much it underperforms the other listings of the run and how likely its owner can still
be won; the dataset comes ranked best first, and a **LEADS** table (JSON, and `LEADS_CSV` as
CSV) lands in the key-value store, ready to work through. The spreadsheet columns
`lead_score`, `lead_tier` (high from 50, medium from 30, low), `lead_type`, `lead_fit` and
`lead_reasons` are in every row.

**What the score looks at.** Performance carries 60 %: reviews per month in the last 12
months against the area (each review is roughly two stays), how much of the next 90 nights is
booked or blocked, and the rating. Fixable gaps carry 40 %: price against similar listings
(too high or too low), photos, description length, Superhost, response rate and time,
Instant Book, core amenities and long minimum stays. `lead_reasons` lists the signals that
fired, strongest first, with the numbers behind them. **Lead types** give the angle: dormant
(no reviews and no longer new), underperforming, new_listing and optimization (performs fine,
but presentation or operations can improve).

**Who is left out.** Hosts with 5 or more listings are already professional operators: tier
`excluded`, score 0. They stay in the dataset (useful as competitors) but not in the LEADS
table. Fewer listings, a business account, a team of co-hosts or a company-like name lower
the fit.

**What it does not do.** It never collects or guesses owners' names, phone numbers, emails or
addresses: Airbnb does not publish them and the Actor does not look for them anywhere else.
Hosts appear only by Airbnb's public numeric host id (and with **Omit personal data**, no host
names anywhere). How you approach owners is up to you and the rules that apply to you. The
score is a screening aid built from public data, not proof that a listing underperforms.

**Cost.** Priced like Revenue & occupancy ($3.50 per 1,000 listings on the Free plan, $1.45 on
Gold): the newest reviews are read for the score but not delivered or charged. The market
report (on by default for this level) adds $0.50.

A real row of the LEADS table, from a Dubai Marina run of 635 two-bedroom listings (37 high,
39 medium and 287 low leads; 272 listings of operators left out), with the listing id masked
and the host id and an empty building left out for this page:

```json
{
  "rank": 21,
  "listing_id": "(masked)",
  "url": "https://www.airbnb.com/rooms/(masked)",
  "score": 67,
  "tier": "high",
  "lead_type": "underperforming",
  "confidence": "medium",
  "fit": 1.0,
  "reasons": "low_review_velocity: 0.17 reviews/month in the last 12 months vs market median 0.49 | low_rating: 4.20 from 5 reviews vs market median 4.80 | open_calendar: 0% of the next 90 nights booked or blocked vs market median 16% | overpriced: 3,155 AED/night, +152% vs market median 1,252 for 2-bedroom listings | not_superhost | no_instant_book | individual_host: 1 listing",
  "bedrooms": 2,
  "nightly_price_before_taxes": 3155.3,
  "currency": "AED",
  "rating": 4.2,
  "review_count": 5,
  "host_listings_in_run": 1,
  "host_listings_total": null,
  "is_superhost": false
}
```

### Track a market over time (monitoring)

Give the search a name in **Track this market** (for example `Dubai Marina 2BR`) and run it
again with the same name, typically every day. Each run compares against the previous one and
adds a **changes** dataset:

| change | what it means |
|---|---|
| `new_listing` | a listing that was not in the market before (or came back) |
| `price_change` | another total for the same dates |
| `availability_change` | nights that got booked or blocked, or freed (with the dates) |
| `new_reviews`, `rating_change` | evidence of stays, rating up or down |
| `title_change`, `photos_change`, `license_change`, `policy_change`, `superhost_change` | the listing changed |
| `missing`, `delisted` | not in the search any more; removed after 3 absences in a row, or confirmed by its page |

The listings dataset of each run also says, per listing, whether it changed
(`scrape.monitor_changed`), which nights became unavailable or available since the last run,
and an occupancy measured from those changes (`estimates.occupancy.observed`), which gets
better with every run.

**What you pay.** The first time a monitor delivers a listing, the normal price of your level.
After that, $1.50 per 1,000 listings checked again (`listing-update`), changed or not: every
check costs requests, and the changes dataset tells you what moved. Reviews are charged once
(only new ones are delivered), and the changes dataset is free. Monitoring reads the calendar
(that is how bookings show up), so a Details monitor is priced as Revenue & occupancy. Example:
600 listings at Revenue & occupancy cost $2.10 on the first run (Free plan), then $0.90 per
daily run, less than half of scraping them again.

**Run it every day with a Schedule.** In Apify Console, open the Actor, set the input
(where, level, **Track this market**, and **Max listings: 0** so the whole area is searched and
removed listings can be detected), save it as a **task**, then **Schedules -> Create new**:
choose the task and a time, for example `0 6 * * *` (every day at 06:00). The monitor's memory
lives in a named key-value store of your account, `airbnb-monitor-<name>`, so it survives
between runs; do not delete it. Two runs of the same monitor never overlap: if one is still
running, the next one stops with a message instead of mixing their results.

**Get alerts.** On the task, open **Integrations** and add Slack, email, Google Sheets, Zapier,
Make or your own webhook, triggered when a run succeeds. Each run's Output tab has a **Market
changes** link with what changed in that run (through the API it is the run's `changes`
dataset), and the status message sums it up, e.g. "Monitor 'Dubai Marina 2BR': 37 change(s)
(29 availability change, 6 price change, 2 new listing)".

```json
{
  "where": ["Dubai Marina, Dubai"],
  "dataLevel": "revenue",
  "bedroomsExact": 2,
  "currency": "AED",
  "maxListings": 0,
  "monitorName": "Dubai Marina 2BR"
}
```

### Is it legal to scrape Airbnb?

This Actor only collects **publicly available** information that anyone can see on Airbnb
without logging in. It does not log in, does not use accounts and does not access private
data such as messages, bookings or guest contact details. Courts in the US have held that
scraping public, logged-out web pages is not unauthorized access (e.g. hiQ v. LinkedIn; Meta
v. Bright Data, 2024). Reviews and host names can be personal data under GDPR and similar
laws: collect them only with a legitimate purpose, or turn on **Omit personal data**. Check
Airbnb's Terms of Service and your local laws for your use case; if in doubt, consult a
lawyer. This Actor is not affiliated with or endorsed by Airbnb.

**What does Omit personal data remove?** Host and co-host names, photos, bios, "lives in" and
work, and reviewer names, photos and profile links become `null`; the host's name is replaced
with "the host" in texts Airbnb generates (the price-drop notice, listing highlights); the
market report shows no host names or listing titles; listing records carry a
`PERSONAL_DATA_OMITTED` warning. What stays: Airbnb's numeric host and reviewer ids, the
reviewer's location label, business data (ratings, Superhost, years hosting, license numbers)
and free text as people wrote it (review text, host responses, listing descriptions), which
can still mention names.

### FAQ

**Do I need proxies?** No setup and no proxy bill: proxy traffic is included in the event
prices. By default (**Proxy strategy: Auto**) the Actor uses Apify datacenter proxies and switches
to residential proxies only if Airbnb starts blocking; after a while it tries datacenter again.
If residential proxies are not available to the run, it slows down instead. The run log, the
status message and the OUTPUT record show requests, blocks and estimated traffic for each kind
of proxy. You can also force datacenter or residential (with a country), or pin an Apify Proxy
group in Advanced. Runs without a proxy or through your own proxy URLs are not supported: the
Actor scrapes through Apify Proxy, one IP per parallel listing.

**Which currencies are supported?** Any currency Airbnb offers (ISO code, e.g. USD, EUR, AED,
GBP). Amounts are always numbers.

**Can I get the listings in my language?** Yes: pick one of Airbnb's 66 languages in
**Language of the texts**. Every field is still collected in English (so prices, dates and
rules are parsed the same way), and the title, description, amenities and house rules also come
in your language in the `localized` block (`title_localized` and `description_localized` in the
spreadsheet). When the host wrote in another language, that text is Airbnb's machine
translation, and the original stays in the main fields. It adds one listing page per listing
(no extra charge). Reviews keep their original language.

**Who is the host: an individual or a management company?** By default the Actor reads the
total number of listings on each host's Airbnb profile (one small request per host, free):
`host_listings_total` in the spreadsheet. The listing page itself shows the "Business" label and
two of the host's profile lines at a time (languages, where they live, or their work, often a
company name like "Holiday Homes LLC"); those are free. With **Host profile: Full** you get the
complete profile: all of those lines, years on Airbnb, sign-up month and verifications
(`host-profile`, once per host).

**Can I search with children or pets?** Yes: like on airbnb.com, children count toward the
listing's capacity and pay the extra-guest fee, infants are free, and pets keep only
pet-friendly listings and add the host's pet fee to the quote. When a listing cannot take
your group, `unavailable_reason` / `unavailable_message` say why ("Maximum number of guests is
4", "This place doesn't allow pets").

**Can I mix listing URLs and searches in the same run?** Yes. Locations, map areas, search
URLs, listing URLs and IDs can be combined; each listing is returned and charged once.

**Can I get exactly 2-bedroom listings?** Yes: set **Exactly N bedrooms** to 2. Airbnb's own
filter is "2 or more", so the Actor asks for that and checks the exact count 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.

**Why are some neighborhood names empty?** Airbnb hides the neighborhood text for some
sessions (an A/B test); the record carries a `LOCATION_TEXT_HIDDEN` warning. **Retry listings
without neighborhood text** asks again with a new session.

**What dates are used if I leave them empty?** 30 days from today, for 5 nights, so that
Airbnb quotes a real price. Every record carries `scrape.dates_auto: true` and the run's OUTPUT
says which dates were used. A plain Airbnb search with dates only shows homes available on
those nights; from Details up the Actor also finds the booked ones (see **Which listings**).
**Search without dates** in Advanced skips the quote entirely.

**How do the extra filters work?** Airbnb itself filters by minimum bedrooms, bathrooms and
beds, type of place, amenities and free cancellation, and by price when **Which listings** is
"Only listings available on your dates". With listing URLs or IDs (no search), the Actor checks
bathrooms, beds, amenities and free cancellation on the listing page and its cancellation
policy; what the page cannot confirm stays, with a `FILTER_UNVERIFIED` warning. Exact
bedrooms, minimum rating, Superhosts only and property type are checked by the Actor: first on
the search card (dropped listings cost no requests and are never charged), and when the card
does not tell (for example a Superhost without the badge), on the listing page; listings that
do not match are not returned and not charged. With "All active listings" the price range and
**Only available on my dates** are checked on each listing's quote for your dates, the same
way.

**Does it download the photos?** No: every record carries the photo URLs (Airbnb's
originals, with room and caption), never image files. Open or download them yourself from the
URLs if you need the files.

**Why does a listing have only 5 photos?** Airbnb often answers with just the first 5 photos
of a regular home, especially at busy times. **Photos** decides what happens then: **Full
gallery** (the default for Everything and Find management leads) gets the rest from the
listing's web page, one more request and about 0.5-0.9 MB per such listing, so the run is
slower; **Preview** (the default for Snapshot, Details and Revenue & occupancy) keeps those 5
and the cover, and the record says so: `photos.complete: false`, `photo_count` empty, a
`PHOTOS_TRUNCATED` warning; **None** returns no photo list (the cover photo stays). The price
is the same for all three. Listings that really have 5 photos are recognized from the search
card and left alone.

**Why is `listing_id` text?** Most Airbnb listing ids have 18 or 19 digits, more than a
spreadsheet or a JSON number can hold: as a number, 614178316141803089 silently becomes
614178316141803136 and points to another listing (or nowhere). The Actor always writes ids as
text, in every dataset and record. Excel still turns long digit strings into numbers when it
opens a CSV file, so download **Excel (XLSX)** instead of CSV, and use the `url` column, the
first one, to open a listing: it is always right.

**Can I download the results as Excel?** Yes: in the run's Output or Storage tab, choose
Excel, CSV, JSON or HTML, or use the API. With the default **Output format: Spreadsheet**,
each listing is one row with 98 readable columns; with Full JSON a CSV has thousands of
columns, so keep it for code.

**Something is missing or wrong.** Open an issue on the Issues tab with the run link (see
Support below).

### Why this scraper

What it does that you can check yourself, run by run:

- **Exact prices for your dates, as numbers.** Every line of Airbnb's quote is kept and
  typed (nightly rate, discounts, taxes, total), and `fees_included_in_rate` says whether
  cleaning and service fees are inside the rate. Verified on 635 Dubai Marina listings and on
  listings in six cities.
- **The whole area, not the first 270 results.** Big searches are split into smaller map
  areas until each one fits under Airbnb's cap; the run's OUTPUT says how many listings
  Airbnb announced and how many were collected.
- **Every active listing, not only the free ones**, and the same area every run
  (OpenStreetMap boundaries instead of Airbnb's moving map).
- **Know the cost first.** The free Estimate, a maximum cost per run, and a clear message when
  Max listings cut a run, with what the whole area would cost.
- **Spreadsheet-ready output** with ids that survive Excel, and the link first.
- **Occupancy you can defend.** Calendar and reviews methods kept apart, each with its method,
  assumptions and confidence, and an observed occupancy when you monitor the market.
- **Monitoring that charges only what changed**, and a market report you can send as is.
- **Calendars charged per listing, not per day**: a 12-month calendar costs $0.001 per listing
  on the Free plan.

### Support

- Open an issue on the **Issues** tab with the run link: we answer within 48 hours.
- **You only pay for delivered results**: listings that fail are not charged, and neither are
  listings your filters drop.
- If a run did not deliver what this page promises, tell us in the issue and include the run
  link; the OUTPUT record (requests, blocks, coverage, why the run stopped) usually shows what
  happened.

### Related Actors

Same engine, same data and prices, one job each:

- [Airbnb Calendar & Occupancy](https://apify.com/thelastscraper/airbnb-calendar-occupancy):
  availability calendar, occupancy rate and revenue estimates, one flat row per listing.
- [Airbnb Reviews Scraper](https://apify.com/thelastscraper/airbnb-reviews): guest reviews with
  translation, date and language filters, $0.50 per 1,000.
- [Airbnb Listing Details Scraper](https://apify.com/thelastscraper/airbnb-listing-details): full
  listing data and price for your dates, from listing URLs or IDs.

# Actor input Schema

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

One per line. A place as you would type it on Airbnb ("Dubai Marina, Dubai", "Lisbon, Portugal"), an Airbnb search URL (its filters are kept, including its guests and dates; dates set here replace its dates, the currency always comes from this form), a listing URL (https://www.airbnb.com/rooms/123) or a listing ID. The Actor detects which is which. Places are resolved with their real OpenStreetMap boundary, so repeated runs cover exactly the same area. To search a postal code, add the city ("10001, New York").

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

YYYY-MM-DD. Leave both dates empty for automatic dates (30 days from today, 5 nights): Airbnb only quotes a price for specific dates. Note: a search with dates only returns the homes still free on those nights. This form starts with 'Which listings' = Only listings available on your dates, so every listing has a price; for market analysis, occupancy or leads switch it to All active listings.

## `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).

## `dataLevel` (type: `string`):

Estimate: counts the listings in the area and tells you what each level would cost, nothing charged. Snapshot: search card per listing: price for your dates, rating, capacity, location, photos (~$1.00 per 1,000 listings on the Free plan, $0.25 on Gold). Details: + full listing page: price breakdown, cancellation policy, host, amenities, house rules, permit number (~$2.50 / $0.95). Revenue & occupancy: + 12-month availability calendar with occupancy and revenue estimates (~$3.50 / $1.45). Everything: + all guest reviews (+$0.50 per 1,000 reviews; $0.25 on Gold) and a 13-month calendar. Find management leads (for property managers): Revenue & occupancy plus the newest reviews (read for the score, not charged), every listing found (with 'Which listings' = All active listings, the whole area) scored on how much it underperforms the area and whether its owner can still be won, ranked best first, with a LEADS table in the key-value store (~$3.50 / $1.45). Listings given by URL or ID always get at least Details.

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

All listings (the default for Details, Revenue, Everything and Find management leads when this field is empty): the Actor searches without dates to find every active listing in the area, then quotes each one for your dates. Booked listings are included with price.is_available = false and no price, so prices and occupancy are not biased toward the homes nobody booked; with a small Max listings most of them can be booked (the run's status says how many). Only available (the default for Snapshot, and what this form starts with, so a first run shows prices): a search with your dates, which returns only the homes still free on those nights. For market analysis choose All listings. All listings means more listings per area, and therefore a higher cost: run an Estimate first, it shows both counts.

## `photos` (type: `string`):

Photo URLs in each listing (the Actor never downloads image files). Full gallery: every photo; when Airbnb sends a listing with only its first 5 photos (common for regular homes at busy times), the Actor also reads the listing's web page: one more request and about 0.5-0.9 MB per such listing, so runs take longer. Preview: the photos Airbnb sends (up to 5 plus the cover when it trims the gallery; photo_count is then empty and photos_complete false), faster. None: no photo list (the cover photo stays). The price is the same either way. Empty = Preview for Snapshot, Details and Revenue & occupancy; Full gallery for Everything and Find management leads (the lead score uses the number of photos).

## `marketReport` (type: `string`):

A ready-to-share HTML report of the listings in this run, saved as MARKET_REPORT in the key-value store: prices by bedrooms and building, occupancy, demand, quality, hosts, amenities, policies, permits and a price map, with the methodology. $0.50 per run, charged only if the report is created. Auto = on for Revenue & occupancy, Everything and Find management leads (except when Monitoring), off for Snapshot and Details.

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

Stop after this many unique listings across all places and URLs (after filters). 0 = no limit. The default (200) costs about $0.50 at Details on the Free plan; if the area has more listings, the run says how many and what all of them would cost. Start small, or run an Estimate first, to check the data and the cost. To track a market (Monitoring), use 0: the whole area has to be searched to notice listings that disappear.

## `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.

## `outputFormat` (type: `string`):

Spreadsheet (default): one flat row per listing with 98 curated columns (100 with a language) in a useful order (url first, listing_id as text, prices as numbers, key amenities as true/false, estimates prefixed est\_), ready for Excel, Google Sheets or CSV. Full JSON: the complete nested record of every listing (~2,800 fields once flattened: line items, every amenity and photo, description, field sources), for developers. Reviews and calendar days are the same in both.

## `language` (type: `string`):

Everything is collected and parsed in English. Another language adds one more listing page per listing (~28 KB, no extra charge) and fills the `localized` block: title, description, amenities and house rules in that language (Airbnb's machine translation when the host wrote in another one; the originals stay in the main fields). In Spreadsheet output, the columns title_localized and description_localized. Needs the listing page (Details or higher). Reviews stay in their original language.

## `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.

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

Keep only these property types, e.g. "apartment", "villa", "townhouse", "serviced apartment", "condo". Case-insensitive partial match against the listing's property type ("apartment" also matches "serviced apartment"). Empty = any. Checked on the search card when it says the type, otherwise on the listing page.

## `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\[]=...).

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

Price per night, in the selected currency. With 'Only listings available on your dates' it is Airbnb's own search filter. With 'All active listings' the Actor applies it to each listing's exact quote for your dates (price.price_per_night: total including fees and taxes, divided by the nights); booked listings have no price and are kept unless 'Only available on my dates' is on.

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

Price per night, in the selected currency. Applied like Min price.

## `onlyAvailable` (type: `boolean`):

With 'All active listings': deliver only the listings whose quote for your dates says available (booked listings, and the few whose quote failed, are dropped and never charged). It still finds them through the search without dates, so the area is fully covered. Needs dates and a level with the listing page (Details or higher).

## `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).

## `minRating` (type: `number`):

Keep only listings rated at least this much (e.g. 4.8). Listings without a rating yet are dropped. Empty = no filter. Checked on the search card, so dropped listings cost nothing.

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

Keep only listings whose host is a Superhost. With Details or higher it is checked on the listing page; with Snapshot only listings whose search card shows the Superhost badge are kept.

## `monitorName` (type: `string`):

Any name, e.g. "Dubai Marina 2BR". Runs with the same name share one monitor, saved in a named key-value store of your account (airbnb-monitor-<name in lowercase with hyphens>). Empty = no monitoring. Set fixed check-in/check-out dates to track price changes (automatic dates move every day, so totals are not comparable). Monitoring reads the calendar (that is how bookings show up), so Details runs are priced as Revenue & occupancy. With Snapshot only the search card is compared (price shown, rating, review count): no bookings, no reviews.

## `monitorTiers` (type: `string`):

Light (default): each run reads the search card, the price quote and the calendar; the full listing page only for new listings and every few days (below). Full: the whole level on every run (more requests, same price).

## `monitorFullEveryDays` (type: `integer`):

With Light: refresh the full listing page (amenities, rules, permit, photos) when the last one is older than this.

## `monitorDelistAfter` (type: `integer`):

A listing missing from N runs in a row (searches that covered the whole area) is reported as delisted. Airbnb reshuffles search results, so one absence is not a removal.

## `monitorVerifyMissing` (type: `boolean`):

Open the page of each missing listing (1 request each) to confirm whether it was removed or is just out of the search.

## `monitorReset` (type: `boolean`):

Only if the run fails because the saved monitor state cannot be read: start a new baseline (the unreadable state is kept as STATE_CORRUPT in the monitor's key-value store). Listings already paid for in this monitor are not charged full price again, only as updates.

## `areaFilter` (type: `string`):

For locations: drop listings outside the place's OpenStreetMap boundary (polygon), outside its bounding box (bbox), or keep everything Airbnb returns (none). Every listing gets location.inside_search_area either way.

## `polygonBufferMeters` (type: `integer`):

Airbnb blurs coordinates by a few hundred meters. A buffer keeps border listings that would be dropped, at the cost of letting in some neighbors.

## `pointRadiusMeters` (type: `integer`):

If the location resolves to a single point (a building or an address) instead of an area, search this radius around it. The run report says when this happened.

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

Same as typing places in 'Where'. Kept for runs and integrations made before 'Where' existed; both lists are combined.

## `bbox` (type: `object`):

Search only inside this rectangle, like moving Airbnb's map. Object with neLat, neLng, swLat, swLng, e.g. {"neLat": 25.09997, "neLng": 55.154318, "swLat": 25.08042, "swLng": 55.136914}. Combined with 'Where'.

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

Airbnb search URLs and/or listing URLs, as before 'Where' existed. Combined with 'Where'.

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

Numeric Airbnb listing IDs (or /rooms/ URLs). Combined with 'Where'.

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

The engine modes from before 'Level of detail' existed. Leave empty to use the level. Search = Snapshot, Details = Details, Calendar = Revenue (13-month calendar), Full = Everything (4 review pages unless Max review pages says otherwise). Reviews = details + reviews without calendar, which has no level of its own.

## `noDates` (type: `boolean`):

Search without dates and quote nothing: Airbnb returns every listing in the area, but each card's price is for dates Airbnb picks per listing (price.quote_source = search_no_dates), so prices are not comparable. Usually you want 'Which listings' = All active listings instead, which also finds every listing but quotes each one for your dates. Conflicts with check-in/check-out.

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

Months of availability to fetch, starting this month. Empty = 12 for Revenue & occupancy and Find management leads (one request: the 30/60/90-day windows are complete, the 365-day window stays empty) and 13 for Everything (one more request, ~16 KB, completes the 365-day window).

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

Also deliver the calendar day by day: one row per listing and day (about 365 per listing) in the 'calendar' dataset, with availability, check-in/check-out allowed and 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 (the default): each listing still carries its occupancy, ADR and revenue estimates from the calendar. Only with Revenue & occupancy, Everything and Find management leads.

## `maxReviewPages` (type: `integer`):

Reviews come in pages of 50, most recent first (Everything level). Empty or 0 = all reviews. Each review is charged, so a cap keeps the cost of listings with hundreds of reviews predictable.

## `estimateCleaning` (type: `boolean`):

Airbnb folds cleaning and service fees into the nightly rate. With this on, 2 extra price quotes per listing (different stay lengths) estimate the fixed per-stay part (estimates.cleaning_fee_estimated). Off by default: it adds 2 requests to the 3-4 of a listing (about +50 % run time) for a low-confidence estimate.

## `hostProfile` (type: `string`):

Count (default, free): one small request per unique host (~1.9 KB) for the host's total number of Airbnb listings, what tells an individual from a management company (it feeds the professional-host flag and the management-lead score). Full: the host's whole public profile (~7 KB per unique host): listings, years on Airbnb, sign-up month, verifications and the business verification badge; charged as host-profile, once per unique host ($1.00 per 1,000 hosts on the Free plan). Languages, 'lives in', work and the business label come free from the listing page's host card when it shows them (it shows 2 of the host's lines at a time; 'lives in' and work are empty with Omit personal data). Off: no profile requests. Needs the listing page (Details or higher).

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

Set host and co-host names, photos, bios, 'lives in' and work, and reviewer names, photos and profile links to null; replace the host's name with "the host" in Airbnb-generated texts (price-drop notice, listing highlights); the market report then shows no host names or listing titles. GDPR-friendly. What stays: numeric host and reviewer ids, the reviewer's location label, business data (ratings, Superhost, years hosting, license numbers) and free text as people wrote it (review text, host responses, listing descriptions), which can still contain names.

## `retryLocationAb` (type: `boolean`):

Airbnb hides the neighborhood name and area text for about half of the sessions (an A/B test). When on, such listings are fetched again with a new session, up to 'Listing page retries' times (about +0.5 requests per listing and retry).

## `pdpRetryAttempts` (type: `integer`):

Airbnb sometimes (about 1 in 9 requests) sends a listing page with only 5 of its photos. Such pages are fetched again with a new session up to this many times and the most complete answer is kept (also used by the neighborhood-text retry above). 0 = never retry.

## `hostFeePct` (type: `string`):

Fraction Airbnb keeps from the host, used for estimates.revenue_net_of_platform_fee, e.g. 0.155. Empty = not computed.

## `pushMode` (type: `string`):

Automatic (default): Incremental, except Find management leads, which delivers at the end so that the dataset comes ranked best lead first with the scores filled in. Incremental: each listing (with its reviews and calendar) is saved and charged as soon as it is complete, so you see results from the first minutes and nothing is lost if the run stops. The few fields that compare a listing with the rest of the run (host's listings in this run, shared license numbers, price and rating vs. similar listings, suspected duplicates) are null in each listing, flagged with scrape.dataset_annotations_pending, and delivered at the end in the 'annotations' dataset (join by listing_id) and the MARKET_SUMMARY record. End: everything is saved at the end with those fields filled in, but nothing appears until the run finishes, an abort loses what was not saved in its last 30 seconds (a timeout is handled: the run stops itself about 90 seconds before it), and an unexpected crash loses the results.

## `outputLayout` (type: `string`):

Separate: listings in the default dataset, reviews and calendar days in their own datasets (best for CSV/Excel; join by listing_id). Nested: reviews and days inside each listing (best for JSON/API; needs Output format = Full JSON). Single dataset: everything in the default dataset, told apart by record_type.

## `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.

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

Optional. Set it only to force a specific Apify Proxy group: it is used as is for the whole run, with session rotation but without the automatic datacenter -> residential ladder. Your own proxy URLs and runs without a proxy are not supported: the Actor scrapes through Apify Proxy, one IP per parallel listing. Leave it unset to use 'Proxy strategy'.

## `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.

## `saveRawResponses` (type: `boolean`):

Keep every raw Airbnb response in the key-value store (RAW_RESPONSES, tar.gz). Only useful for debugging.

## Actor input object example

```json
{
  "where": [
    "Dubai Marina, Dubai"
  ],
  "adults": 2,
  "children": 0,
  "infants": 0,
  "pets": 0,
  "dataLevel": "details",
  "coverage": "available",
  "marketReport": "auto",
  "maxListings": 5,
  "currency": "AED",
  "outputFormat": "spreadsheet",
  "language": "en",
  "onlyAvailable": false,
  "freeCancellation": false,
  "superhostOnly": false,
  "monitorTiers": "light",
  "monitorFullEveryDays": 7,
  "monitorDelistAfter": 3,
  "monitorVerifyMissing": false,
  "monitorReset": false,
  "areaFilter": "polygon",
  "polygonBufferMeters": 0,
  "pointRadiusMeters": 1500,
  "noDates": false,
  "calendarDays": false,
  "estimateCleaning": false,
  "hostProfile": "count",
  "omitPersonalData": false,
  "retryLocationAb": false,
  "pdpRetryAttempts": 1,
  "pushMode": "auto",
  "outputLayout": "separate",
  "proxyStrategy": "auto",
  "maxConcurrency": 32,
  "delaySeconds": 1,
  "maxRequests": 0,
  "saveRawResponses": false
}
```

# Actor output Schema

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

One item per listing (default dataset).

## `reviews` (type: `string`):

One item per review (outputLayout=separate).

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

One item per listing and day, with Daily calendar rows on (calendarDays; outputLayout=separate).

## `annotations` (type: `string`):

pushMode=incremental: run-level fields per listing (join by listing_id).

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

OUTPUT record: per-task coverage, counts, charged events, why the run stopped.

## `market` (type: `string`):

MARKET_SUMMARY: median price by bedrooms and neighborhood, rating distribution, hosts with several listings, shared licenses.

## `marketReport` (type: `string`):

MARKET_REPORT: the HTML market report of the run (marketReport; on by default for Revenue & occupancy, Everything and Find management leads). Open it in a browser or print it to PDF.

## `leads` (type: `string`):

LEADS: the ranked management leads of a 'Find management leads' run (best first; operators left out). JSON; the same table as CSV is LEADS_CSV.

## `leadsCsv` (type: `string`):

LEADS_CSV: the leads table as a CSV file.

## `changes` (type: `string`):

Monitoring (monitorName): what changed since the previous run of the same monitor.

# 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"
    ],
    "dataLevel": "details",
    "coverage": "available",
    "maxListings": 5,
    "currency": "AED"
};

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

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

```

## MCP server setup

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