# Booking.com Hotels Scraper & Price Tracker (`myth84/booking-hotels-scraper`) Actor

Booking.com hotels scraper and hotel price tracker (Booking scraper): hotel prices from Booking.com search results for any destination and dates — stay price, taxes, review score, reviews, stars, type, location, photo. Tracks price changes between runs. One flat row per property, no personal data.

- **URL**: https://apify.com/myth84/booking-hotels-scraper.md
- **Developed by:** [Flatrow Data Studio](https://apify.com/myth84) (community)
- **Categories:** Travel, Automation, AI
- **Stats:** 2 total users, 1 monthly users, 75.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.69 / 1,000 properties

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 Hotels Scraper & Price Tracker – hotel prices and ratings, no personal data

Booking.com hotels scraper and hotel price tracker: get hotel prices, taxes, review scores and availability for any destination and dates, as a clean table or through an API — no login. Use it as a Booking scraper for rate shopping, hotel price monitoring and hotel price comparison across dates and destinations.

**No login, no cookies, no personal data:** nothing to sign in to, no cookies to paste, nothing about guests or reviewers in the output.

- **What you get:** one flat row per Booking.com property for any destination and dates, or for the search URLs you paste: total price of the stay, excluded taxes and fees, strike-through price, review score on 10, review count, stars, type, neighbourhood, coordinates, photo and link; a price-monitoring mode that returns only what changed since your previous run. No personal data.
- **For whom:** hoteliers and revenue managers (rate shopping), travel data and BI teams, deal finders and price-alert tools, AI agents through MCP.
- **How much:** from $2.50 per 1,000 properties on the Free plan, lower on paid plans; Apify's free monthly credit of $5 covers about 1,999 properties. A fixed price per property saved and nothing else (compute and proxies included, see the Pricing tab); unchanged prices in monitoring mode are never charged; `maxResults` caps every run.

**Sample output**: one real row from a Lisbon search, key columns only (the full row is under *Output example*):

```json
{
  "platformListingId": "2628938",
  "title": "Villa Baixa - Lisbon Luxury Apartments",
  "city": "Lisboa",
  "checkIn": "2026-11-20",
  "checkOut": "2026-11-23",
  "currency": "EUR",
  "priceTotal": 637.43,
  "taxesAndFees": 62.25,
  "priceTotalAllIn": 699.68,
  "rating": 9.6,
  "reviewCount": 874,
  "starRating": 4
}
```

Scrape Booking.com search results for any destination and dates and get **one flat row per property**: hotels, apartments, aparthotels, hostels, guest houses and B\&Bs with the total price of the stay, the taxes and fees Booking.com shows as excluded, the strike-through price of deals, the review score on 10 and the number of reviews, the official stars, the accommodation type, coordinates and neighbourhood, bedrooms / beds / bathrooms for apartments, badges such as "Limited-time Deal", the free-cancellation flag and the main photo. Search by destination and stay, **up to 50 destinations in one run** with `locations`, or **paste Booking.com search URLs** with their filters; **monitor prices**: in price-monitoring mode a scheduled run compares every property with your previous run of the same search and can return only the new properties and the price changes. This Booking.com scraper reads the same search API as the Booking.com website, without logging in, 100 properties per request, removes duplicates and stops exactly at the number of properties you ask for.

**No personal data, by design.** Nothing about guests or reviewers is collected: no names, no review texts, no profile photos, no ids of persons. The output only contains property-level facts (business names), the average score and the number of reviews. The dataset is safe to store, share and feed to AI agents.

### What can you do with Booking.com data?

- **Track hotel prices** for a destination and dates: rate shopping for hoteliers and revenue managers, deal finders, seasonal price studies, price alerts with a scheduled run. With `monitorPrices` and `onlyChanges`, a daily schedule gives you only the price drops, rises and new properties, and you pay only for those rows.
- **Build accommodation datasets** for a city or a region, with coordinates ready for mapping, stars, type and review scores for segmentation.
- **Compare segments**: hotels vs apartments vs hostels, 3 vs 4 stars, best reviewed vs cheapest, with the same price basis (same stay, same guests, same currency).
- **Feed AI agents, spreadsheets and BI tools** with a stable, documented schema shared by the other scrapers of this travel studio (Airbnb Scraper uses the same columns), so stays from several platforms can be compared.

### What data does Booking.com Scraper extract?

Every row has every column: a value Booking.com does not show in search results is `null` (or `[]` for lists), so CSV and Excel exports keep the same columns from run to run.

| Group | Columns |
|---|---|
| Identity | `schemaVersion`, `platform`, `platformListingId`, `url`, `title`, `propertyType`, `roomType` |
| Location | `city`, `region`, `country`, `countryCode`, `latitude`, `longitude` |
| Stay | `checkIn`, `checkOut`, `nights`, `guests`, `isAvailable` |
| Prices | `currency`, `pricePerNight`, `priceTotal`, `priceBeforeDiscount`, `taxesAndFees`, `taxesIncluded`, `priceTotalAllIn`, `cleaningFee`, `serviceFee` |
| Quality | `rating`, `ratingMax`, `reviewCount`, `starRating`, `badges`, `isSuperhost`, `isNew`, `listedBy`, `cancellationPolicy`, `instantBook` |
| Size | `bedrooms`, `beds`, `bathrooms`, `maxGuests`, `amenities` |
| Photos | `imageUrls`, `imageCount` |
| Search context | `searchLocation`, `searchRank`, `searchPage`, `viewCountryCode`, `scrapedAt` |
| Price monitoring | `changeType`, `previousPrice`, `priceDelta`, `priceDeltaPercent` (null unless `monitorPrices` is on, see below) |

Columns that Booking.com never shows on search result cards stay empty for this Actor: `amenities` (always `[]`), `maxGuests`, `instantBook`, `isNew`, `isSuperhost`, `listedBy` (always `null`), `cleaningFee` and `serviceFee` (Booking.com does not itemise them; `taxesAndFees` holds the excluded charges). `bedrooms`, `beds` and `bathrooms` are shown for apartments and holiday homes, rarely for hotel rooms. `rating` is on a 10-point scale (`ratingMax` is `10`).

**Which price to compare.** On Booking.com, `priceTotal` is the price of the stay **before** the taxes and charges Booking.com shows as excluded, which are in `taxesAndFees`; `taxesIncluded` is then `false` (it is `true` when Booking.com shows an excluded amount of 0, `null` when it shows no excluded amount). `priceTotalAllIn` is the total of the stay **with** them, `priceTotal` + `taxesAndFees` (€637.43 + €62.25 = €699.68 in the sample above), and `null` when the taxes are unknown, never estimated: it is the column to compare stays across platforms, filled with the same rule by every travel scraper of the studio.

### How to scrape Booking.com hotels

1. **Enter a destination** as you would type it on Booking.com ("Lisbon, Portugal", "Paris", "Algarve"), **a list of destinations** in `locations`, or paste one or more **Booking.com search URLs** copied from your browser: their destination, dates, guests, rooms, sort order, filters, currency and language are used as they are. If Booking.com does not recognise a destination text, copy the `dest_id` from a Booking.com search URL into **Destination id**: that path is always reliable.
2. **Choose the stay**: fixed dates (`checkIn` / `checkOut`) for a precise quote, or relative dates (check-in in *N* days for *M* nights, the default) for schedules and recurring price checks that must never expire. Set adults, children (with their ages) and rooms: prices depend on them.
3. **Set the maximum number of properties** and, if needed, the currency, the language, the sort order and the filters: property types, star ratings, minimum review score, price per night, free cancellation, breakfast included (see *Filters* below), or any other Booking.com filter string.
4. **Run** and open the **Output** tab: the *Overview*, *Prices*, *Location* and *Changes* views show the main columns; export everything as JSON, CSV, Excel or through the API.
5. **To follow prices**, schedule the run, tick `monitorPrices` and, to get only what changed, `onlyChanges`: every run after the first returns only the new properties and the price changes (see *Price monitoring* below).

### Input

Give a list of `locations` (one or more destinations), a `destId` or at least one URL in `startUrls`; `location` (a single destination) is still accepted. `checkIn` and `checkOut` go together, otherwise `checkInDaysFromNow` and `nights` apply. Field names and defaults are those of the input form.

The search of our validation run, written with `locations`: 60 properties in Lisbon for a 3-night stay starting in 30 days, 2 adults, 1 room, prices in EUR, Booking.com's top-picks order (every other field keeps its default; the validation run itself pinned Lisbon by its Booking.com destination id, `destId` with `location`):

```json
{
  "locations": ["Lisbon, Portugal"],
  "checkInDaysFromNow": 30,
  "nights": 3,
  "adults": 2,
  "rooms": 1,
  "currency": "EUR",
  "language": "en-us",
  "sortBy": "popularity",
  "maxResults": 60
}
```

Every field, with its type and default:

| Field | Type | Default | Description |
|---|---|---|---|
| `locations` | string\[] | `[]` | One or more destinations as typed on Booking.com (city, region, landmark or address), one per line, searched one after the other with the same dates, guests, rooms, sort, filters, currency and language (up to 50, with `location`), together with the `destId` and the search URLs. When set, `maxResults` applies to each destination and each search URL. Prefilled with `["Lisbon, Portugal"]` in the form (clear it to search a `destId` or search URLs only, otherwise Lisbon is searched too, `maxResults` each); with no `locations`, `location`, `destId` or `startUrls` at all, the Actor searches Lisbon. |
| `location` | string | — | Single destination (kept for compatibility; prefer `locations`), as typed on Booking.com, searched before the destinations of `locations`. Resolved by Booking.com; give `destId` when the text is ambiguous. |
| `destId` | integer | — | Booking.com destination id, the `dest_id` parameter of a search URL, a whole number, negative for cities (e.g. `-2167973` for Lisbon). Optional when the text is enough. |
| `destType` | string | `"CITY"` | Type of the destination id (`dest_type` of the URL): `CITY`, `DISTRICT`, `REGION`, `COUNTRY`, `LANDMARK`, `AIRPORT`, `HOTEL`. `CITY` is validated. |
| `startUrls` | string\[] | `[]` | Booking.com search results URLs copied from your browser (`https://www.booking.com/searchresults.html?ss=…`). Their destination, dates, guests, rooms, sort, `nflt` filters, currency and language are used as they are; the fields below fill what a URL does not set. A URL that is not a results page is refused with the reason. |
| `checkIn` | string | — | Check-in date, YYYY-MM-DD. Leave both dates empty to use relative dates. |
| `checkOut` | string | — | Check-out date, YYYY-MM-DD, after check-in. Required when `checkIn` is set. |
| `checkInDaysFromNow` | integer | `30` | Without fixed dates: check-in this many days from today (UTC). |
| `nights` | integer | `3` | Without fixed dates: length of the stay. |
| `adults` | integer | `2` | Number of adults. |
| `children` | integer | `0` | Number of children (0–17). |
| `childrenAges` | integer\[] | `[]` | Age of each child; a child without a listed age counts as 8 years old. |
| `rooms` | integer | `1` | Number of rooms (units). |
| `maxResults` | integer | `100` | Stop after this many unique properties (100 per request, 1,000 at most): for the whole run, or for each destination and each search URL when `locations` is set. You are never charged for more. In monitoring mode, the number of properties compared. Prefilled with `20` in the form for a quick first run. |
| `sortBy` | string | `"popularity"` | `popularity` (Booking.com's top picks) or `price` (lowest first), both validated; `class`, `review_score_and_price`, `distance_from_search`, `upsort_bh`, `bayesian_review_score` are the other orders of the Booking.com sort bar, not yet verified. |
| `propertyTypes` | string\[] | `[]` | Keep only these accommodation types, several types adding up: `hotels` (validated), `apartments`, `hostels`, `guest_houses`, `bed_and_breakfasts`, `villas`, `holiday_homes`, `aparthotels`, `homestays` (to confirm at the first run). Empty: every type. |
| `starRatings` | integer\[] | `[]` | Official star ratings to keep, from 1 to 5, e.g. `[4, 5]` for 4 or 5 stars. Empty: any rating. To confirm at the first run. |
| `minReviewScore` | integer | — | Minimum guest review score out of 10: `6`, `7`, `8` or `9`. To confirm at the first run. |
| `priceMin` | integer | — | Lowest price per night, in the currency of the search (whole amount, 0 to 1,000,000,000). To confirm at the first run. |
| `priceMax` | integer | — | Highest price per night, in the currency of the search, greater than `priceMin` (whole amount, up to 1,000,000,000). To confirm at the first run. |
| `freeCancellation` | boolean | `false` | Only properties offering free cancellation. To confirm at the first run. |
| `breakfastIncluded` | boolean | `false` | Only properties with breakfast included. To confirm at the first run. |
| `filters` | string | — | For experts: any other Booking.com filter, the `nflt` parameter of a search URL, filters separated by `;` (e.g. `ht_id=204`, validated). The filter fields above are added to it without duplicates. |
| `currency` | string | `"EUR"` | ISO 4217 code of the currency of every price (EUR and USD validated, any Booking.com currency accepted). |
| `language` | string | `"en-us"` | Booking.com language code for types, neighbourhoods and badges: `en-us` (validated), `en-gb`, `fr`, `de`, `es`, `it`, `pt-pt`… (pick one from the list or type any code). |
| `monitorPrices` | boolean | `false` | Compare the total price of every property with the one recorded by your previous run of the same search (`changeType`, `previousPrice`, `priceDelta`, `priceDeltaPercent`). |
| `monitorStoreName` | string | `"booking-price-monitor"` | Key-value store of your account that keeps the previous prices (one record per search). Letters, digits and dashes. |
| `onlyChanges` | boolean | `false` | With `monitorPrices`: save and charge only the new properties and the price changes; a run without any change succeeds with an empty dataset. |
| `proxyConfiguration` | object | `{"useApifyProxy":true}` | Apify datacenter proxies by default (enough for the search API in our tests), included in the price; keep them, or bring your own proxy URLs. A proxy country is recorded in `viewCountryCode`. |
| `maxRequests` | integer | `100` | Safety cap on API requests per run (100 properties per request, plus one to three light requests to resolve a destination given as text, more when Booking.com has to be asked again). |
| `delayMs` | integer | `800` | Pause between two page requests of the same search, in milliseconds. |
| `debugStoreHtml` | boolean | `false` | Debugging only: store every API response (JSON) in the key-value store. |

**Several destinations in one run.** List them in `locations` (with or without `location`): each destination is searched on its own with the same dates, guests, rooms, sort, filters, currency and language, and `maxResults` applies to each of them. This input returns up to 50 properties for each of the three cities, 150 at most:

```json
{
  "locations": ["Paris, France", "Rome, Italy", "Barcelona, Spain"],
  "checkInDaysFromNow": 30,
  "nights": 3,
  "adults": 2,
  "currency": "EUR",
  "maxResults": 50
}
```

The `searchLocation` column tells which destination found each property. A property found by two destinations (a city and one of its districts) is saved and charged once, under the first destination of the list. Without `locations`, `maxResults` keeps capping the whole run, `location` (or `destId`) and search URLs together.

### Output example

One real row, produced by the Actor from a Lisbon search (EUR, English, 20–23 November 2026, 2 adults, 1 room). All columns are present, in this order, for every property:

```json
{
  "schemaVersion": "travel-listing/1.5",
  "platform": "booking",
  "platformListingId": "2628938",
  "url": "https://www.booking.com/hotel/pt/villa-baixa-lisbon-luxury-apartments.html?checkin=2026-11-20&checkout=2026-11-23&group_adults=2&group_children=0&no_rooms=1&selected_currency=EUR&lang=en-us",
  "title": "Villa Baixa - Lisbon Luxury Apartments",
  "propertyType": "Aparthotel",
  "roomType": "entire_place",
  "city": "Lisboa",
  "region": "Santa Maria Maior",
  "country": "Portugal",
  "countryCode": "PT",
  "latitude": 38.7124951804023,
  "longitude": -9.13769279818235,
  "checkIn": "2026-11-20",
  "checkOut": "2026-11-23",
  "nights": 3,
  "guests": 2,
  "currency": "EUR",
  "pricePerNight": 212.48,
  "priceTotal": 637.43,
  "priceBeforeDiscount": 910.61,
  "cleaningFee": null,
  "serviceFee": null,
  "taxesAndFees": 62.25,
  "taxesIncluded": false,
  "priceTotalAllIn": 699.68,
  "rating": 9.6,
  "ratingMax": 10,
  "reviewCount": 874,
  "starRating": 4,
  "bedrooms": 1,
  "beds": 2,
  "bathrooms": 1,
  "maxGuests": null,
  "amenities": [],
  "badges": [
    "Limited-time Deal"
  ],
  "isSuperhost": null,
  "listedBy": null,
  "instantBook": null,
  "isNew": null,
  "isAvailable": true,
  "cancellationPolicy": "free_cancellation",
  "imageUrls": [
    "https://cf.bstatic.com/xdata/images/hotel/square600/736934046.webp?k=7cf29ad6bc51ef6ac4fa95219b49ce0a6099661e41c2cbbf1c7ebe149dbd04b0&o="
  ],
  "imageCount": 1,
  "searchLocation": "Lisbon, Portugal",
  "searchRank": 1,
  "searchPage": 1,
  "viewCountryCode": null,
  "scrapedAt": "2026-10-19T08:00:00.000Z",
  "changeType": null,
  "previousPrice": null,
  "priceDelta": null,
  "priceDeltaPercent": null
}
```

A hotel room row has `roomType` `hotel_room`, `bedrooms` / `bathrooms` `null`, and `priceBeforeDiscount` `null` unless the hotel runs a deal; a hostel dorm bed has `roomType` `shared_room`.

The last four columns are filled in price-monitoring runs only (see below).

The **Output** tab offers four views of the same rows: **Overview** (name, type, stars, city, dates, prices, score, reviews, link, photo), **Prices** (nights, nightly average, total, strike-through price, excluded taxes, currency, cancellation, deals), **Location** (city, neighbourhood, country, coordinates, rank) and **Changes** (price-monitoring runs: change type, dates, total price, previous total, difference, search, link).

### Filters

Pick the usual Booking.com filters in the form instead of copying a filter string: each field becomes the element of Booking.com's `nflt` filter string shown below, the string the website itself puts in its search URLs.

| Field | Booking.com filter | Sent to Booking.com as | Status |
|---|---|---|---|
| `propertyTypes` | Property type (several types add up) | `ht_id=204` hotels, `ht_id=201` apartments, `ht_id=203` hostels, `ht_id=216` guest houses, `ht_id=208` bed and breakfasts, `ht_id=213` villas, `ht_id=220` holiday homes, `ht_id=219` aparthotels, `ht_id=222` homestays | hotels validated; the other types to confirm at the first run |
| `starRatings` | Property rating (several ratings add up) | `class=4;class=5` for `[4, 5]` | to confirm at the first run |
| `minReviewScore` | Review score: 6+, 7+, 8+ or 9+ out of 10 | `review_score=80` for `8` | to confirm at the first run |
| `priceMin`, `priceMax` | Your budget, per night, in the currency of the search | `price=EUR-50-150-1` for 50 to 150 EUR (an open bound is sent as `0` or `max`) | to confirm at the first run |
| `freeCancellation` | Free cancellation | `fc=2` | to confirm at the first run |
| `breakfastIncluded` | Breakfast included | `mealplan=1` | to confirm at the first run |

4- and 5-star hotels in Paris rated 8 or more, under 250 EUR a night, with free cancellation, for 2 adults and 3 nights starting in 30 days:

```json
{
  "location": "Paris, France",
  "propertyTypes": ["hotels"],
  "starRatings": [4, 5],
  "minReviewScore": 8,
  "priceMax": 250,
  "freeCancellation": true,
  "checkInDaysFromNow": 30,
  "nights": 3,
  "adults": 2,
  "currency": "EUR",
  "maxResults": 50
}
```

This input sends `ht_id=204;class=4;class=5;review_score=80;price=EUR-0-250-1;fc=2` to Booking.com.

- **Several filters combine like on the website**: several values of the same filter add up (4 *or* 5 stars, hotels *or* apartments), different filters narrow the search (4 or 5 stars *and* rated 8+).
- **With `filters` and search URLs.** The fields are added, without duplicates, to the `filters` string (for any other Booking.com filter) and to the `nflt` filters of every pasted search URL. A URL keeps its own price range and minimum score when it already has one, and the log names the field value left out; the same price range or minimum score given twice in the form with two different values (in the fields and in `filters`) is refused before the run starts.
- **Prices are per night**, in `currency` or in the currency of a pasted URL, whole amounts, like Booking.com's budget filter; `priceTotal` in the output is the total of the stay.
- **To confirm at the first run.** Hotels only (`ht_id=204`) is the filter validated in our tests; the other values are Booking.com's own filter values, sent as they are. The start line of the run log lists the filters each search sends and the ones not verified yet (`filterFields`). Check the stars, scores and types of the first rows; if a filter seems ignored, open an issue with your run id.
- **Empty fields change nothing**: with no filter field set, the requests, the rows and the charges are those of a run without them.

### Search URLs

Set the destination, dates, guests, sort order and filters on Booking.com, then paste the URL of the results page into `startUrls`. The Actor converts the parameters it knows to its own search: `ss`, `dest_id` and `dest_type` (destination), `checkin` and `checkout` (dates), `group_adults`, `group_children` and `age` (guests), `no_rooms` (rooms), `order` (sort), `nflt` (filters), `selected_currency` and `lang`. What a URL does not carry comes from the form: a URL without dates uses the relative dates (`checkInDaysFromNow`, `nights`), so a scheduled task made of URLs never expires; the filter fields of the form are added to the URL's `nflt` filters (see *Filters*). Tracking parameters are ignored; other unknown parameters are listed in the run log. A URL that is not a Booking.com results page (a property page, the home page, another site) or that names no destination is refused before the run starts, with the reason. Several URLs run one after the other in the same dataset; the form destination runs too when you keep one.

### Price monitoring

Tick `monitorPrices`, then **schedule the run** (daily is typical). The scraper keeps the last total price of every property it compared in a key-value store of your account named `monitorStoreName` (`booking-price-monitor` by default), with one record per search (same destination, stay, guests, rooms, sort, filters, currency and language). The first run of a search is the reference: every property comes back with `changeType` = `"new"` (and `RUN_STATS.monitorBaseline` is true). From the second run on, every property is compared with the recorded one: `price_changed` rows carry `previousPrice` (the previous total of the stay), `priceDelta` and `priceDeltaPercent`, the others are `unchanged`. With `onlyChanges` the dataset holds **only the new properties and the price changes**, and **only those rows are charged**; a run where nothing changed succeeds with an empty dataset. In both cases `maxResults` is the number of properties compared by the run.

A scheduled input that watches the 100 top-pick Lisbon hotels for a stay one month ahead:

```json
{
  "location": "Lisbon, Portugal",
  "destId": -2167973,
  "filters": "ht_id=204",
  "checkInDaysFromNow": 30,
  "nights": 3,
  "adults": 2,
  "currency": "EUR",
  "maxResults": 100,
  "monitorPrices": true,
  "onlyChanges": true
}
```

A `price_changed` row, as the Actor produces it from the row of the output example when the previous run had recorded a total of 699 EUR (the other columns are the same as above):

```json
{
  "platformListingId": "2628938",
  "title": "Villa Baixa - Lisbon Luxury Apartments",
  "checkIn": "2026-11-20",
  "checkOut": "2026-11-23",
  "currency": "EUR",
  "priceTotal": 637.43,
  "changeType": "price_changed",
  "previousPrice": 699,
  "priceDelta": -61.57,
  "priceDeltaPercent": -8.8
}
```

What to know before relying on it:

- **Fixed dates compare one stay; relative dates compare a lead time.** With `checkIn` / `checkOut`, the record follows the price of that stay until it passes. With relative dates (the default), the record follows the price of the stay *N days ahead for M nights*: each run searches new dates, so a change mixes the hotel's pricing and the calendar (weekday, season). Both are useful; just know which one you track. Changing `checkInDaysFromNow` or `nights` starts a new reference.
- **The record is written only after a clean run.** A blocked or failed search, an unresolved destination, a charge limit reached in the middle of a run or an interrupted run never overwrites the reference, so a bad day cannot erase your prices; the log says when a record was kept unchanged.
- **Same currency only.** A price is compared only with a previous total in the same currency; when Booking.com answers in another currency, the property is reported `unchanged` and the new currency becomes the reference.
- **Rankings move.** Booking.com's top-picks order varies between sessions, so the set of compared properties (the first `maxResults` of the run) drifts a little from run to run; a property that drops out of the results and comes back later is not reported as new (its last price is kept for 90 days). Sort by `price` or narrow the search with `filters` for a steadier set.
- **One record per search.** Runs sharing a `monitorStoreName` share the records; changing the destination, stay, guests, rooms, sort, filters, currency or language of a search starts a new reference for it. Each destination of `locations` has its own record; keep the same list, in the same order, from run to run, since a property found by two destinations is compared under the first one. Delete the key-value store in Apify Console to start over.

### How much does it cost to scrape Booking.com?

This Actor uses **pay-per-event pricing: you pay a fixed price per property** saved to your dataset, and nothing else. On the Free plan, properties cost $2.50 per 1,000, so Apify's free monthly credit of $5 covers about 1,999 properties; paid plans pay less per property, and the price of every plan tier is on the **Pricing tab** of this page.

| What you pay for | How it is counted | Price |
|---|---|---|
| `result` event: one property saved to your dataset | once per unique property of the run, capped by `maxResults` (per destination with `locations`) | Pricing tab, per plan tier |
| Run start | a symbolic amount, once per run | Pricing tab |
| Compute, proxies, storage and data transfer | included: no platform usage is passed on to you | — |

The cost of a run is known before you start: 1,000 properties cost 1,000 times the `result` price of your tier, whatever the number of pages fetched. In price-monitoring mode with `onlyChanges`, only the new properties and the price changes are charged. One request returns 100 properties in about a second, so a run of several hundred properties takes well under a minute.

### Limits and behaviour worth knowing

- **One stay per search.** Every row of a search shares the same `checkIn`, `checkOut`, `guests` and `currency`, which is what makes prices comparable; with several destinations (`locations`) or search URLs, each one is its own search in the same dataset (`searchLocation` tells them apart). Schedule several tasks if you prefer separate datasets.
- **About 1,000 properties per search.** Booking.com announces thousands of results for a big city but serves a limited depth per search; the scraper stops at the first empty page and reports it in the log. Narrow the search with the filters (`propertyTypes`, `starRatings`, `minReviewScore`, `priceMin` / `priceMax`) or use district destination ids to cover a whole city.
- **`priceTotal` is the total of the stay for the unit Booking.com matched** to your guests and rooms, after discounts and before the charges Booking.com lists as excluded (`taxesAndFees`: city tax, VAT or service charges depending on the destination); `priceTotalAllIn` adds them back. `pricePerNight` is the average per night (`priceTotal / nights`). `priceBeforeDiscount` is the strike-through total of a deal.
- **Rankings move and sponsored cards appear.** Booking.com's top-picks order varies between sessions and a sponsored property can be added on top of a page. The scraper keeps one session per search, removes duplicates by property id and counts sponsored cards in the run statistics. The `price` order is exact.
- **Text destinations are resolved by Booking.com**: without the filters (they apply to the search itself), then through Booking.com's suggestions for the full text and for the city alone, with a few retries when an answer is empty or in error. When the text is still not recognised, the run fails with an explicit message asking for `destId`. The `dest_id` of a Booking.com search URL always works.
- **Search cards show a subset of the property.** Amenities, maximum guests, room-level cancellation terms beyond the free-cancellation flag and the full photo gallery are not in search results and are therefore `null` or empty. Property pages and availability calendars are not covered by this Actor.
- **Blocking.** The Booking.com search API answered every request from Apify datacenter proxies in our tests. If a response is unusable, the scraper opens a new session and retries once, then gives up on that search and reports it. If a whole run is blocked, raise `delayMs` and try again later, or open an issue with your run id: blocking changes are fixed as a priority.
- **No empty successes.** A run that finds no property ends as failed with an explicit message (destination not recognised, dates in the past, filters too strict, or blocked), so that your schedules and integrations notice. The one exception is a price-monitoring run that compared properties and found no change: it succeeds with an empty dataset.

### Integrations and API

Start the Actor from Apify Console, schedule it, or call it from the [Apify API](https://docs.apify.com/api/v2) with any language (the **API** tab shows ready-made code for Node.js, Python and curl). Webhooks notify your systems when a run finishes; the dataset can be pulled as JSON, CSV, Excel, XML or RSS from the run's Output tab, or pushed to Google Sheets, Make, Zapier, n8n, Slack, Airtable, Google Drive and more through the Apify integrations. AI agents can call the Actor through the Apify MCP server.

For bugs or questions, open an issue in the **Issues** tab of this Actor with your run id and input: bugs and API changes are fixed as a priority, feature requests (property details, availability calendars, other platforms of the travel studio) are welcome.

### Use it from your AI assistant

Add this Actor as a tool to Claude, ChatGPT, Cursor, VS Code or any MCP client with the Apify MCP server URL below (sign in with your Apify account when asked):

`https://mcp.apify.com?tools=myth84/booking-hotels-scraper`

Then ask in plain words. Copy this prompt and change the details:

```text
Use myth84/booking-hotels-scraper to find 20 hotels in Rome, Italy for 2 adults, 2 nights starting 30 days from today, prices in EUR, cheapest first. Input: {"location": "Rome, Italy", "checkInDaysFromNow": 30, "nights": 2, "adults": 2, "currency": "EUR", "sortBy": "price", "propertyTypes": ["hotels"], "maxResults": 20}. Show the name, total price, excluded taxes, review score, number of reviews and link of each hotel.
```

### For AI agents (MCP)

Through the [Apify MCP server](https://docs.apify.com/mcp) this Actor is a tool that answers questions such as *"what do hotels in Lisbon cost for two adults from 20 to 23 November?"*, *"list the best-reviewed 4-star hotels in Paris under 200 EUR a night"* or *"compare hotel prices in Barcelona and Valencia next month"*.

**Minimal input** (one or more destinations in `locations`, `maxResults` per destination; every other field keeps its default, raise `maxResults` only when the question needs more rows):

```json
{
  "locations": ["Barcelona, Spain", "Valencia, Spain"],
  "checkInDaysFromNow": 30,
  "nights": 2,
  "adults": 2,
  "currency": "EUR",
  "maxResults": 20
}
```

- **Key output fields**: `platformListingId`, `title`, `url`, `priceTotal`, `pricePerNight`, `taxesAndFees`, `currency`, `rating` (on 10), `reviewCount`, `starRating`, `propertyType`, `region`, `latitude` / `longitude`, `cancellationPolicy`; in monitoring mode `changeType`, `previousPrice`, `priceDelta`. Every column is always present, in a fixed order; `null` means Booking.com did not show the value. The full list is in *What data does Booking.com Scraper extract?* above.
- **Use it when** you need current Booking.com search results for a destination and a stay: total prices, taxes, review scores, review counts, stars, type, location, photo. Pass `locations` (one or more destinations, searched one by one, `maxResults` each) or `location` (or `destId`), the dates (`checkIn` / `checkOut`, or `checkInDaysFromNow` + `nights`), `adults`, `children` with `childrenAges`, `currency`, optionally `sortBy` and the filters (`propertyTypes`, `starRatings`, `minReviewScore`, `priceMin` / `priceMax`, `freeCancellation`, `breakfastIncluded`, or a raw `filters` string), and a small `maxResults` (10–50 is enough for an answer); or pass a Booking.com results URL in `startUrls`. To report price changes between two calls, pass `monitorPrices: true`, `onlyChanges: true` and the same search and `monitorStoreName`.
- **Do not use it for** guest reviews, property descriptions and amenities, availability calendars, booking or anything behind a login: it does not collect personal data and only reads public search results.
- **Cost per 1,000 results**: 1,000 `result` events, $2.50 per 1,000 on the Free plan and less on paid plans (Pricing tab); nothing else is charged (in monitoring mode with `onlyChanges`, unchanged prices are free).
- **Typical time**: about a second per request of 100 properties: 20 properties in a few seconds, several hundred in well under a minute.

### Alternatives and switching

- **Official API.** Booking.com's APIs are made for its accommodation and affiliate partners and need an approved partner account; if you have one and need bookings or contracted rates, use it. This Actor reads what any visitor sees in Booking.com search results (public prices, excluded taxes, review scores, stars) with no account, no keys and no approval.
- **Your own scraper.** Nothing to build or maintain: sessions, retries, pagination, deduplication and Booking.com page changes are handled for you. The columns stay the same from run to run, a run that finds nothing fails with an explicit message instead of succeeding empty, and a scheduled test run catches Booking.com changes early.
- **Another scraper from the Store.** What you can count on here: `maxResults` is a hard cap (per destination with `locations`), the run stops at that number of properties and you are never charged for more; with `monitorPrices` and `onlyChanges`, a scheduled run returns and charges only the new properties and the price changes; `priceTotalAllIn` gives one total, taxes included, to compare with the other platforms. The input names differ from one Actor to the next; the usual ones map to this Actor as follows:

| Usual input | Here | Note |
|---|---|---|
| `search`, `query`, `destination` | `location`, `locations` for up to 50 places, or `destId` | Text as typed on Booking.com, or the exact `dest_id` |
| `startUrls` | `startUrls` | Booking.com search results URLs, filters included |
| `maxItems`, `limit` | `maxResults` | Unique properties per run, never charged beyond |
| `checkin`, `checkout` | `checkIn`, `checkOut` | YYYY-MM-DD; or `checkInDaysFromNow` + `nights` for schedules |
| `adults`, `children`, `rooms` | `adults`, `children` + `childrenAges`, `rooms` | Prices depend on them |
| `minScore` | `minReviewScore` | 6, 7, 8 or 9 out of 10 |
| `stars`, `starsCountFilter` | `starRatings` | A list, e.g. `[4, 5]` |
| `propertyType` | `propertyTypes` | A list, e.g. `["hotels", "apartments"]` |
| `minMaxPrice`, `minPrice`, `maxPrice` | `priceMin`, `priceMax` | Per night, in the currency of the search |
| `nflt` | `filters` | Any other Booking.com filter string, e.g. `ht_id=204` |
| `sort` | `sortBy` | `popularity` or `price` |
| `currency`, `language` | `currency`, `language` | ISO 4217 code, Booking.com language code |
| `proxy` | `proxyConfiguration` | Apify proxies, included in the price |

### FAQ

#### Does Booking.com Scraper collect personal data?

No. The scraper reads search result cards only and keeps nothing about guests or reviewers: no names, photos, profile ids, contact details or review texts. It outputs property facts (business names and addresses at the neighbourhood level), the average review score and the number of reviews. Every row goes through a privacy filter before it is saved.

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

The Actor only reads search results that Booking.com serves to any visitor without an account, and it stores no personal data. Scraping public data is generally lawful, but you are responsible for how you use the results and for complying with Booking.com's terms of service and the laws that apply to you (including copyright on property texts and photos). Use the data for analysis, not to republish listings.

#### Why are the prices different from what I see in my browser?

Prices depend on the stay (dates, adults, children ages, rooms), the currency and the moment: Booking.com runs time-limited deals and member rates (never used here: no login). Compare rows obtained with the same input, and check `taxesAndFees`: Booking.com shows some charges excluded from the headline price, and `priceTotalAllIn` is the total with them.

#### What if my runs get blocked? Do I need proxies?

Apify datacenter proxies (the default) worked for every request in our tests and are included in the price. If a run reports blocked requests, increase `delayMs` and try again later, or bring your own proxy URLs; persistent blocking is fixed as a priority, open an issue with your run id.

#### How do I get more than 1,000 properties for a city, or fewer duplicates?

Booking.com limits the depth of one search. Split the city: one run per accommodation type (`propertyTypes`), per star rating (`starRatings`) or per price range (`priceMin` / `priceMax`), or one run per district with its `destId`. Across runs, deduplicate by `platformListingId`; inside a run the scraper already does it.

#### Can I search several cities in one run?

Yes. Put up to 50 destinations in `locations`, one per line ("Paris, France", "Rome, Italy", "Barcelona, Spain"…), alongside or instead of `location`. Each destination is a separate search with the same dates, guests, rooms, filters and currency, and `maxResults` applies to each destination: 3 cities with `maxResults` 50 give up to 150 properties. Every row says in `searchLocation` which destination found it, and a property found by two destinations is saved and charged once. Large lists need more requests: raise `maxRequests` if the log says that some destinations were not searched.

#### Which currencies, languages and dates can I use?

Any currency Booking.com accepts (`currency`, ISO 4217 code; EUR and USD validated) and any Booking.com language code (`language`; `en-us` validated). Prices are converted by Booking.com into the requested currency; property types, neighbourhoods and badges come in the requested language. For dates, give `checkIn` and `checkOut` for a quote on precise dates, or leave them empty: the Actor then searches a stay starting `checkInDaysFromNow` days from today for `nights` nights (relative dates), so that a scheduled run or an example task never expires.

#### The run says the location could not be resolved. What should I do?

The Actor asks Booking.com to recognise your destination text, and tries again on its own when an answer comes back empty or in error; the reason of each attempt is in the log. If the run still fails, run it again a few minutes later, write the destination as "City, Country" (for example "Rome, Italy"), or, for a result that never depends on the text, give `destId`: open a Booking.com search for the place in your browser and copy the `dest_id` (and `dest_type`) of the URL, or paste the whole URL into `startUrls`. A destination Booking.com does not know at all ends with the same message after the retries.

#### Which filters are supported? Can I use a Booking.com search URL?

The form has a field for the filters most people use: property types (`propertyTypes`), star ratings (`starRatings`), minimum review score (`minReviewScore`), price per night (`priceMin` / `priceMax`), free cancellation (`freeCancellation`) and breakfast included (`breakfastIncluded`); *Filters* above shows what each one sends. Hotels only is validated; the other values are Booking.com's own filter values, to confirm at the first run, and the run log lists them. For any other filter of the website, copy the `nflt` parameter of a Booking.com search URL into `filters` (several filters separated by `;`), or paste the whole URL into `startUrls`: its destination, dates, guests, rooms, sort order, `nflt` filters, currency and language are used as they are, the form fills what the URL does not set (relative dates when it has none), and the filter fields are added to the URL's filters without duplicates.

#### How often should I run it, and how do I get only price changes?

Every run fetches live search results. Prices and availability change daily, so schedule the Actor as often as your use case needs (daily is typical for price tracking) and compare runs by `platformListingId`, `checkIn` and `checkOut`, or let the Actor compare them for you: tick `monitorPrices` (and `onlyChanges`) and schedule the run. The first run records every property of the search and returns it as `new`; each later run flags the properties that appeared since and the properties whose total price changed, with `previousPrice`, `priceDelta` and `priceDeltaPercent`, and with `onlyChanges` returns and charges only those rows. A run without any change succeeds with an empty dataset. The previous prices live in the key-value store `monitorStoreName` of your account; keep the same destination, stay, guests, sort, filters, currency and language from run to run. With relative dates you follow the price of a stay at a constant lead time; with fixed dates, the price of one stay.

### More scrapers by Flatrow Data Studio

The travel scrapers of the studio share the same core columns, so stays from several platforms land in one table; compare their prices on `priceTotalAllIn`, the total of the stay with taxes and fees, filled with the same rule by each scraper (`null` when a platform does not show the taxes):

- [Airbnb Listings Scraper & Price Tracker](https://apify.com/myth84/airbnb-listings-scraper): Airbnb prices, ratings, review counts and locations for any place and dates, up to 50 destinations per run, with price monitoring.
- [Airbnb Listing Details & Availability Calendar](https://apify.com/myth84/airbnb-listing-details-scraper): amenities, house rules, six category ratings and a 1–12 month availability calendar for the Airbnb listing URLs you give.
- [Expedia Hotels Scraper: Prices & Ratings](https://apify.com/myth84/expedia-hotels-scraper): Expedia hotel prices per night and for the whole stay, guest ratings and review counts, to compare with the other platforms.

Did this scraper give you the data you needed? A rating on its Store page helps other people find it. For a bug or a missing field, open an issue in the **Issues** tab.

### Legal note

This Actor reads publicly available Booking.com search results without logging in and collects no personal data. You are responsible for your use of the data and for complying with Booking.com's terms and the laws that apply to you.

Not affiliated with, endorsed or sponsored by Booking.com. Booking.com is a trademark of Booking.com B.V.

# Changelog

This Actor's version history is a separate document: https://apify.com/myth84/booking-hotels-scraper/changelog.md

# Actor input Schema

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

One or more destinations, one per line, as typed on Booking.com, e.g. <code>Lisbon, Portugal</code>, <code>Rome, Italy</code>. Each is its own search with the same dates, guests, filters and currency, and <b>maxResults applies to each destination</b> (and to each search URL). A property found twice is saved and charged once. Always searched, also with destId or startUrls: clear the list to search those only. Up to 50. Default empty; with no destination at all, the Actor searches Lisbon.

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

Booking.com search results URLs copied from your browser (<code>https://www.booking.com/searchresults.html?ss=…</code>), one search each: their destination, dates, guests, rooms, sort, filters (<code>nflt</code>), currency and language are kept, and the form fills what a URL leaves out. A URL that is not a results page is refused with the reason. Default empty: search by destination.

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

Single destination (kept for compatibility; prefer <code>locations</code>), as typed in the Booking.com search box, e.g. <code>Lisbon, Portugal</code>; searched first, before the destinations of <code>locations</code> (up to 50 together). If Booking.com cannot resolve the text, give its <code>destId</code>. Leave empty when you use locations.

## `destId` (type: `integer`):

Booking.com destination id, the reliable way to target a place: the <code>dest_id</code> of a search URL, a whole number, negative for cities, e.g. <code>-2167973</code> for Lisbon. Searched for <code>location</code>, or alone. Optional when the destination text is resolved. The destinations of <code>locations</code> are searched too: clear that list (prefilled with Lisbon) to search this id only.

## `destType` (type: `string`):

Type of the destination id (<code>dest_type</code> of the search URL): CITY, DISTRICT, REGION, COUNTRY, LANDMARK, AIRPORT or HOTEL. Default CITY: the type of most destination ids, and the one validated.

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

Check-in date, YYYY-MM-DD, e.g. <code>2026-12-01</code>, given with checkOut. Leave both empty for a stay relative to today (checkInDaysFromNow and nights), better for schedules: fixed dates expire.

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

Check-out date, YYYY-MM-DD, after checkIn, e.g. <code>2026-12-04</code>. Required when checkIn is set.

## `checkInDaysFromNow` (type: `integer`):

Without fixed dates: check-in this many days after today (UTC), e.g. <code>7</code> for next week. Default 30: a month ahead, a typical booking window, and the stay moves with each scheduled run so it never expires.

## `nights` (type: `integer`):

Without fixed dates: length of the stay in nights, 1 to 30. Default 3: a typical city break.

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

Number of adults, 1 to 30; prices depend on it. Default 2: the most searched occupancy.

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

Number of children (0 to 17 years old); give their ages in childrenAges, prices depend on them. Default 0: adults only.

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

Age of each child, one number per child, e.g. <code>\[5, 9]</code>. Default empty: a child without a listed age counts as 8 years old.

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

Number of rooms (units) to book, 1 to 30. Default 1: one room for all the guests.

## `maxResults` (type: `integer`):

Maximum number of properties saved and charged, 1 to 1,000 (Booking.com serves about 1,000 per search; one request returns 100). With <code>locations</code> it applies to each destination; with price monitoring it is the number compared. Default 100: enough to compare a city, about $0.25 on the Free plan. The form is prefilled with 20 for a quick first run.

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

Order of the results: <code>popularity</code> (Booking.com's top picks) and <code>price</code> (lowest first) are validated; the other orders of the Booking.com sort bar are passed as they are. Default popularity: the order visitors see first.

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

Keep only these accommodation types, e.g. <code>\["hotels"]</code>; several types add up. Hotels is validated; the other types are Booking.com's own filter values, to confirm at the first run (the run log lists them). Default empty: every type.

## `starRatings` (type: `array`):

Keep only these official star ratings, numbers from 1 to 5, e.g. <code>\[4, 5]</code> for 4 or 5 stars. To confirm at the first run. Default empty: any rating.

## `minReviewScore` (type: `integer`):

Minimum guest review score out of 10: 6, 7, 8 or 9, e.g. <code>8</code> for "Very good: 8+". To confirm at the first run. Leave empty for any score.

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

Lowest price per night, a whole amount in the currency of the search, e.g. <code>50</code> (Booking.com's budget filter), 0 to 1,000,000,000 so that currencies counted in millions (IDR, VND) fit. To confirm at the first run. Leave empty for no minimum.

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

Highest price per night, a whole amount in the currency of the search, greater than priceMin, e.g. <code>150</code>, 1 to 1,000,000,000. To confirm at the first run. Leave empty for no maximum.

## `freeCancellation` (type: `boolean`):

Keep only the properties that offer free cancellation. To confirm at the first run. Default off: every property.

## `breakfastIncluded` (type: `boolean`):

Keep only the properties with breakfast included. To confirm at the first run. Default off: every property.

## `filters` (type: `string`):

For experts: any other Booking.com filter, as the <code>nflt</code> parameter of a search URL, filters separated by <code>;</code>, e.g. <code>ht_id=204</code> for hotels only. The filter fields above are added to it; the README lists the supported values. Leave empty for none.

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

ISO 4217 code of every price, e.g. <code>USD</code>, <code>EUR</code> or <code>GBP</code>; pick one or type any code Booking.com accepts (USD and EUR validated). Default EUR: the currency of our validation runs.

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

Booking.com language of property types, neighbourhoods and badges, e.g. <code>en-us</code>, <code>en-gb</code>, <code>fr</code>, <code>de</code>, <code>es</code>; pick one or type any Booking.com code. Default en-us: English (US), the language validated.

## `monitorPrices` (type: `boolean`):

Compare the total price of each property with the one recorded by your previous run of the same search, and fill changeType, previousPrice and priceDelta. maxResults is then the number of properties compared. Default off: a plain search.

## `monitorStoreName` (type: `string`):

Key-value store of your account that keeps the previous prices, one record per search (each destination has its own), e.g. <code>booking-lisbon-daily</code>. Letters, digits and dashes, up to 63 characters. Default booking-price-monitor: one store for all your monitoring runs.

## `onlyChanges` (type: `boolean`):

With monitorPrices: save and charge only the new properties and the price changes; a run without any change succeeds with an empty dataset. Default off: every compared property is saved with its changeType.

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

Proxies of the requests. Default: Apify datacenter proxies, included in the price and enough in our tests. A proxy country you select is recorded in viewCountryCode; you can also give your own proxy URLs.

## `maxRequests` (type: `integer`):

Safety cap on API requests for the whole run: one per 100 properties, plus about one to resolve a destination given as text. Default 100: enough for 50 destinations of 100 properties.

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

Pause between two page requests of the same search, in milliseconds; 0 disables it. Default 800: steady pacing that worked for every request of our tests.

## `debugStoreHtml` (type: `boolean`):

Debugging only: save every API response (JSON) in the run's key-value store. Default off: it uses storage.

## Actor input object example

```json
{
  "locations": [
    "Lisbon, Portugal"
  ],
  "startUrls": [],
  "destType": "CITY",
  "checkInDaysFromNow": 30,
  "nights": 3,
  "adults": 2,
  "children": 0,
  "childrenAges": [],
  "rooms": 1,
  "maxResults": 20,
  "sortBy": "popularity",
  "propertyTypes": [],
  "starRatings": [],
  "freeCancellation": false,
  "breakfastIncluded": false,
  "currency": "EUR",
  "language": "en-us",
  "monitorPrices": false,
  "monitorStoreName": "booking-price-monitor",
  "onlyChanges": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxRequests": 100,
  "delayMs": 800,
  "debugStoreHtml": false
}
```

# Actor output Schema

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

All extracted properties as dataset items, one flat row per property. Append ?format=csv or ?format=xlsx for spreadsheets. The Overview view is selected by default.

## `runStats` (type: `string`):

Requests made, bytes transferred, blocked requests, duplicates and sponsored cards seen, properties seen and pushed, and the estimated platform cost of the run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "locations": [
        "Lisbon, Portugal"
    ],
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("myth84/booking-hotels-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "locations": ["Lisbon, Portugal"],
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("myth84/booking-hotels-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "locations": [
    "Lisbon, Portugal"
  ],
  "maxResults": 20
}' |
apify call myth84/booking-hotels-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,myth84/booking-hotels-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/G6OSvwdklPh2Rvall/builds/0E5I0cClA9Hafm0wn/openapi.json
