# Booking.com Hotel Search Scraper (`boncross/booking-hotel-search`) Actor

Scrape every hotel Booking.com is selling for a destination and your dates. Just add city names and get name, stars, guest review score, price for the stay, address, coordinates, free-cancellation flag and a photo. Export to CSV, JSON or Excel, or schedule it.

- **URL**: https://apify.com/boncross/booking-hotel-search.md
- **Developed by:** [BonCross API](https://apify.com/boncross) (community)
- **Categories:** Travel
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 hotel-listeds

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

## Booking.com Hotel Search Scraper

### What is Booking.com Hotel Search Scraper?

Booking.com Hotel Search Scraper prices a whole destination for your dates: hotels, apartments, hostels, guest houses and homes, one row each, with the price for your party, the guest score, the address and the coordinates. You type a city and two dates. Or you point it at a landmark, draw a box on the map, or let the dates float.

Why it's worth choosing for market work:

- Booking does the sorting and filtering. All ten of its sort orders and its sidebar filters are passed to Booking itself, and what you get is what the site returns for the same search. A property Booking filters out is never charged.
- You can search the way the site lets a traveller search: around a landmark or airport, inside a map rectangle, within a radius of a point, or across flexible dates where each property is priced at its own cheapest stay.
- Every price says whether tax is in it. Each row has a flag and the amount payable on top, and prices are quoted on one basis on every run, which keeps two runs comparable.
- It's fast at scale. Four cities at 300 hotels each took 4 to 5 seconds on most runs, and 36 cities (about 10,400 rows) took 15 to 21 seconds.
- $1.20 per 1,000 hotels on the Free plan, $0.80 on Business. Looking up a destination is free and proxy usage is included.

**BonCross Verified** means we tested this actor against the live site before release and kept the record:

- 46 of 46 live checks on its inputs and filters passed on 8 October 2026
- 7 destinations run on 7 October 2026 in 7 countries: 175 hotels, none empty
- Charges checked against the 175 rows

### Four ways to define the market you want

| You have | You set | You get |
|---|---|---|
| A place name | "Destinations": a city, region or district | Every property Booking is selling there for your dates |
| A point of interest | "Landmark or airport", with or without a destination, and a radius if you want one | Properties nearest first, each with its distance from the landmark |
| An area on a map | "Map area: box", or "Map area: centre point" with a radius | Everything inside the box or the circle |
| No fixed dates | "Flexible months" with a length of stay and a start day, or "Flexible: days either side" | Each property priced for its own cheapest dates, which are on the row |

You can combine any of them with Booking's filters: property type, stars, review score, budget per night, meals, free cancellation and no prepayment, plus anything else on its sidebar by name, from "Swimming pool" to a neighbourhood or a hotel brand.

### What data do you get for each property?

| | Field | Notes |
|---|---|---|
| 🏨 | `id`, `hotelId`, `name`, `slug`, `url` | the property and a link back to it; `id` is the property and stay |
| | `propertyTypeId`, `propertyType` | Booking's type code and its name on Booking's Property type filter ("Hotels", "Aparthotels", "Hostels") |
| 📅 | `checkIn`, `checkOut`, `nights` | the stay the price was quoted for |
| 💶 | `priceTotal`, `priceTotalText`, `pricePerNight`, `currency` | stay total (as a number and as the site shows it) and nightly equivalent |
| | `priceBeforeDiscount`, `discounts` | the struck-through price and the deal behind it, such as "Limited-time Deal" |
| 🧾 | `pricesIncludeTax`, `taxesAndChargesExcluded` | whether the price includes every tax and charge Booking puts a figure on, and the amount payable on top where it does not |
| | `hasExcludedCharges` | true where something is payable on top of the price, such as a city tax |
| ⭐ | `stars`, `qualityRating` | official star rating; `qualityRating` is Booking's own 1-5 award for homes and apartments (the squares on the card), kept apart from stars |
| 💬 | `rating`, `ratingScale`, `ratingText`, `reviewCount` | guest score out of 10 and its wording; null on a property with no reviews yet |
| 📍 | `address`, `city`, `countryCode`, `lat`, `lng` | full location |
| 🚇 | `neighbourhood`, `distanceFromCentreText`, `publicTransportText` | as the site words them |
| | `isFreeCancellation`, `isNoPrepayment` | booking conditions advertised on the card |
| 🛏 | `bedsInRoom`, `bedrooms` | the offer matched to your party; `bedrooms` is null on ordinary hotel rooms |
| 🍳 | `mealPlanText` | the meal plan on the card, where one is advertised (a minority of properties) |
| | `isSoldOut`, `isSponsored`, `isSustainable`, `isCentrallyLocated` | row flags |
| | `isPartnerSupplied` | true when every room offered for your dates comes through one of Booking's supply partners rather than the property itself |
| 📷 | `photo` | the property's main photo |
| | `sortBy` | the order the rows came back in |
| 🗺 | `destination`, `destinationId`, `destinationType` | the destination you typed and the place it resolved to (city, region, district …) |
| | `distanceFrom`, `distanceMeters`, `distanceText` | on a landmark or map-point search: the landmark (or point), the straight-line distance in metres and Booking's own wording ("0.2 miles from Eiffel Tower") |
| | `scrapedAt` | when the row was collected |

### How to scrape Booking.com hotel search

1. [Create a free Apify account](https://console.apify.com/sign-up) and open [Booking.com Hotel Search Scraper](https://apify.com/boncross/booking-hotel-search).
2. Add your destinations: city, region or district names, such as "Paris" or "Lisbon".
3. Set your check-in and check-out dates and how many adults, rooms and children you're pricing for.
4. If you want, pick a sort order, add filters, and cap the rows per destination or for the run.
5. Click Start. Download the rows as CSV, Excel or JSON when it finishes, usually within seconds.

### How much does it cost?

| Event | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| `actor-start`, per run | $0.001 | $0.001 | $0.001 | $0.001 |
| `hotel-listed`, per property row written | $0.0012 | $0.001 | $0.0009 | $0.0008 |

Enterprise plans pay the Business price.

**$1.20 per 1,000 hotels** on the Free plan, $0.80 on Business. You pay nothing extra to look a destination up, error rows are never charged, and proxy usage and platform usage are included in the price.

- One city, 100 hotels: $0.001 + 100 × $0.0012 = **$0.121** ($0.081 on Business).
- Five cities, 500 hotels each: $0.001 + 2,500 × $0.0012 = **$3.001** ($2.001 on Business).
- A daily scan of one city's 100 hotels for a month: 30 × ($0.001 + 100 × $0.0012) = **$3.63** for the month ($2.43 on Business).

The $5 of credits that comes with Apify's Free plan each month covers about 41 searches of 100 hotels, or roughly 4,100 priced properties.

### ⬇️ Input

Give it destinations and dates, and you have a run. Everything else narrows or reshapes the search.

You have two limits. "Max hotels per destination" (default 100, and 0 means every one) applies to each destination separately. "Max rows in total" caps the whole run across every destination, and 0 means no ceiling.

| Input | Type | Notes |
|---|---|---|
| `destinations` | array | City, region or district names |
| `checkIn`, `checkOut` | string | `YYYY-MM-DD`. Check-out must be after check-in |
| `adults`, `rooms`, `childrenAges` | number, array | Who the prices should cover |
| `maxHotelsPerDestination` | number | Properties per destination (default 100). `0` means every one |
| `maxItems` | number | Ceiling for the whole run, across every destination (default 0, no ceiling) |
| `sortBy` | string | Booking's sort orders (default `popularity`): `popularity` (Our top picks), `upsort_bh`, `price`, `price_from_high_to_low`, `review_score_and_price`, `class`, `class_asc`, `class_and_price`, `distance_from_search`, `bayesian_review_score` |
| `propertyTypes` | array | Names from Booking's Property type filter: Hotels, Apartments, Hostels, Ryokans, Entire homes & apartments … |
| `minStars`, `minRating` | number | Booking's star and review-score filters; a score between its bands (8.5) is finished off row by row |
| `minPricePerNight`, `maxPricePerNight` | number | Booking's budget filter, per night, in the run's currency |
| `mealPlans` | array | `breakfast`, `breakfast_and_dinner`, `breakfast_and_lunch`, `all_meals`, `all_inclusive`, `self_catering` |
| `onlyFreeCancellation`, `noPrepaymentOnly` | boolean | Booking's reservation-policy filters |
| `excludePartnerSupplied` | boolean | Leave out properties whose rooms are all sold through a supply partner (default off: they are real and bookable) |
| `filters` | array | Anything else on the sidebar, by label ("Swimming pool", "Free WiFi", "Pets allowed") or code (`hotelfacility=433`) |
| `destinationType` | string | Force what a name resolves to. Auto prefers a city |
| `landmark` | string | Search around a landmark or airport ("Eiffel Tower", "Big Ben" or "Heathrow Airport"), looked up inside each destination the way Booking's own landmark search does, or on its own with no destination. Rows come nearest first unless you choose another sort order |
| `radiusKm` | number | Keep properties within this distance of the landmark, the map centre, or otherwise the destination's centre. Required with `mapCentre` |
| `mapBoundingBox` | string | A map rectangle instead of destinations: `"south lat, west lng, north lat, east lng"` |
| `mapCentre` | string | A map point instead of destinations, `"lat, lng"` such as `"48.859, 2.3585"`, with `radiusKm` |
| `flexibleMonths`, `flexibleNights`, `flexibleStartDay` | array, number, string | Any dates in these months (`YYYY-MM`), for this many nights, starting on this weekday. Replaces check-in and check-out |
| `flexibleDays` | number | Let each stay move 1, 2, 3 or 7 days either side of check-in |
| `currency`, `language` | string | Currency code and Booking language code |
| `maxConcurrency`, `delayMs` | number | Parallel requests, 1 to 32 (default 32), and an optional pause before each call in ms (default 0). Neither changes the rows |

**Two cities for one night, well-reviewed properties only, in euros**

```json
{
  "destinations": ["Paris", "Lisbon"],
  "checkIn": "2026-11-02",
  "checkOut": "2026-11-03",
  "adults": 2,
  "rooms": 1,
  "currency": "EUR",
  "maxHotelsPerDestination": 100,
  "minRating": 8
}
```

**The cheapest hostels and guest houses with free WiFi in Lisbon, under 60 a night**

```json
{
  "destinations": ["Lisbon"],
  "checkIn": "2026-11-02",
  "checkOut": "2026-11-04",
  "sortBy": "price",
  "propertyTypes": ["Hostels", "Guest houses"],
  "filters": ["Free WiFi"],
  "maxPricePerNight": 60
}
```

**Hotels within 1 km of the Eiffel Tower, nearest first**

```json
{
  "destinations": ["Paris"],
  "landmark": "Eiffel Tower",
  "radiusKm": 1,
  "checkIn": "2026-11-10",
  "checkOut": "2026-11-11"
}
```

**Everything inside a map rectangle over the Marais**

```json
{
  "mapBoundingBox": "48.853, 2.349, 48.865, 2.368",
  "checkIn": "2026-11-10",
  "checkOut": "2026-11-11",
  "maxHotelsPerDestination": 500
}
```

**A Friday-to-Sunday weekend any time in November or December, each property at its cheapest weekend**

```json
{
  "destinations": ["Lisbon"],
  "flexibleMonths": ["2026-11", "2026-12"],
  "flexibleNights": 2,
  "flexibleStartDay": "friday"
}
```

Filter labels are matched on each destination's own sidebar, because the options differ by place (a neighbourhood list, the brands present, the landmarks nearby). Not sure of a label? Each run saves that sidebar, with the label, code and count of each filter, and you can copy the codes from there.

One warning about those counts. They're Booking's sidebar figures, and for a few options they measure something different from what the filter returns. The clearest case is **Number of bedrooms**: the filter counts bedrooms in entire homes and apartments, while the sidebar count also includes hotels whose offer for your party spans two rooms. In Tokyo, 852 hotels are counted under "2+ bedrooms" and the filter returns 46 of them.

#### For developers

- The run's key-value store holds `STATS` (counts, including each destination's matching total in `totalByDestination`, which is the number the rows follow) and `SEARCH_OPTIONS` (each destination's filters with their labels, codes and counts).
- `maxHotelsPerDestination` is the per-destination limit and `maxItems` the run-wide one.
- A filter that keeps almost nothing is cut short: after 500 rows read for a destination, the run stops reading it if fewer than 0.15 rows per 100 are being kept.
- `maxConcurrency` (default 32, from 1 to 32) is how many requests run at once. Several destinations and pages are read together. Set it to 1 for a strictly one-at-a-time run. The hotels are the same either way.
- `delayMs` (default 0) pauses before each call. Values above 2000 are treated as 2000.
- A map area is one search. Its rows have `destination` "map …" with the area's coordinates, `destinationType` `BOUNDING_BOX` or `LATLONG`, and no `destinationId`.
- If the platform moves or restarts a run part-way, it carries on where it stopped. Rows already in the dataset aren't delivered or billed twice. We tested it by restarting a 36-city run part-way, and no row appeared twice.

### ⬆️ Output

One row per property. This one is from the Paris and Lisbon example above, run on 7 October 2026.

```json
{
  "id": "51086-2026-11-02-2026-11-03",
  "hotelId": 51086,
  "name": "Mercure Tour Eiffel Grenelle",
  "slug": "toureiffelparis",
  "url": "https://www.booking.com/hotel/fr/toureiffelparis.html",
  "checkIn": "2026-11-02",
  "checkOut": "2026-11-03",
  "nights": 1,
  "address": "64, Boulevard de Grenelle",
  "city": "Paris",
  "countryCode": "FR",
  "lat": 48.8505123550271,
  "lng": 2.2926490008831,
  "propertyTypeId": 204,
  "stars": 4,
  "qualityRating": null,
  "rating": 8.1,
  "ratingScale": 10,
  "ratingText": "Very good",
  "reviewCount": 1049,
  "currency": "EUR",
  "priceTotal": 205.23,
  "priceTotalText": "€ 205.23",
  "pricePerNight": 205.23,
  "priceBeforeDiscount": null,
  "discounts": [],
  "pricesIncludeTax": false,
  "taxesAndChargesExcluded": 37.42,
  "hasExcludedCharges": true,
  "isSoldOut": false,
  "isFreeCancellation": false,
  "isNoPrepayment": false,
  "isSponsored": false,
  "isSustainable": true,
  "isPartnerSupplied": false,
  "bedsInRoom": 2,
  "bedrooms": null,
  "mealPlanText": null,
  "distanceFromCentreText": "2.7 miles from centre",
  "neighbourhood": "15th arr., Paris",
  "publicTransportText": "Dupleix station is within 100 yards",
  "isCentrallyLocated": false,
  "photo": "https://cf.bstatic.com/xdata/images/hotel/square600/776603526.webp?k=2eabefa89ada95f00159c251594146fe6f5bf6d54d30b2f01835668f44d57471&o=",
  "scrapedAt": "2026-10-07T20:34:31.892Z",
  "propertyType": "Hotels",
  "destination": "Paris",
  "destinationId": -1456928,
  "destinationType": "CITY",
  "sortBy": "popularity"
}
```

#### How to read the price

Every price is the one Booking.com shows a visitor in the United States, whichever run or row you look at. Two runs of the same search are always on the same basis. On that basis some properties have every tax inside the price and others quote it before taxes, and each row tells you which. `pricesIncludeTax` is false where a tax or charge with a figure is payable on top, and `taxesAndChargesExcluded` is that figure for the stay. `priceTotal + taxesAndChargesExcluded` is then the full price: €205.23 + €37.42 in the row above. Prices are reported exactly as Booking returned them and never converted from one basis to the other. A charge Booking can't put a figure on, such as a city tax that "may apply", doesn't count against `pricesIncludeTax` and is flagged by `hasExcludedCharges`.

#### Unrated properties

A property with no reviews yet returns `rating`, `ratingScale` and `ratingText` as null and `reviewCount` as 0. A score of zero there would read as the worst possible rating and drag down any average you compute, which is why you get "not rated". Up to 7 of 200 properties were unrated in a large city search.

#### Landmark, map and flexible-date rows

Searching around a landmark or a map point adds three columns: `distanceFrom` (the landmark's name, or the point), `distanceMeters` (the straight-line distance from it, worked out from the two sets of coordinates) and `distanceText` (Booking's own wording). On the Eiffel Tower example, Pullman Paris Tour Eiffel came back with `distanceMeters` 349 and `distanceText` "0.2 miles from Eiffel Tower". `distanceFromCentreText` is then empty, since Booking's distance is measured from the landmark or the point.

On a flexible-date search each row is priced for its own dates. `checkIn`, `checkOut` and `nights` are the stay Booking priced that property for: its cheapest stay of the length and start day you asked for, in the months you gave, or its cheapest night inside the window around your dates. `priceTotal` is for those dates and `id` includes them, which means the same property can appear on another run at other dates. We checked this against fixed-date searches of the same properties on the dates given: the prices were identical, and the dates were the cheapest of the alternatives.

You can export the dataset as JSON, CSV, Excel, XML or HTML.

### How many hotels can you get, and how fast?

As many as the destination has. A large city runs to a couple of thousand matching properties for a one-night stay (**2,057** in Osaka and **1,406** in Kyoto when measured), and the actor pages through them until it reaches your limit.

| Run | Rows | Time |
|---|---|---|
| 36 cities, two nights, 300 each | about 10,400 | 15 to 21 s |
| 12 cities, two nights, 300 each | 3,600 | 7 to 9 s |
| Lisbon, Bangkok, Osaka and Kyoto, two nights, 300 each | 1,200 | 4 to 5 s on most runs, up to 15 s |
| One city (Osaka), one night, 10 hotels | 10 | 3 to 5 s |

Whole runs on Apify, measured on 2 October 2026, with start-up and the resolving of the destination names included. The spread on the four-city line is Booking.com itself, which answers faster at some hours than others. The 36-city run worked out at about 30,000 rows a minute, and a few hundred destinations finish well inside the default one-hour run limit.

### Limitations

- You get one stay per run, unless you search flexible dates, where each property gets its own cheapest stay. To compare fixed dates, run the same destination across several date pairs.
- A search row has one price per property, the cheapest the site is advertising for your party. For every room and rate plan, use [Booking.com Room Rates Scraper](https://apify.com/boncross/booking-room-rates).
- `propertyType` names Booking's own type code in English (`en-gb`, the default), the same on every run: an aparthotel is "Aparthotels" even when Booking lists it under Hotels. One code that Booking never names on its filter (mostly inns) has an empty `propertyType`, and `propertyTypeId` is always there. In other languages the name comes from the destination's filter list, and it can be empty for a type that list doesn't show. Booking's own Hotels filter can still include aparthotels on some searches and not others.
- Sold-out properties aren't listed. The search returns properties with something to sell for your dates, as Booking's own "Only show available properties" does.
- Partner-supplied rooms come and go between identical searches. Booking offers some properties through supply partners, and whether those rooms are listed changes from one search to the next. A property whose rooms are all partner-supplied (`isPartnerSupplied: true`) can be missing from the next identical search, and Booking leaves such properties out of its own match count: a search Booking counts as 31 properties can return 31 or 32 rows. In one 300-row search, 22 rows were partner-supplied.
- Price order is Booking's own. Sorting by price follows the figure Booking ranks by, which isn't always the price shown: in 8 cheapest-first and dearest-first runs of 30 rows, at most one row per run sat out of place.
- Paid placements are rare. `isSponsored` was false on all 503 rows measured, which is why there's no option to exclude them.
- Distances are localised text ("2.7 miles from centre"), because the site words them that way. The wording and unit follow your language input, as a visitor in the United States sees them. On a landmark or map-point search `distanceMeters` gives the straight-line distance as a number.
- A flexible-month search needs a start weekday. Booking prices nothing without one.
- Prices follow the currency and language you ask for. A property's own currency may differ.

### FAQ

#### Why does the same search return a slightly different list the second time?

Mostly because of partner-supplied rooms, which Booking shows in some answers and leaves out of others. If you need a list that holds still from run to run, switch on "Leave out partner-supplied properties". Those properties are real and bookable, and that's why the switch is off by default.

#### The landmark search picked the wrong place. What do I do?

A landmark is Booking's first suggestion for the name inside the destination. Look at `distanceFrom` on the rows (or the run log) to see what it resolved to, and give a fuller name if it isn't the place you meant.

#### Why did a destination resolve to the wrong kind of place?

A bare name prefers the city over a landmark inside it. Set "Destination type" to force a specific kind of place. If Booking has none of that kind, the error row names what it does offer.

#### Why do some properties have no star rating?

Booking.com doesn't give them one. Apartments, guesthouses and many private rentals are unrated on the site, and the field stays empty. A minimum star filter will therefore remove more than you expect. The guest review score is present far more often and is usually the better filter.

#### Is the price per night or for the stay, and for how many people?

Both are on the row: `priceTotal` is the stay and `pricePerNight` the nightly equivalent. They're quoted for the party you entered, children included.

#### How do I get the rooms and rate plans, not just one price?

Feed the hotels this actor returns into [Booking.com Room Rates Scraper](https://apify.com/boncross/booking-room-rates). The `url` on each row is the input it takes.

#### Can I compare several dates in one run?

Not with fixed dates. A search returns one stay, and comparing dates means running the same destination once per date pair. If what you want is each property's cheapest dates, a flexible search does that in one run.

#### Do I need proxies or a Booking.com account?

Neither. No login and no cookie of yours is used, and proxy usage is included in the price.

#### Is it legal to scrape Booking.com?

The actor reads only what Booking.com serves to a logged-out visitor, takes no account access and collects no private data. Reading public pages like these is generally lawful in the UK, EU and US. You remain responsible for how you use what you collect and for the site's own terms.

### Pipelines, schedules and agents

Search rows are usually the first step of something longer: a daily price scan into a warehouse, or a list of hotels handed on to the room rates and reviews actors. Apify Schedules run it on a cron, a webhook can fire when a run finishes, and the rows go on to Google Sheets, Slack, Make or Zapier through Apify's integrations.

`POST https://api.apify.com/v2/acts/boncross~booking-hotel-search/run-sync-get-dataset-items` with the input JSON as the body returns the rows in a single call for short runs. An agent can call the same actor through the Apify MCP server at `mcp.apify.com` with a city and dates, and gets structured rows back.

### More from BonCross

- [Booking.com Hotel Details Scraper](https://apify.com/boncross/booking-hotel-details): The full Booking.com record for a property.
- [Booking.com Reviews Scraper](https://apify.com/boncross/booking-reviews): Every Booking.com guest review for any hotel.
- [Booking.com Room Rates Scraper](https://apify.com/boncross/booking-room-rates): Every room Booking.com is selling for a hotel and your dates.
- [Expedia Hotel Details Scraper](https://apify.com/boncross/expedia-hotel-details): The full property record from Expedia and Hotels.com.
- [Expedia Hotel Search Scraper](https://apify.com/boncross/expedia-hotel-search): Every hotel Expedia and Hotels.com list for a destination and your dates.
- [Expedia Room Rates Scraper](https://apify.com/boncross/expedia-room-rates): Every room Expedia and Hotels.com are selling for a hotel and your dates.

### Your feedback

If a filter label doesn't match, a landmark resolves oddly or a row looks wrong against the site, open an issue on the actor's Issues tab and include the input you ran. We reply there, and requests for new search options are welcome.

# Changelog

This Actor's version history is a separate document: https://apify.com/boncross/booking-hotel-search/changelog.md

# Actor input Schema

## `destinations` (type: `array`):

Cities, regions or districts to search, e.g. "Paris" or "Lisbon".

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

Arrival date, YYYY-MM-DD. Leave both dates empty to price one night 30 days from today. Not needed when you search flexible months.

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

Departure date, YYYY-MM-DD. Must be after check-in. Not needed when you search flexible months.

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

Adults per room.

## `rooms` (type: `integer`):

How many rooms the prices should cover.

## `childrenAges` (type: `array`):

One entry per child, their age at check-in (0-17). Leave empty for adults only.

## `maxHotelsPerDestination` (type: `integer`):

Stop after this many properties per destination. 0 means every one the site returns.

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

A ceiling for the whole run, across every destination. 0 means no ceiling.

## `landmark` (type: `string`):

Search around a landmark or airport instead of across the whole destination, e.g. "Eiffel Tower", "Big Ben" or "Heathrow Airport". It is looked up inside each destination the way Booking.com's own landmark search does (on its own when no destination is given). Rows then come nearest first, unless you choose another sort order, and each carries its distance from the landmark.

## `radiusKm` (type: `number`):

Keep properties within this distance: from the landmark, from the map centre, or otherwise from the destination's centre. 0 means no limit. Needed with a map centre.

## `mapBoundingBox` (type: `string`):

Search a rectangle on the map instead of a destination: the south-west and north-east corners as "south latitude, west longitude, north latitude, east longitude", e.g. "48.853, 2.349, 48.865, 2.368". Replaces the destination list.

## `mapCentre` (type: `string`):

Search around a point on the map instead of a destination, as "latitude, longitude" in decimal degrees, e.g. "48.859, 2.3585", together with a radius. Each row carries its distance from the point. Replaces the destination list.

## `flexibleMonths` (type: `array`):

Search any dates in these months instead of fixed dates, as YYYY-MM (a full date counts as its month), e.g. "2026-11". Each property comes back priced for its own cheapest stay that fits the length and start day below, and its row carries those dates. Check-in and check-out are then not needed.

## `flexibleNights` (type: `integer`):

Length of stay for flexible months, 1 to 28 nights.

## `flexibleStartDay` (type: `string`):

The weekday the stay starts on, for flexible months.

## `flexibleDays` (type: `integer`):

Let each property's stay move up to this many days either side of check-in, keeping the length of stay: 1, 2, 3 or 7, as Booking.com offers. Each row carries the dates its price is for. 0 means the exact dates.

## `sortBy` (type: `string`):

Booking's own orderings, as on its Sort menu.

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

Keep only these kinds of property, by the names on Booking's Property type filter: Hotels, Apartments, Ryokans, Hostels, Guest houses, Villas, Capsule hotels, Entire homes & apartments and so on. What is on offer varies by destination.

## `minStars` (type: `integer`):

Keep 3-star properties and up with 3, and so on. Applied by Booking's star filter. 0 keeps everything.

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

Drop properties scoring below this out of 10. Booking's review-score filter does the 6+/7+/8+/9+ part and the rest is checked on each row. 0 keeps everything.

## `minPricePerNight` (type: `number`):

Booking's budget filter, in the run's currency (US dollars when Currency is empty). 0 means no minimum.

## `maxPricePerNight` (type: `number`):

Booking's budget filter, in the run's currency (US dollars when Currency is empty). 0 means no maximum.

## `mealPlans` (type: `array`):

Keep properties offering any of these, as on Booking's Meals filter.

## `onlyFreeCancellation` (type: `boolean`):

Keep only properties offering free cancellation for these dates. Applied by Booking's own filter.

## `noPrepaymentOnly` (type: `boolean`):

Keep only properties you can book without paying in advance.

## `excludePartnerSupplied` (type: `boolean`):

Some properties are sold on Booking.com from a partner's inventory rather than the property's own. They are real and bookable, and Booking shows them in some answers and not others, so they come and go between identical searches (each row says so in isPartnerSupplied). Turn this on to keep only properties selling their own rooms.

## `filters` (type: `array`):

Any other filter on Booking's sidebar, by its label as shown there ("Swimming pool", "Free WiFi", "Pets allowed", "Twin beds", "Toilet with grab rails", or a neighbourhood, a hotel brand or a nearby landmark as that sidebar names it: "Le Marais", "Mercure" and "Louvre Museum" in Paris) or its code ("hotelfacility=433"). Labels are matched on each destination's own sidebar, and every run saves that sidebar, with each filter's code and count, in its SEARCH_OPTIONS record.

## `destinationType` (type: `string`):

Force what a name resolves to. "auto" prefers a city over a landmark inside it.

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

Three-letter code, e.g. USD or EUR. Default USD. Left empty, Booking picks a currency from the visitor's location, which can change between runs.

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

Booking language code, e.g. en-gb, en-us, de, fr, ja.

## `delayMs` (type: `integer`):

Optional pause before each call, in milliseconds. 0 (the default) runs as fast as the parallel limit allows. Values above 2000 are treated as 2000.

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

How many requests run at once across the whole run. The default is the fastest level measured clean; lower it only if a run reports refusals or errors.

## Actor input object example

```json
{
  "destinations": [
    "Paris"
  ],
  "checkIn": "2026-11-02",
  "checkOut": "2026-11-03",
  "adults": 2,
  "rooms": 1,
  "childrenAges": [],
  "maxHotelsPerDestination": 100,
  "maxItems": 0,
  "landmark": "",
  "radiusKm": 0,
  "mapBoundingBox": "",
  "mapCentre": "",
  "flexibleMonths": [],
  "flexibleNights": 0,
  "flexibleStartDay": "",
  "flexibleDays": 0,
  "sortBy": "popularity",
  "propertyTypes": [],
  "minStars": 0,
  "minRating": 0,
  "minPricePerNight": 0,
  "maxPricePerNight": 0,
  "mealPlans": [],
  "onlyFreeCancellation": false,
  "noPrepaymentOnly": false,
  "excludePartnerSupplied": false,
  "filters": [],
  "destinationType": "auto",
  "currency": "USD",
  "language": "en-gb",
  "delayMs": 0,
  "maxConcurrency": 32
}
```

# Actor output Schema

## `dataset` (type: `string`):

Booking.com hotel search: every row the run returned.

## `stats` (type: `string`):

Counts for the run: what was resolved, fetched, filtered and returned.

# 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 = {
    "destinations": [
        "Paris"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("boncross/booking-hotel-search").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 = { "destinations": ["Paris"] }

# Run the Actor and wait for it to finish
run = client.actor("boncross/booking-hotel-search").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 '{
  "destinations": [
    "Paris"
  ]
}' |
apify call boncross/booking-hotel-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,boncross/booking-hotel-search"
        }
    }
}
```

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/tKC0tXqeE8ByMRT4e/builds/Hjf6fSVdFdLBLxbb0/openapi.json
