# Booking.com Hotels Scraper (`w3crawler/booking-com-hotels-scraper`) Actor

Scrape hotel listings from Booking.com search results. Extracts hotel name, price, rating, review count, location, and star rating.

- **URL**: https://apify.com/w3crawler/booking-com-hotels-scraper.md
- **Developed by:** [w3crawler](https://apify.com/w3crawler) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 hotels

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?

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

### What does Booking.com Hotels Scraper do?

Booking.com Hotels Scraper collects hotel listings from public Booking.com search pages. It extracts public hotel-card fields with a browser and uses the page's public JSON-LD as a bounded HTTP fallback when browser extraction is unavailable. It does not sign in, use private endpoints, bypass access controls, or collect account data. See [Booking.com](https://www.booking.com/) for the source website.

### Why use Booking.com Hotels Scraper?

Use the Actor for destination research, accommodation comparison, travel planning, and public rate monitoring. It returns one row per distinct source-backed hotel until `maxItems` records are reached. Operational issues are logged and summarized outside the dataset.

### What data can Booking.com Hotels Scraper extract?

| Field                                                     | Type                               | Meaning                                                                                |
| --------------------------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------- |
| `rank`                                                    | integer                            | Position assigned while results are collected.                                         |
| `hotelId`                                                 | string                             | Identifier parsed from a public hotel URL, when available.                             |
| `name`                                                    | string                             | Public hotel name.                                                                     |
| `url`                                                     | string                             | Public Booking.com hotel page URL.                                                     |
| `searchUrl`                                               | string                             | Search URL used for the result.                                                        |
| `price` / `originalPrice`                                 | string                             | Localized displayed price text and original price when published.                      |
| `priceAmount` / `originalPriceAmount`                     | number                             | Numeric values inferred from the displayed price text.                                 |
| `currency`                                                | string                             | Currency inferred from the displayed symbol or code.                                   |
| `rating` / `reviewText` / `reviewCount`                   | string / string / integer          | Public score, qualitative label, and review count.                                     |
| `stars`                                                   | integer                            | Public star classification when published.                                             |
| `location` / `distanceFromCenter`                         | string                             | Public address/location and distance text.                                             |
| `thumbnail` / `image`                                     | string                             | Public image URL when published.                                                       |
| `badge`                                                   | string                             | Public recommendation or promotion label.                                              |
| `breakfastIncluded` / `freeCancellation` / `noPrepayment` | boolean                            | Availability signals detected in the public card text.                                 |
| `roomsLeft`                                               | integer                            | Public low-inventory message when present.                                             |
| `amenities`                                               | array of strings                   | Public facility labels found on the card or JSON-LD.                                   |
| `address` / `description` / `telephone`                   | string                             | Additional public JSON-LD fields when the HTTP fallback exposes them.                  |
| `latitude` / `longitude`                                  | number                             | Public JSON-LD coordinates when available.                                             |
| `destination` / `checkIn` / `checkOut` / `adults`         | string / string / string / integer | Search context used for the request.                                                   |
| `source`                                                  | string                             | Source label, currently `booking.com`.                                                 |
| `scrapedAt`                                               | string                             | UTC timestamp for the emitted row.                                                     |

Missing optional source fields are omitted; they are not filled with fabricated values or empty placeholders.

### Input parameters

| Input                | Type    | Required | Default and limits      | Description                                                                      |
| -------------------- | ------- | -------: | ----------------------- | -------------------------------------------------------------------------------- |
| `destination`        | string  |      yes | —                       | City, region, or hotel name used to build the public search URL.                 |
| `checkIn`            | string  |       no | 30 days from run date   | Valid calendar date in `YYYY-MM-DD` format.                                      |
| `checkOut`           | string  |       no | One day after `checkIn` | Valid calendar date in `YYYY-MM-DD`; it must be after check-in.                  |
| `adults`             | integer |       no | `2`; 1–10               | Number of adult guests.                                                          |
| `maxItems`           | integer |       no | `25`; 1–300             | Maximum number of successful hotel rows. Diagnostics do not consume this limit.  |
| `proxyConfiguration` | object  |       no | Direct public request   | Standard Apify Proxy configuration. It is used only when configured by the user. |

The Actor accepts these fields through the Apify input form or JSON input. It does not accept `startUrls`; `destination` is authoritative and is converted into a Booking.com `searchresults.html` URL. Explicit `checkIn`, `checkOut`, `adults`, and `maxItems` values override their defaults. There are no separate filters, sort controls, detail-page visits, or page-count inputs: Booking.com ranking is preserved.

#### Minimal input

```json
{
  "destination": "Paris"
}
```

#### Dated input

```json
{
  "destination": "Paris",
  "checkIn": "2026-10-12",
  "checkOut": "2026-10-15",
  "adults": 2,
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

### How to run the Actor in Apify Console

1. Open this Actor and select **Input**.
2. Enter a destination, such as `Paris`, and optionally set dates, adult count, result limit, or a standard proxy configuration.
3. Select **Save input** if you want to reuse the configuration.
4. Click **Start** and open **Dataset** after the run finishes.
5. Download the dataset, open the **API** tab for programmatic access, or inspect `OUTPUT` in the default key-value store for the run summary.

### How pagination, deduplication, and limits work

The browser starts at the generated search URL. If fewer than `maxItems` successful rows are available on the first page and at least ten cards are visible, it follows a public next-page link when one is published; otherwise it requests the next public offset in increments of 25. Collection stops at `maxItems` successful hotel rows or when no next page is exposed.

Rows are deduplicated during the run by the public hotel identifier, falling back to the hotel name. The `rank` field reflects collection order. There are no user-selectable filters or sorts, and the Actor does not visit each hotel detail page. Price and other fields are only those exposed on the public search card or public JSON-LD.

### What happens when the source is blocked or empty?

The browser checks the public page for access barriers and card content. If the browser is blocked, returns no cards, or fails before producing a successful row, the Actor makes one bounded public HTTP fallback request and parses only public HTML/JSON-LD. It never solves a challenge or bypasses a login, paywall, CAPTCHA, WAF, or other access boundary.

If the public response is readable but contains no usable hotels, the run completes with `status: "SUCCEEDED"`, `runStatus: "SUCCEEDED"`, and `dataStatus: "NO_RESULTS"`. A blocked or unavailable source with no saved hotel rows fails the run. When hotel rows were saved before a later request or output failure, the run remains successful and reports `dataStatus: "PARTIAL"`. Optional bounded `debug_html` and `crawl_error` keys can provide public-response evidence; they are stored outside the dataset.

### Output examples

#### Successful hotel row

```json
{
  "rank": 1,
  "hotelId": "example-paris-hotel",
  "name": "Example Paris Hotel",
  "url": "https://www.booking.com/hotel/fr/example-paris-hotel.html",
  "searchUrl": "https://www.booking.com/searchresults.html?ss=Paris",
  "price": "€120",
  "priceAmount": 120,
  "currency": "EUR",
  "rating": "8.4",
  "reviewCount": 1250,
  "destination": "Paris",
  "checkIn": "2026-10-12",
  "checkOut": "2026-10-15",
  "adults": 2,
  "source": "booking.com",
  "scrapedAt": "2026-09-08T00:00:00.000Z"
}
```

#### Run summary in key-value store

```json
{
  "status": "SUCCEEDED",
  "runStatus": "SUCCEEDED",
  "dataStatus": "COMPLETE",
  "datasetItems": 25,
  "diagnosticItems": 0,
  "diagnosticCount": 0,
  "uniqueItems": 25
}
```

`OUTPUT` uses `status` and `runStatus` values `SUCCEEDED` or `FAILED`, with `dataStatus` values `COMPLETE`, `PARTIAL`, `NO_RESULTS`, or `FAILED`. It reports source-backed hotel counts and operational diagnostics; dataset rows contain only public hotel records.

### How much will it cost?

There is no separate per-result fee configured by this Actor. Cost depends on Apify compute time, browser runtime, and any proxy traffic. Start with a small `maxItems` value and use direct public requests by default; browser extraction generally uses more compute than the HTTP fallback.

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Advanced usage and troubleshooting

Use the API tab or an Apify client to start runs and read the default dataset. For blocked or failed runs, inspect the run log, `OUTPUT`, and any `debug_html` or `crawl_error` key. `AWS_WAF_CHALLENGE`, `CAPTCHA`, `ACCESS_DENIED`, HTTP status codes, and similar codes mean that the public source did not expose usable data; they are not hotel records. Retrying repeatedly does not guarantee access and should respect Booking.com load and terms.

The Actor has no login, private API, CAPTCHA-solving, fingerprint-evasion, or stealth mode. Proxy settings are limited to the standard Apify Proxy configuration provided by the user. A missing price, rating, address, image, or amenity is an omission caused by the public response, not a zero value.

### API and Issues

For programmatic runs, use the **API** tab on the Actor page or the dataset URL shown in the run details. For support and feature requests, use the **Issues** tab and include the run ID, input, and relevant run-log details. Do not include credentials or private account information in an issue.

### Privacy, legal, and non-affiliation

This Actor reads public Booking.com search responses and does not request credentials or private account data. Use it only where you have a lawful, legitimate purpose and follow Booking.com's terms, robots rules, applicable contracts, privacy laws, and rate limits. Public pages may still contain personal data; handle results under the laws that apply to you.

This is an independent, unofficial Actor and is not affiliated with, endorsed by, or sponsored by Booking.com. Booking.com is a trademark of its respective owner.

# Changelog

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

# Actor input Schema

## `destination` (type: `string`):

City or destination to search hotels for.

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

Check-in date in YYYY-MM-DD format. When omitted, the Actor searches 30 days ahead so live prices are available.

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

Check-out date in YYYY-MM-DD format. When omitted, the Actor uses one night after check-in.

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

Number of adult guests.

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

Maximum number of hotels to scrape.

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

Optional proxy configuration. Direct public browser requests are used by default.

## Actor input object example

```json
{
  "destination": "Paris",
  "adults": 2,
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Dataset containing source-backed public hotel records only.

## `files` (type: `string`):

Key-value store containing bounded debug HTML and crawl-error JSON when produced.

## `runSummary` (type: `string`):

Canonical run status, source-backed hotel counts, and operational diagnostic counts.

# 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 = {
    "destination": "Paris",
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("w3crawler/booking-com-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 = {
    "destination": "Paris",
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("w3crawler/booking-com-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 '{
  "destination": "Paris",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call w3crawler/booking-com-hotels-scraper --silent --output-dataset

```

## MCP server setup

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