# Booking.com Scraper — Rate & Value Report (`api-empire/booking-scraper`) Actor

Scrape Booking.com property rates, room details, availability, ratings, reviews, amenities, and value indicators. Compare hotel pricing and value across properties and dates to support travel research, competitor analysis, market intelligence, and pricing strategies.

- **URL**: https://apify.com/api-empire/booking-scraper.md
- **Developed by:** [API Empire](https://apify.com/api-empire) (community)
- **Categories:** Travel, Lead generation, Automation
- **Stats:** 7 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### Booking.com Scraper — Hotels, Room Rates and Value Scores as JSON

Booking.com Scraper — Rate & Value Report extracts three linked entity types from public Booking.com pages in one run: **property records** (name, stars, guest rating, facilities, address, trader identity), **per-room rate options** (base price, discounted price, discount %, taxes and fees, board type, refundable flag), and a derived **value ranking** that scores each property on rating against price and re-orders the report best-value first. Every row is typed, normalized JSON — no HTML, no selectors, no parsing. By the end of this page you will know which fields you get, what unlocks each of them, and where the honest gaps are.

***

### What is Booking.com Scraper — Rate & Value Report?

Booking.com Scraper — Rate & Value Report is an Apify Actor that turns a destination name or a list of Booking.com URLs into a ranked accommodation dataset. It scrapes public search-results and hotel detail pages, then adds two derived layers: a value score (`valueScore`, `valueRatio`, `valueRank`) computed across the whole result set, and a per-room rate breakdown parsed from Booking's own room blocks.

**No Booking.com account, cookie, or login is required.** The Actor never authenticates — it fetches the same pages an anonymous visitor sees. It reads no member-only rates, touches no booking or payment flow, and performs no in-platform action.

- Scrape **hotels and other accommodation** — hotels, apartments, hostels, villas, resorts, campsites and 9 more categories via `stayCategory`
- Scrape **per-room rate options** — `basePrice`, `discountedPrice`, `discountPct`, `taxesAndFees`, `totalPrice`, `boardType`, `refundable`
- Scrape **derived value rankings** — `valueScore` (0–100 percentile), `valueRank` (1 = best rating-for-price), `valueRatio` (raw `rating ÷ price`)
- Export as **JSON, CSV, Excel, XML or HTML** from the Apify dataset, or read it straight from the Apify API
- **No proxy management and no parsing** — a residential proxy ladder and two independent fetch engines are built in

***

### What data does the Rate & Value Report collect?

One run returns a single dataset item per property, and each item carries the property record, its room inventory, its rate options, its review breakdown, its trader identity block, and the derived value fields. Forty top-level keys are written on every row.

| Data Type | Key Fields | JSON Field Names |
| --- | --- | --- |
| Property record | Name, Booking hotel id, star class, accommodation type, description, canonical URL | `name`, `hotelId`, `stars`, `type`, `description`, `url` |
| Value ranking (derived) | Percentile value score, value rank, raw rating-per-price ratio, output position | `valueScore`, `valueRank`, `valueRatio`, `order` |
| Room rate options | Pre-discount price, discounted price, discount %, taxes and fees, total, board type, refundability | `rateBreakdown[]` → `.basePrice`, `.discountedPrice`, `.discountPct`, `.taxesAndFees`, `.totalPrice`, `.boardType`, `.refundable`, `.currency`, `.roomId`, `.roomName` |
| Room inventory | Room id, name, description, size, max occupancy, cheapest block price | `rooms[]` → `.id`, `.name`, `.description`, `.size`, `.occupancy`, `.price` |
| Guest ratings | Score, localized label, review count, per-category subscores | `rating`, `ratingLabel`, `reviews`, `categoryReviews[].name`, `categoryReviews[].score` |
| Facilities and highlights | Facility names and ids, marketing highlights, breakfast availability | `facilities[].name`, `facilities[].id`, `highlights`, `breakfast` |
| Location and address | Latitude, longitude, street, city, country code, breadcrumb trail | `location.lat`, `location.lng`, `address.full`, `address.city`, `address.country`, `breadcrumbs[]` |
| House rules and fine print | Check-in window, check-out window, house-rule lines, fine print | `checkIn`, `checkOut`, `policies`, `finePrint` |
| Business / trader identity | Trader flag, legal company name, email, phone, registration number, postal address | `traderInfo` → `.isBusiness`, `.companyName`, `.email`, `.phone`, `.registrationNumber`, `.tradeRegisterName`, `.address.*` |
| Host, chain and licence | Host name, hotel chain, first published licence number | `hostInfo`, `hotelChain`, `licenseInfo` |
| Media | Hero image, deduplicated gallery (capped at 50), per-room photo sets | `image`, `images`, `roomImages[].roomId`, `roomImages[].images` |
| Run metadata | Scrape timestamp, queued URL, originating query, resolved stay dates, price, currency | `timeOfScrapeISO`, `source_url`, `startUrlOrQuery`, `checkInDate`, `checkOutDate`, `price`, `currency` |

#### Need more accommodation and local-market data?

API Empire does not currently publish a second Booking.com Actor, so there is no companion review or availability scraper for this platform to point you at. For adjacent work, the Apartments.com Scraper — Neighborhood Rent & Livability Report covers long-stay rental pricing in the same value-report style, and the Google Maps Scraper with Lead Contact Enrichment is the usual pairing when you need on-the-ground contact details for the properties you just ranked.

***

### How does this differ from the official Booking.com Demand API?

Booking.com's own programmatic surface is the Demand API at `developers.booking.com`; access is granted through an approved affiliate or distribution partnership with a signed agreement, and the endpoints are built for partners who send bookings back to Booking.com. This Actor is the opposite shape: a read-only extractor over public pages that anyone with an Apify account can start immediately.

| Feature | Booking.com Demand API | Rate & Value Report |
| --- | --- | --- |
| Access | Approved partnership and signed agreement required, per Booking.com's published Demand API onboarding docs | Open — start the Actor from the Apify Console or Apify API with your Apify token |
| Intended purpose | Distributing and booking inventory as a Booking.com partner | Read-only extraction and analysis of public listing data |
| Value scoring | Not provided — you receive raw availability and pricing | `valueScore`, `valueRank`, `valueRatio` computed across the whole result set |
| Discount visibility | Rate plans as contracted, in partner terms | `basePrice` vs `discountedPrice` and a derived `discountPct` as shown publicly on the page |
| Trader / legal identity | Not the API's concern | `traderInfo`, `licenseInfo`, `hostInfo` as published on the listing |
| Setup time | Partner onboarding and review | Fill the input form, press Start |
| Output shape | Partner-contract JSON schema | 40 stable top-level keys per property, identical on every run |

Use the Demand API when you are an approved partner and your goal is to sell inventory — it is the only lawful path to real booking capability. Use this Actor when your goal is analysis: rating against price, published discounts and taxes, or a structured accommodation dataset built from pages that are already public.

***

### Why do developers and teams scrape Booking.com?

Booking.com is the largest single public catalogue of accommodation pricing, and almost every price the platform shows is decorated with a discount claim, a tax note and a board type that only exist inside the rendered page. Four groups get real leverage from turning that into rows.

#### For AI engineers and agent builders

A travel agent answering "find me a well-rated place in Lisbon under €150 that includes breakfast" needs structure, not a screenshot. Run the Actor with `location`, `stayCheckIn`, `stayCheckOut` and `priceBand`, then hand the dataset to the model: `valueScore` is a ready ranking signal, `rateBreakdown[].boardType` answers the breakfast constraint without string matching, and `rateBreakdown[].refundable` answers the cancellation constraint. Every field is typed JSON, so there is no HTML parsing inside the agent loop — the most common reliability failure in tool-using agents.

#### For travel marketers and deal sites

Deal editors need the properties whose rating is disproportionate to their price, not the cheapest ones. Set `sortResultsBy` to `bestValue` and the report arrives pre-ranked: `valueRank: 1` is the strongest rating-for-price in the set, and `valueRatio` exposes the raw number for re-weighting. `discountPct` on each rate option separates a real markdown from a strikethrough that never moved, and `ratingLabel` gives the exact wording Booking shows guests in the language set by `resultLanguage`.

#### For researchers and market analysts

Everything returned is drawn from pages Booking.com serves to anonymous visitors — no login, no member rate, no reviewer personal data, no booking-flow content. That matters for pricing studies, tourism-economics work and accommodation-supply research where sample provenance is part of the method. A typical study sweeps one `location` per city with fixed `stayCheckIn`/`stayCheckOut` and `maxProperties`, then compares `price`, `stars`, `rating` and `taxesAndFees` across markets. `timeOfScrapeISO` timestamps every observation, so repeated runs assemble into a panel.

#### For developers building data products

The Actor is a scheduled job with a stable output contract, which is what a pipeline needs. Point a daily Apify schedule at a saved input, read `defaultDatasetId` from the run object, and upsert on `hotelId` plus `checkInDate`. Field names and types do not change between runs, so a warehouse table defined once keeps loading. Pay-per-event pricing means a run's cost tracks the rows you actually got, which makes per-customer cost modelling straightforward.

***

### 🚀 How to scrape Booking.com hotel rates (step by step)

The Actor runs on the Apify platform only. There is no separate signup, no API key of its own, and no credit system — you start it from the Apify Console or call it with the Apify API using your Apify token.

1. **Open the Actor on its Apify Store listing** and press *Try for free*, or open it in the Apify Console if it is already in your account.
2. **Give it a target.** No field is required by the schema, but the run does nothing without one of the two entry points: a city, region or landmark in `location`, or Booking.com URLs in `stayUrls` (hotel detail pages and `searchresults` pages are both accepted).
3. **Set the stay dates.** Fill `stayCheckIn` and `stayCheckOut` (`YYYY-MM-DD`, or a relative form like `2 weeks`). This unlocks `rateBreakdown`, `taxesAndFees` and correct currency handling — without both dates Booking serves no priced availability blocks.
4. **Choose filters and ordering.** `maxProperties` caps the sample, `sortResultsBy` sets the output order (`bestValue` by default), and `stayCategory`, `starRating`, `minGuestRating`, `priceBand` and `searchOrder` narrow the comparison set before ranking.
5. **Start the run, then export.** Open the *Output* tab — the default *💎 Value-ranked hotels* view leads with the ranking columns — and export to JSON, CSV, Excel, XML or HTML, or pull the dataset over the Apify API.

#### What to do when Booking.com changes its structure

Nothing on your side. The Actor reads four independent layers of the page — Apollo store, JSON-LD, inline `window.booking` variables, DOM selectors — and merges whatever each yields, so a change to one layer degrades single fields rather than breaking the run. Output key names and types are the integration contract and are kept stable while the scraper is maintained against Booking's markup.

***

### What changed in Booking.com scraping recently?

The largest structural shift is regulatory rather than technical: the European Commission designated Booking.com a gatekeeper under the Digital Markets Act on 13 May 2024, with compliance obligations applying from 13 November 2024, which reshaped how search results and ranking disclosures render in the EU.

- **Trader-identity blocks became routine.** The EU Digital Services Act's trader-traceability obligation has applied to online marketplaces since 17 February 2024, and Booking now publishes legal-entity, registration and contact data on many listings. That is exactly the block this Actor reads into `traderInfo`, `licenseInfo` and `hostInfo` — data that simply was not on the page for most listings before.
- **Two rendering paths coexist.** Priced availability appears in the React/Apollo store on some responses and in the legacy server-rendered `#hprt-table` rooms table on others. A scraper that knows only one of them returns an empty `rateBreakdown` on the other. This Actor tries the Apollo path first and falls back to the DOM table.
- **Anti-bot on the search-results page is aggressive.** A competing Booking.com Actor's own listing states plainly that "Booking.com blocks shared Apify proxies" (plowdata/booking-com-review-scraper, checked on the Apify Store 2026-07-25 — not measured here). This Actor defaults to Apify RESIDENTIAL proxies and steps down a ladder on repeated blocks.
- **What is still public:** search results, hotel detail pages, published rates, guest scores, facilities, house rules and trader blocks. **What is not:** member and loyalty-gated rates, anything behind login, and the booking or payment flow.

Maintenance continues against whichever rendering path Booking ships next; the layered extractor is what makes that survivable.

***

### ⬇️ Input

Every parameter below comes from `.actor/actor.json`. Nothing is required — but a run with neither `location` nor `stayUrls` logs *"No destination and no Stay URLs. Nothing to do."* and exits without pushing rows. Each field also accepts the base Booking scraper's key name as an alias, so an input written for the base Actor runs here unchanged.

| Parameter | Required | Type | Description | Example Value |
| --- | --- | --- | --- | --- |
| `location` | No | string | Destination to value-rank — city, region or landmark. Ignored when `stayUrls` is non-empty. Default `""`, editor `textfield`. Alias: `search`. | `"Amsterdam"` |
| `stayUrls` | No | array | Booking.com URLs — hotel detail pages and/or `searchresults` pages. Non-Booking URLs are dropped. Default `[]`, editor `stringList`. Alias: `startUrls` (also accepts `urls`); string or `{"url": …}` entries. | `["https://www.booking.com/hotel/nl/example.html"]` |
| `maxProperties` | No | integer | How many properties to scrape and rank per destination / URL. Default `10`, minimum `1`, maximum `20000`. Alias: `maxItems`. | `15` |
| `sortResultsBy` | No | string | Output ordering. Enum: `bestValue`, `lowestPrice`, `highestRating`, `asFound`. Default `bestValue`, editor `select`. Any unrecognized value falls through to `bestValue`. | `"bestValue"` |
| `includeRateBreakdown` | No | boolean | Parse per-room rate options from Booking's room blocks. Default `true`. Needs both stay dates to return anything. | `true` |
| `includePropertyDetails` | No | boolean | Include rooms, facilities, highlights, images, room photos, breadcrumbs, chain, licence, host and trader info. Default `true`. Alias: `scrapeAdditionalHotelData`. | `true` |
| `stayCheckIn` | No | string | Check-in. Absolute `YYYY-MM-DD` or relative (`2 weeks`). Default `""`, editor `datepicker`, `dateType: absoluteOrRelative`, pattern `^(\d{4})-(0[1-9]\|1[0-2])-(0[1-9]\|[12]\d\|3[01])$\|^(\d+)\s*(day\|week\|month\|year)s?$\|^$`. Alias: `checkIn`. | `"2026-09-12"` |
| `stayCheckOut` | No | string | Check-out. Same format, same pattern, same editor as `stayCheckIn`. Default `""`. Alias: `checkOut`. | `"2026-09-15"` |
| `dateFlexibility` | No | string | Shift the stay dates by up to this many days. Enum: `0`, `1`, `2`, `3`, `7`. Default `"0"`, editor `select`. Sent as `flex_window` only when not `"0"`. Alias: `flexWindow`. | `"0"` |
| `guestsAdults` | No | integer | Adult guests the rate is quoted for. Default `2`, minimum `1`, maximum `30`. Alias: `adults`. | `2` |
| `guestsChildren` | No | integer | Children the rate is quoted for. Default `0`, minimum `0`, maximum `30`. Alias: `children`. | `0` |
| `roomsNeeded` | No | integer | Rooms for the stay. Default `1`, minimum `1`, maximum `9`. Alias: `rooms`. | `1` |
| `stayCategory` | No | string | Accommodation type filter. Enum: `none`, `hotels`, `apartments`, `hostels`, `guest houses`, `homestays`, `bed and breakfasts`, `holiday homes`, `boats`, `villas`, `motels`, `resorts`, `holiday parks`, `campsites`, `luxury tents`. Default `"none"`, editor `select`. Applied only on destination searches. Alias: `propertyType`. | `"hotels"` |
| `searchOrder` | No | string | Booking's server-side result order, applied before value re-ranking. Enum: `distance_from_search`, `price`, `review_score_and_price`, `review_score`, `class`. Default `"review_score_and_price"`, editor `select`. Alias: `sortBy`. | `"review_score_and_price"` |
| `minGuestRating` | No | string | Guest-rating floor, e.g. `8`. Default `""`, editor `textfield`. Truncated to a whole number and sent as `review_score=<n×10>`, so `8.5` behaves as `8`. Alias: `minimumRating`. | `"8"` |
| `starRating` | No | string | Official star class filter. Enum: `any`, `1`, `2`, `3`, `4`, `5`. Default `"any"`, editor `select`. Alias: `starsCountFilter`. | `"any"` |
| `priceBand` | No | string | Nightly price band, `min-max` (`60-250`) or `min+` (`100+`). Default `"0-999999"`, editor `textfield`; the default is treated as "no filter". Malformed values are ignored silently. Alias: `minMaxPrice`. | `"60-250"` |
| `resultCurrency` | No | string | Currency for prices and the rate breakdown. Enum: `USD`, `EUR`, `GBP`, `CAD`, `AUD`, `CHF`, `JPY`, `CNY`, `INR`, `BRL`, `MXN`. Default `"EUR"`, editor `select`. Alias: `currency`. | `"EUR"` |
| `resultLanguage` | No | string | Booking interface language, which also selects the `searchresults.<lang>.html` domain path. Enum: `en-gb`, `en-us`, `de`, `fr`, `es`, `it`, `pt-br`, `nl`, `pl`, `ru`, `ja`, `zh`. Default `"en-gb"`, editor `select`. Alias: `language`. | `"en-gb"` |
| `proxyConfiguration` | No | object | Apify proxy settings, editor `proxy`. Default `{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}`. `apifyProxyCountry` is carried through to the residential tier when set. | `{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}` |

#### Example input

```json
{
  "location": "Amsterdam",
  "stayUrls": [],
  "maxProperties": 15,
  "sortResultsBy": "bestValue",
  "includeRateBreakdown": true,
  "includePropertyDetails": true,
  "stayCheckIn": "2026-09-12",
  "stayCheckOut": "2026-09-15",
  "dateFlexibility": "0",
  "guestsAdults": 2,
  "guestsChildren": 0,
  "roomsNeeded": 1,
  "stayCategory": "hotels",
  "searchOrder": "review_score_and_price",
  "minGuestRating": "8",
  "starRating": "any",
  "priceBand": "60-250",
  "resultCurrency": "EUR",
  "resultLanguage": "en-gb",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

**Most common input mistake:** leaving `stayCheckIn` and `stayCheckOut` empty while expecting the rate breakdown. Booking only injects priced availability blocks for a specific stay, so a dateless run returns `rateBreakdown: []`, no `taxesAndFees`, and prices in Booking's own default currency rather than your `resultCurrency` — because the currency parameter is only appended to detail-page URLs when both dates are present. The Actor logs a warning for exactly this case: *"Rate breakdown requested but no check-in/out dates set."*

***

### ⬆️ Output

Results land in the Actor's default Apify dataset as typed, normalized JSON with a stable key set — 40 top-level keys on every row, in the same order, whether or not each has a value. Export from the Console or the API as **JSON, CSV, Excel (XLSX), XML, HTML or JSONL**. The default view, *💎 Value-ranked hotels*, surfaces all 40 keys with the ranking columns first; nothing is hidden behind it. Missing data is `null` (or `[]` / `""`) — the extractor never substitutes a plausible-looking value for one it could not find.

#### Scraped property with value score and rate breakdown

```json
{
  "order": 1,
  "valueRank": 1,
  "valueScore": 100.0,
  "valueRatio": 0.023133,
  "name": "Canal House Amsterdam",
  "price": 372.0,
  "currency": "EUR",
  "rating": 8.6,
  "ratingLabel": "Fabulous",
  "stars": 4,
  "rateBreakdown": [
    {
      "roomId": "12345678_401234567_2_0_0",
      "roomName": "Deluxe King Room with Canal View",
      "boardType": "Breakfast included",
      "basePrice": 465.0,
      "discountedPrice": 372.0,
      "discountPct": 20.0,
      "taxesAndFees": 44.64,
      "totalPrice": 416.64,
      "currency": "EUR",
      "refundable": true
    },
    {
      "roomId": "12345678_401234567_2_1_0", "roomName": "Standard Twin Room",
      "boardType": null, "basePrice": null, "discountedPrice": 318.0,
      "discountPct": null, "taxesAndFees": 38.16, "totalPrice": 356.16,
      "currency": "EUR", "refundable": false
    }
  ],
  "reviews": 1487,
  "breakfast": "Available",
  "url": "https://www.booking.com/hotel/nl/canal-house-amsterdam.en-gb.html",
  "startUrlOrQuery": "Amsterdam",
  "type": "hotel",
  "description": "Set in a 17th-century canal house in the Jordaan district …",
  "checkInDate": "2026-09-12",
  "checkOutDate": "2026-09-15",
  "checkIn": "From 15:00 to 23:00",
  "checkOut": "From 07:00 to 11:00",
  "location": { "lat": 52.374, "lng": 4.8897 },
  "address": { "full": "Keizersgracht 148", "country": "NL", "city": "Amsterdam" },
  "image": "https://cf.bstatic.com/xdata/images/hotel/max1024x768/000000001.jpg",
  "rooms": [
    {
      "id": "12345678_401234567",
      "name": "Deluxe King Room with Canal View",
      "description": "This double room features a seating area, minibar and canal views.",
      "size": 28,
      "occupancy": 2,
      "price": 372.0
    }
  ],
  "highlights": ["Free WiFi", "Canal view", "Very good breakfast"],
  "finePrint": "The property is located in a listed building without a lift.",
  "policies": ["Pets: not allowed", "Smoking: not allowed"],
  "images": ["https://cf.bstatic.com/xdata/images/hotel/max1024x768/000000001.jpg"],
  "roomImages": [
    { "roomId": "401234567", "images": ["https://cf.bstatic.com/%E2%80%A6/000000011.jpg"] }
  ],
  "categoryReviews": [
    { "name": "Cleanliness", "score": 8.9 },
    { "name": "Location", "score": 9.4 }
  ],
  "hotelChain": null,
  "licenseInfo": "0363 1234 5678 ABCD",
  "hostInfo": null,
  "traderInfo": {
    "isBusiness": true, "email": "info@example-hotel.nl", "phone": "+31201234567",
    "companyName": "Example Hospitality B.V.", "firstName": null, "middleName": null,
    "lastName": null, "registrationNumber": "12345678",
    "tradeRegisterName": "Kamer van Koophandel",
    "address": {
      "street": "Keizersgracht 148", "street2": null, "postalCode": "1015 CX",
      "city": "Amsterdam", "countryCode": "NL", "state": null
    }
  },
  "breadcrumbs": [
    { "name": "Netherlands", "url": "https://www.booking.com/country/nl.html" },
    { "name": "Amsterdam", "url": "https://www.booking.com/city/nl/amsterdam.html" }
  ],
  "hotelId": "12345678",
  "facilities": [{ "name": "Free WiFi", "id": 107 }, { "name": "Bar", "id": 11 }],
  "timeOfScrapeISO": "2026-07-25T09:41:12.883410+00:00",
  "source_url": "https://www.booking.com/hotel/nl/canal-house-amsterdam.html"
}
```

#### Every output key, and what fills it

| Field | Type | Notes |
| --- | --- | --- |
| `order` | integer | 1-based position in the final report, rewritten after re-ranking so it always matches `sortResultsBy`. |
| `valueRank` | integer | null | 1 = highest `rating ÷ price` in the run. `null` without a rating or a price. |
| `valueScore` | number | null | Percentile of `rating ÷ price` across scored rows, `0`–`100`, one decimal. Lowest scored row is `0.0`, highest `100.0`; a lone scoreable row gets `100.0`. |
| `valueRatio` | number | null | Raw `rating ÷ price`, 6 decimals. |
| `name` | string | Property name. A page yielding no name is retried then skipped, so this is never `null` on a pushed row. |
| `price` | number | null | Lowest priced option on the page — minimum of `rooms[].price` and `rateBreakdown[].discountedPrice`, falling back to Booking's inline `b_cheapest_price_that_fits_search_eur` and then the DOM price element. |
| `currency` | string | The property's `b_hotel_currencycode`, defaulting to `"USD"`. Its listing currency — not necessarily the currency `price` is quoted in (see caveats). |
| `rating` | number | null | Guest score out of 10, from `ReviewScoreSummary` or JSON-LD `aggregateRating.ratingValue`. |
| `ratingLabel` | string | null | Booking's localized label; if absent, derived from the score — `Superb` ≥ 9, `Very good` ≥ 8, `Good` ≥ 7, `Pleasant` ≥ 6, else `null`. |
| `stars` | number | null | Official star class from the `StarRating` object. |
| `rateBreakdown` | array | Per-room rate options. `[]` when `includeRateBreakdown` is `false`, when no stay dates are set, or when no priced block exists. Never fabricated. |
| `rateBreakdown[].roomId` | string | null | Apollo room id, or the DOM table's `data-block-id`. |
| `rateBreakdown[].roomName` | string | null | Room type name as displayed. |
| `rateBreakdown[].boardType` | string | null | Booking's meal-plan value, or normalized from the meal-plan cell into `All inclusive`, `Full board`, `Half board`, `Breakfast included`, `Breakfast available`, `Dinner included`, `Lunch included`. |
| `rateBreakdown[].basePrice` | number | null | Pre-discount / strikethrough price, when published. |
| `rateBreakdown[].discountedPrice` | number | null | The price actually charged for this option. |
| `rateBreakdown[].discountPct` | number | null | `(basePrice − discountedPrice) / basePrice × 100`, one decimal. Only when both exist and `basePrice ≥ discountedPrice`. |
| `rateBreakdown[].taxesAndFees` | number | null | Excluded charges as published under the price. |
| `rateBreakdown[].totalPrice` | number | null | `discountedPrice + taxesAndFees`, 2 decimals. `null` when taxes are absent or published as zero. |
| `rateBreakdown[].currency` | string | null | From Booking's price object; on the DOM path it is backfilled with your `resultCurrency`. |
| `rateBreakdown[].refundable` | boolean | null | `true` on free cancellation, `false` on non-refundable, `null` when neither is stated. |
| `reviews` | integer | Review count; `0` when unavailable. |
| `breakfast` | string | null | `"Available"` when breakfast appears in the facility/highlight set or in Booking's "breakfast is available/included" copy, else `null`. |
| `url` | string | Canonical URL from JSON-LD, falling back to the fetched URL. |
| `startUrlOrQuery` | string | Your `location` value, or the URL on a URL-driven run — the grouping key for multi-destination datasets. |
| `type` | string | Booking's `b_hotel_type_anchor`, defaulting to `"hotel"`. |
| `description` | string | null | JSON-LD description, falling back to the Apollo description. Not gated by `includePropertyDetails`. |
| `checkInDate` / `checkOutDate` | string | null | The **resolved stay dates** for this run, `YYYY-MM-DD`. `null` on a dateless run. |
| `checkIn` / `checkOut` | string | null | The property's **house-rule time windows**, e.g. `"From 15:00 to 23:00"`. A one-sided window renders as `"From 15:00"` or `"Until 11:00"` — never a half-formed `"to None"`. |
| `location` | object | `{ "lat": number\|null, "lng": number\|null }`, from Apollo data or an inline-variable regex fallback. |
| `address` | object | `{ "full", "country", "city" }`; `country` upper-cased. Empty strings, not `null`, when unknown. |
| `image` | string | First gallery image, or `""`. |
| `rooms` | array | `{ id, name, description, size, occupancy, price }` per room type. `[]` when `includePropertyDetails` is `false`. |
| `highlights` | array | Booking's facility-highlight titles. `[]` when `includePropertyDetails` is `false`. |
| `finePrint` | string | Fine-print paragraphs joined with spaces; `""` when none. Not gated by `includePropertyDetails`. |
| `policies` | array | null | Real house-rule lines only (`"Pets: not allowed"`), from house-rule objects and boolean rule flags. `null` when none are published — never invented from marketing copy. |
| `images` | array | Deduplicated gallery URLs, **capped at 50**. `[]` when `includePropertyDetails` is `false`. |
| `roomImages` | array | `{ roomId, images[] }` per room photo set. `[]` when `includePropertyDetails` is `false`. |
| `categoryReviews` | array | `{ name, score }` subscores such as `Cleanliness`, `Location`, `Staff`; the `hotel_` prefix is stripped and the name title-cased. Not gated by `includePropertyDetails`. |
| `hotelChain` | string | null | Chain name when the property belongs to one. `null` when `includePropertyDetails` is `false`. |
| `licenseInfo` | string | null | **First** published licence/registration number only. |
| `hostInfo` | string | null | Host profile name; falls back to the trader's first + last name when no company name is published. |
| `traderInfo` | object | null | `isBusiness`, `email`, `phone`, `companyName`, `firstName`, `middleName`, `lastName`, `registrationNumber`, `tradeRegisterName`, plus nested `address` with `street`, `street2`, `postalCode`, `city`, `countryCode`, `state`. `null` when `includePropertyDetails` is `false`. |
| `breadcrumbs` | array | `{ name, url }` for Booking's country/region/city trail. `[]` when `includePropertyDetails` is `false`. |
| `hotelId` | string | null | Booking's numeric hotel id, as a string. |
| `facilities` | array | `{ name, id }` per facility; the DOM fallback returns `id: null`. `[]` when `includePropertyDetails` is `false`. |
| `timeOfScrapeISO` | string | UTC ISO-8601 timestamp of the extraction. |
| `source_url` | string | The URL as queued, before availability parameters were appended — the stable join key across runs. |

#### Scraped rate option (standalone shape)

`rateBreakdown` is the second entity in the report and has its own schema, identical whether it came from the Apollo store or the legacy rooms table:

```json
{
  "roomId": "12345678_401234567_2_0_0",
  "roomName": "Deluxe King Room with Canal View",
  "boardType": "Breakfast included",
  "basePrice": 465.0,
  "discountedPrice": 372.0,
  "discountPct": 20.0,
  "taxesAndFees": 44.64,
  "totalPrice": 416.64,
  "currency": "EUR",
  "refundable": true
}
```

***

### Limits, caveats and known behaviour

These are the things worth knowing before you build on the output. All of them are visible in the source.

- **`price` follows the stay, not the night.** On a multi-night search Booking renders the price for the whole stay in the rooms table, and `price` is the minimum of those figures — so on a 3-night run `price` is the 3-night total for the cheapest option, even though the dataset view labels the column *Nightly Price*. Within one run every row uses the same stay length, so the ranking is internally consistent; keep the stay length fixed when comparing `valueRatio` across runs.
- **`currency` and the price currency can disagree.** `currency` comes from the property's own `b_hotel_currencycode` and defaults to `"USD"`. Your `resultCurrency` reaches Booking as `selected_currency`, which is appended to detail URLs **only when both stay dates are set**. On a dateless run, prices come back in whatever currency Booking picks for the locale. Set both dates when currency matters.
- **The whole result set is buffered before anything is pushed.** Value scoring is a percentile across the run, so every property is scraped and held in memory first; rows appear in the dataset only after the last one finishes. A run aborted mid-way writes nothing.
- **Properties are fetched sequentially.** No concurrency — hotel pages go one after another, with a 1-second pause between search pages. `maxProperties` accepts up to 20000, but wall-clock time scales with it and the run timeout is the practical ceiling.
- **Filters apply to destination searches only.** `stayCategory`, `starRating`, `minGuestRating`, `priceBand` and `searchOrder` are encoded into the search URL. Hotel detail URLs in `stayUrls` are fetched as given, unfiltered.
- **`minGuestRating` is truncated.** `8.5` becomes `8` before conversion to Booking's `review_score=80` filter.
- **Relative dates are approximate.** `1 month` resolves to 30 days from today, `1 year` to 365. A date matching neither the absolute nor the relative form resolves to empty — silently turning the run into a dateless scan.
- **`basePrice` from the legacy rooms table is a heuristic.** On the DOM path the pre-discount price is inferred as the largest other plausible figure in the price cell (bounded to under 10× the charged price), so an unrelated number printed there can distort `basePrice` and `discountPct`. The Apollo path reads a named field and is unaffected.
- **`valueScore` is relative, not absolute.** It ranks *your* result set against itself, not against all of Booking.com — scrape 5 hotels and one is 100 and one is 0 by construction. Raise `maxProperties` for a meaningful spread.

***

### How does this compare to other Booking.com scrapers?

| Feature | Booking.com Scraper — Rate & Value Report | Generic Booking.com scraper |
| --- | --- | --- |
| Output format | 40 typed top-level keys per property, identical every run; JSON, CSV, XLSX, XML, HTML | Raw rows, shape varies by Actor |
| Entity coverage | Property record **+** per-room rate options **+** derived value ranking in one item | Usually one entity — either listings or reviews |
| Rate detail | `basePrice`, `discountedPrice`, `discountPct`, `taxesAndFees`, `totalPrice`, `boardType`, `refundable` per room option | A single nightly price field |
| Input flexibility | Destination search **or** hotel URLs **or** search-results URLs, plus 8 filters and base-Actor key aliases | Usually URL-only or destination-only |
| Anti-bot handling | Chrome-TLS fetch with a headless Chromium fallback, on a RESIDENTIAL → DATACENTER → NO\_PROXY ladder with 3 retries per tier | Varies; some listings require you to bring your own proxies |
| Missing data policy | `null` / `[]`, never a fabricated rate or an invented policy line | Varies |

The closest Apify Store listings were checked on **2026-07-25**. `plowdata/booking-com-review-scraper` targets a different entity — guest reviews and per-category scores across two datasets — and its listing advertises "~30-50 reviews/sec" while instructing users to supply their own proxies because "Booking.com blocks shared Apify proxies" (its listing text, checked 2026-07-25 — not measured here). `ryanclinton/booking-scraper` is the closest positional competitor: its listing advertises a stateful rate-intelligence engine with six modes, saved rate history across runs, and "up to 240 hotels per destination" (checked 2026-07-25 — not measured here). This Actor is stateless by comparison, keeps no history between runs, and does one thing: a single-run value ranking with the published rate components underneath it.

If you are building an AI agent or a RAG pipeline, the output-format row is the decision-maker: parsing HTML inside an agent loop is a reliability failure mode, not a feature. Check the rate-detail row too — a single `price` field cannot tell your model whether a discount is real or whether taxes are already included.

***

### How many hotels can you scrape in one run?

`maxProperties` sets the ceiling: default `10`, minimum `1`, maximum `20000`. There is no other hard cap inside the Actor — no separate item limit, no internal page limit.

Pagination is offset-based: the Actor builds a Booking search URL, extracts every `property-card` link, then re-requests the same URL with `&offset=` incremented by 25 until it has `maxProperties` links or a page returns no new cards, pausing one second between pages. Detail pages are then fetched one at a time, each with up to 9 attempts across the proxy ladder. Any `searchresults` URL you pass in `stayUrls` is expanded the same way, and the combined list is truncated to `maxProperties`.

Two practical limits sit above the schema. Booking's own search paging depth bounds how many distinct properties one destination query can surface, so a large `maxProperties` on a small city stops early with *"No more hotels found at offset N."* And because the Actor is sequential and buffers the full result set before writing, the run timeout — not `maxProperties` — usually decides how large a run can be. No benchmark timing is quoted here because none has been measured.

#### What a run costs

Pricing is pay-per-event, declared in `.actor/actor.json`: **$0.005** once per run for `actor-start`, and **$0.01** per hotel row successfully pushed (`row_result`). Properties that fail every retry are skipped and never charged, and once your event limit is reached the Actor stops pushing and exits with *"User spending limit reached"*. Rows that came back thin — a property with no price, so `valueScore: null` — are still pushed and still charged, because they are still a successfully scraped property record. Apify platform compute and proxy usage are billed separately by Apify under your plan.

***

### 🔌 Integrate the Rate & Value Report into your workflow

The Actor runs on Apify, so it works with any language or tool that can send an HTTP request to the Apify API — authentication is your Apify API token, and there is no separate account or key for the Actor itself.

#### REST API integration

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_API_TOKEN>")

run_input = {
    "location": "Amsterdam",
    "maxProperties": 15,
    "sortResultsBy": "bestValue",
    "stayCheckIn": "2026-09-12",
    "stayCheckOut": "2026-09-15",
    "resultCurrency": "EUR",
}

run = client.actor("<YOUR_USERNAME>/booking-scraper-rate-value-report").call(run_input=run_input)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    rate = (item.get("rateBreakdown") or [{}])[0]
    print(item["valueRank"], item["name"], item["price"], item["currency"],
          item["valueScore"], rate.get("boardType"), rate.get("discountPct"))
```

*Works in Python, Node.js, Go, Ruby, cURL — the same run-and-read-dataset pattern applies to every Apify API client.*

#### Automation platforms (n8n, Make, LangChain)

**n8n** ships an official **Apify** node: choose the *Run Actor* operation, select this Actor, paste the JSON input, and pipe the dataset items onward — a Postgres insert, a Slack digest of the top three `valueRank` rows, or a Google Sheets append.

**Make** has an **Apify** app with *Run an Actor* and *Get Dataset Items* modules. A common build is a scheduled scenario that runs the Actor each morning and filters to rows where `rateBreakdown[].discountPct` crosses a threshold before creating a record or firing an alert.

**LangChain** connects through the Apify integration: `ApifyWrapper` / `ApifyDatasetLoader` calls the Actor and maps each dataset item to a `Document`, so a value-ranked accommodation dataset can be embedded into a vector store and queried by a travel agent with no HTML in the pipeline.

**Apify webhooks** (fire on run success, POST the dataset id to your endpoint) and **Apify schedules** cover recurring monitoring.

***

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

Scraping publicly accessible Booking.com pages is generally lawful in most jurisdictions, and this Actor collects only such pages — it does not log in, does not access member-only or loyalty-gated rates, does not bypass authentication, and never touches the booking or payment flow.

Most of what it returns is business and product data: listings, published rates, discounts, taxes, facilities and house rules. That category is governed by Booking.com's terms of service and, in the EU, by database rights — review both before commercial redistribution and keep request volumes reasonable.

One part needs different handling. `traderInfo`, `hostInfo` and `licenseInfo` can contain a natural person's name, email, phone and postal address when the property is let by an individual rather than a company. That subset is personal data under GDPR and CCPA and requires a lawful basis to store or process. No reviewer identities and no guest data are collected. Consult legal counsel for commercial use cases involving bulk personal data.

***

### ❓ Frequently asked questions

#### Does the Rate & Value Report work without a Booking.com account?

Yes. The Actor never logs in and holds no Booking.com credentials — it fetches public search and hotel pages anonymously through Apify Proxy. The only credential involved anywhere is your Apify API token, and only if you start runs over the API rather than from the Console.

#### How often is the scraped data updated?

Every run is a live fetch. Nothing is cached between runs and no rate history is stored, so each row reflects the page as Booking served it at `timeOfScrapeISO`. For a time series, schedule the Actor and join successive datasets on `source_url` (or `hotelId`) plus `checkInDate`.

#### Why is `rateBreakdown` empty for some properties?

Almost always because the run had no stay dates. Booking only injects priced availability blocks for a specific check-in/check-out pair, so a dateless run returns `rateBreakdown: []` by design — the Actor logs a warning rather than inventing a rate. It is also empty when `includeRateBreakdown` is `false`, when the property is sold out for your dates, or when Booking served a layout with neither Apollo room blocks nor the legacy rooms table. `price` can still be populated from Booking's inline cheapest-price value.

#### What happens when a property is delisted or a page returns nothing?

The property is retried through the full proxy ladder — up to 9 attempts across RESIDENTIAL, DATACENTER and NO\_PROXY — and if no hotel name can be extracted, the Actor logs `Giving up on <url>` and skips it. No partial row is pushed and no `row_result` event is charged. If nothing could be extracted at all, the run finishes cleanly with *"Nothing extracted from any hotel URL"* and an empty dataset, so downstream jobs see zero rows rather than malformed ones.

#### Can I scrape login-gated or member-only Booking.com rates?

No. Only publicly accessible content is returned. Genius and other loyalty-gated prices, anything behind a Booking.com login, guest or reviewer personal details, and the booking/checkout flow are all outside what this Actor reads. If a rate is only visible to a signed-in member, it will not appear in `rateBreakdown`.

#### How do I try it before committing to a large run?

Start it from its Apify Store listing with the prefilled input — `location: "Amsterdam"`, `maxProperties: 10` — and add your own stay dates. Under pay-per-event a small run costs the `actor-start` event plus one `row_result` per property returned, so a 10-property test is easy to price before scaling `maxProperties` up.

#### Does it work for AI agent workflows and LLM pipelines?

Yes. The Actor is callable as an HTTP endpoint by any agent framework through the Apify API — LangChain, LlamaIndex, a custom tool-calling loop, or an n8n/Make automation. Every response is typed JSON with stable keys, so nothing needs parsing between the scrape and the model's context window. `valueScore`, `rateBreakdown[].boardType` and `rateBreakdown[].refundable` map directly onto the constraints a travel agent is asked to satisfy.

#### How does the Actor handle Booking.com's anti-bot system?

With three layers, all in the source. Requests go out through an impit client that impersonates Chrome's TLS fingerprint, over an Apify Residential proxy by default. A response that looks blocked — under 3000 characters, or containing `captcha`, `robot check`, `are you a robot`, `px-captcha` or `access denied` — triggers a headless Chromium fallback with a real browser context, Chrome user agent, 1366×900 viewport and automation flags disabled. Repeated failures walk a proxy ladder: RESIDENTIAL, then DATACENTER, then no proxy, 3 retries per tier. Pin a proxy country with `apifyProxyCountry` in `proxyConfiguration`.

#### Does it return data in a format LLMs can use directly?

Yes. Typed, normalized JSON with stable field names and consistent key ordering on every row — no HTML, no selectors, no post-processing. Pass the dataset straight into an LLM context window, index it into a vector store, or expose it as an agent tool. Absent values are explicit `null` / `[]`, which is what a model needs to reason about missing data instead of hallucinating around a blank string.

#### Can I use it without managing proxies?

Yes. `proxyConfiguration` defaults to Apify Proxy with the `RESIDENTIAL` group, and the fallback ladder, retry counts and browser fallback are handled inside the Actor. You do not supply proxy credentials, rotate sessions, or configure a browser. Change it only for a specific reason — a country requirement, or your own proxy setup.

#### What happens when Booking.com changes its page structure?

The output schema stays put. The extractor reads four independent layers of every page — Apollo store, JSON-LD, inline `window.booking` variables, DOM selectors — and merges what each yields, so a markup change usually costs one field rather than the run. Key names and types do not change on your side, so warehouse tables and agent tools keep working while the scraper is updated behind them.

***

### 💬 Your feedback

Found a bug, hit a Booking.com layout the extractor does not cover, or need a field that is on the page but not in the schema? We want to know. Open an issue on the Actor's **Issues** tab on its Apify Store listing — include your input JSON and the run id, and the parsing path can be traced from the run log. Feature requests for new filters or extra rate components are welcome there too.

# Actor input Schema

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

City, region or landmark whose accommodation you want value-ranked (e.g. Amsterdam, Lisbon). Ignored when Stay URLs are provided. (Base alias: `search`.)

## `stayUrls` (type: `array`):

One or more Booking.com URLs — hotel detail pages or search-results pages. Detail-page rate breakdown needs stay dates (below). (Base alias: `startUrls`.)

## `maxProperties` (type: `integer`):

How many properties to scrape and value-rank per destination / URL. Example: 15. Default is 10.

## `sortResultsBy` (type: `string`):

Output ordering. `bestValue` re-ranks by the derived value score (guest rating ÷ nightly price, percentile-ranked). Example: bestValue puts the property with the strongest rating-for-price at the top.

## `includeRateBreakdown` (type: `boolean`):

Extract each room's rate options — base price, discounted price, discount %, taxes & fees, board type, refundable flag — from Booking's room blocks. Requires stay dates to be set; otherwise Booking serves no priced availability and this stays empty. Default is on.

## `includePropertyDetails` (type: `boolean`):

Include rooms, facilities, images, breadcrumbs and trader/contact info. Turn off for a lean value-only report (name, price, rating, value score). Default is on. (Base alias: `scrapeAdditionalHotelData` — now actually honoured.)

## `stayCheckIn` (type: `string`):

Absolute date (YYYY-MM-DD) or relative (e.g. 2 weeks). Leave empty for a dateless value scan. (Base alias: `checkIn`.)

## `stayCheckOut` (type: `string`):

Absolute date (YYYY-MM-DD) or relative (e.g. 3 weeks). Leave empty for a dateless value scan. (Base alias: `checkOut`.)

## `dateFlexibility` (type: `string`):

Allow the stay dates to shift by this many days. Use 0 for exact dates. (Base alias: `flexWindow`.)

## `guestsAdults` (type: `integer`):

Adult guests the rate is quoted for. (Base alias: `adults`.)

## `guestsChildren` (type: `integer`):

Children the rate is quoted for. (Base alias: `children`.)

## `roomsNeeded` (type: `integer`):

Number of rooms for the stay. (Base alias: `rooms`.)

## `stayCategory` (type: `string`):

Restrict the comparison to one accommodation type. (Base alias: `propertyType`.)

## `searchOrder` (type: `string`):

How Booking orders the raw search results before value re-ranking is applied. (Base alias: `sortBy`.)

## `minGuestRating` (type: `string`):

Only compare properties at or above this guest rating (e.g. 8). Leave empty for no floor. (Base alias: `minimumRating`.)

## `starRating` (type: `string`):

Filter by official star class. (Base alias: `starsCountFilter`.)

## `priceBand` (type: `string`):

Min-max nightly price filter, e.g. 60-250 or 100+ for a floor only. (Base alias: `minMaxPrice`.)

## `resultCurrency` (type: `string`):

Currency the prices and rate breakdown are quoted in. (Base alias: `currency`.)

## `resultLanguage` (type: `string`):

Booking interface language for the request. (Base alias: `language`.)

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

Residential proxy is used by default; the actor also falls back RESIDENTIAL → DATACENTER → NO\_PROXY on repeated blocks.

## Actor input object example

```json
{
  "location": "Amsterdam",
  "stayUrls": [],
  "maxProperties": 10,
  "sortResultsBy": "bestValue",
  "includeRateBreakdown": true,
  "includePropertyDetails": true,
  "stayCheckIn": "",
  "stayCheckOut": "",
  "dateFlexibility": "0",
  "guestsAdults": 2,
  "guestsChildren": 0,
  "roomsNeeded": 1,
  "stayCategory": "none",
  "searchOrder": "review_score_and_price",
  "minGuestRating": "",
  "starRating": "any",
  "priceBand": "0-999999",
  "resultCurrency": "EUR",
  "resultLanguage": "en-gb",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

All scraped items in the Actor's default dataset.

# 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 = {
    "location": "Amsterdam",
    "stayUrls": [],
    "maxProperties": 10,
    "sortResultsBy": "bestValue",
    "includeRateBreakdown": true,
    "includePropertyDetails": true,
    "stayCheckIn": "",
    "stayCheckOut": "",
    "dateFlexibility": "0",
    "guestsAdults": 2,
    "guestsChildren": 0,
    "roomsNeeded": 1,
    "stayCategory": "none",
    "searchOrder": "review_score_and_price",
    "minGuestRating": "",
    "starRating": "any",
    "priceBand": "0-999999",
    "resultCurrency": "EUR",
    "resultLanguage": "en-gb",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("api-empire/booking-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 = {
    "location": "Amsterdam",
    "stayUrls": [],
    "maxProperties": 10,
    "sortResultsBy": "bestValue",
    "includeRateBreakdown": True,
    "includePropertyDetails": True,
    "stayCheckIn": "",
    "stayCheckOut": "",
    "dateFlexibility": "0",
    "guestsAdults": 2,
    "guestsChildren": 0,
    "roomsNeeded": 1,
    "stayCategory": "none",
    "searchOrder": "review_score_and_price",
    "minGuestRating": "",
    "starRating": "any",
    "priceBand": "0-999999",
    "resultCurrency": "EUR",
    "resultLanguage": "en-gb",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("api-empire/booking-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 '{
  "location": "Amsterdam",
  "stayUrls": [],
  "maxProperties": 10,
  "sortResultsBy": "bestValue",
  "includeRateBreakdown": true,
  "includePropertyDetails": true,
  "stayCheckIn": "",
  "stayCheckOut": "",
  "dateFlexibility": "0",
  "guestsAdults": 2,
  "guestsChildren": 0,
  "roomsNeeded": 1,
  "stayCategory": "none",
  "searchOrder": "review_score_and_price",
  "minGuestRating": "",
  "starRating": "any",
  "priceBand": "0-999999",
  "resultCurrency": "EUR",
  "resultLanguage": "en-gb",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call api-empire/booking-scraper --silent --output-dataset

```

## MCP server setup

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