# Booking.com Reviews Scraper (`w3crawler/booking-com-reviews-scraper`) Actor

Scrape all guest reviews from Booking.com hotels: reviewer name, country, score, date, stay type, positive/negative text, and host responses. Supports full pagination.

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

## Pricing

from $2.99 / 1,000 reviews

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 Reviews Scraper do?

Booking.com Reviews Scraper collects publicly visible guest-review records from [Booking.com](https://www.booking.com/) hotel pages. It uses public browser DOM extraction and bounded public HTML/JSON-LD/reader fallbacks. It does not sign in, use private endpoints, solve CAPTCHAs, evade fingerprints, or bypass a login, paywall, WAF, or other access control.

### Why use Booking.com Reviews Scraper?

Use the Actor for travel research, property benchmarking, public guest-sentiment analysis, accommodation recommendations, and review-change monitoring. It preserves only fields actually exposed by the public response and adds optional public hotel-summary context. Operational diagnostics are written to logs and the `OUTPUT` key-value record, never to the dataset.

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

| Field                                                        | Type             | Meaning                                                            |
| ------------------------------------------------------------ | ---------------- | ------------------------------------------------------------------ |
| `url` / `hotelUrl`                                           | string           | The public Booking.com hotel URL used for the row.                 |
| `searchUrl`                                                  | string           | Public reader or review source URL when that fallback exposes one. |
| `hotelName`                                                  | string           | Public hotel name when available.                                  |
| `reviewPosition`                                             | integer          | Position within the requested hotel's emitted review set.          |
| `requestedSort` / `requestedLanguage`                        | string           | Sort and language values supplied for the run.                     |
| `reviewerName` / `reviewerCountry`                           | string           | Public reviewer display details when shown.                        |
| `overallScore`                                               | number           | Individual review score when shown.                                |
| `title` / `positiveText` / `negativeText`                    | string           | Public review title and text sections.                             |
| `date` / `stayDate` / `stayType` / `roomType` / `nightsText` | string           | Public timing and stay context when shown.                         |
| `hostResponse` / `hasHostResponse`                           | string / boolean | Public property response and whether one was present.              |
| `propertyType`                                               | string           | Public property type from the hotel page or structured data.       |
| `hotelReviewScore` / `hotelReviewCount`                      | number / integer | Public aggregate hotel score and review count.                     |
| `qualityRating` / `hotelReviewLabel`                         | number / string  | Public quality rating and qualitative label when shown.            |
| `scrapedAt`                                                  | string           | UTC timestamp for the emitted row.                                 |

Missing optional fields are omitted. The Actor does not infer a score, date, reviewer identity, or text from surrounding content.

### Input parameters

| Input                | Type             | Required | Default and limits | Description                                                                                                                                             |
| -------------------- | ---------------- | -------: | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `hotelUrls`          | array of strings |      yes | 1–25 URLs          | HTTPS Booking.com hotel-page URLs. Other hosts, non-HTTPS URLs, and non-hotel paths are rejected.                                                       |
| `maxReviews`         | integer          |       no | `50`; 0–5000       | Maximum successful review rows per hotel. `0` means all public reviews within the finite safety budget.                                                 |
| `sortBy`             | enum             |       no | `f_recent_desc`    | `f_relevance_desc`, `f_recent_desc`, `f_recent_asc`, `f_score_asc`, or `f_score_desc`.                                                                  |
| `language`           | string           |       no | empty              | Two-letter language code such as `en` or `fr`, optionally followed by a region such as `en-US`. Empty means the public default/all available languages. |
| `proxyConfiguration` | object           |       no | Direct request     | Standard Apify Proxy configuration; direct public requests are used unless a proxy is explicitly enabled.                                               |

The input schema is authoritative. The Actor does not accept `startUrls`; `hotelUrls` is the only URL source. Explicit values override defaults. There are no separate keyword filters, property filters, or custom page-size inputs.

#### Minimal input

```json
{
  "hotelUrls": ["https://www.booking.com/hotel/fr/mirific.en-gb.html"]
}
```

#### Bounded review run

```json
{
  "hotelUrls": [
    "https://www.booking.com/hotel/fr/mirific.en-gb.html",
    "https://www.booking.com/hotel/fr/example-riverside-hotel.en-gb.html"
  ],
  "maxReviews": 25,
  "sortBy": "f_recent_desc",
  "language": "en",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

### How to run the Actor in Apify Console

1. Open this Actor and select **Input**.
2. Add one or more HTTPS Booking.com hotel-page URLs to **Hotel URLs**.
3. Set **Max Reviews Per Hotel**, a supported public sort, and an optional language code. Configure standard Apify Proxy only if needed for your lawful use case.
4. Select **Save input** if you want to reuse the configuration.
5. Click **Start** and open the **Dataset** after the run finishes.
6. Use the **API** tab for programmatic access, inspect `OUTPUT` in the default key-value store, or download the dataset.

### How pagination, limits, and deduplication work

The browser opens each hotel page, uses the public reviews control when available, and follows the public next-page control. The review page size is fixed by the public interface at 10 records. `maxReviews` is applied independently to each hotel. With `maxReviews: 0`, the Actor continues until public pagination ends, three consecutive empty/duplicate pages occur, or an internal finite safety budget of 500 pages is reached. With a positive limit, the internal page budget is `ceil(maxReviews / 10) + 2` pages.

Reviews are deduplicated within each hotel using the public reviewer, date, score, title, positive text, and negative text fields. The summary `uniqueItems` count also prevents identical successful rows from being counted twice across the run. Input URL order is preserved. The Actor does not invent offsets when a public next-page control is absent.

`sortBy` and `language` are passed to the public review interface when supported. They are not private API parameters. There are no additional filters or user-selectable sorts beyond `sortBy`, and the Actor does not visit private or authenticated detail pages.

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

The browser checks the hotel page and review area for public access boundaries before extracting. If it sees a CAPTCHA, WAF page, login prompt, paywall, geofence, device check, rate limit, or access denial, it logs the outcome and stops that hotel's browser route. When the browser produces no successful review rows without an explicit access boundary, the Actor makes bounded public HTML/JSON-LD and reader fallback requests. It never tries to defeat the boundary.

The dataset contains only public review records with source-backed review content. A successful response with no reviews completes with `status: "SUCCEEDED"`, `runStatus: "SUCCEEDED"`, and `dataStatus: "NO_RESULTS"`, leaving the dataset empty. If every target is blocked or collection fails before a review is saved, the Actor fails the run and leaves the dataset empty. Blocked responses use stable codes such as `CAPTCHA_OR_CHALLENGE`, `WAF_BLOCKED`, `ACCESS_DENIED`, `LOGIN_REQUIRED`, `RATE_LIMITED`, or `GEOFENCE_RESTRICTED` in the run log. When some reviews were saved before another target failed or was blocked, the run succeeds with `status: "SUCCEEDED"` and `dataStatus: "PARTIAL"`, retaining the usable rows.

### Output examples

#### Rich successful review row

```json
{
  "url": "https://www.booking.com/hotel/fr/example-riverside-hotel.en-gb.html",
  "hotelUrl": "https://www.booking.com/hotel/fr/example-riverside-hotel.en-gb.html",
  "hotelName": "Example Riverside Hotel",
  "reviewPosition": 1,
  "requestedSort": "f_recent_desc",
  "requestedLanguage": "en",
  "reviewerName": "Example Guest",
  "reviewerCountry": "France",
  "overallScore": 8.4,
  "title": "A comfortable stay",
  "positiveText": "The room was clean and quiet.",
  "hotelReviewScore": 8.4,
  "hotelReviewCount": 1250,
  "scrapedAt": "2026-09-08T00:00:00.000Z"
}
```

#### Reader fallback row

```json
{
  "url": "https://www.booking.com/hotel/fr/example-riverside-hotel.en-gb.html",
  "hotelUrl": "https://www.booking.com/hotel/fr/example-riverside-hotel.en-gb.html",
  "hotelName": "Example Riverside Hotel",
  "reviewPosition": 1,
  "requestedSort": "f_recent_desc",
  "requestedLanguage": "en",
  "reviewerName": "Lorena",
  "reviewerCountry": "Colombia",
  "positiveText": "The breakfast and location were convenient.",
  "searchUrl": "https://r.jina.ai/http://www.booking.com/hotel/fr/example-riverside-hotel.en-gb.html",
  "scrapedAt": "2026-09-08T00:00:00.000Z"
}
```

Per-review score and date are intentionally absent from reader highlights when the public page does not expose them.

#### Run summary in key-value store

```json
{
  "status": "SUCCEEDED",
  "runStatus": "SUCCEEDED",
  "dataStatus": "PARTIAL",
  "datasetItems": 25,
  "diagnosticItems": 0,
  "diagnosticCount": 1,
  "requestErrorCount": 1,
  "blockedCount": 1,
  "noResultsCount": 0,
  "uniqueItems": 25
}
```

`OUTPUT` contains canonical `status` and `runStatus` values (`SUCCEEDED` or `FAILED`), a `dataStatus` value (`COMPLETE`, `PARTIAL`, `NO_RESULTS`, or `FAILED`), source-backed dataset counts, and operational diagnostic and failure counts. `diagnosticItems` is always `0`; diagnostics are not dataset rows.

### How much will it cost?

Apify charges for compute time and any proxy resources used by the run. Cost depends on the number of hotel URLs, review pages, browser time, and proxy type. Start with a small `maxReviews` value and verify public access before scheduling larger runs.

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 a run with the JSON shape shown above and read the default dataset. For blocked, failed, or empty runs, inspect the run log and `OUTPUT` counts. If the public site changes its markup, include the run ID and relevant log details in an **Issues** report. A repeated challenge is an access limitation, not a signal to increase retries or attempt a bypass.

The Actor omits fields that are not present in the public response. An absent score is not zero, an absent review date is not a fabricated date, and an absent reviewer country is not inferred from a flag or URL. Proxy configuration is standard Apify Proxy only; there is no stealth, fingerprint-evasion, CAPTCHA-solving, login, or private API mode.

### API and Issues

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

### Privacy, legal, and non-affiliation

This Actor reads public Booking.com pages and does not request credentials or private account data. Public reviews may still contain personal data. Use the Actor only for a lawful, legitimate purpose and follow Booking.com's terms, robots rules, applicable contracts, privacy laws, and rate limits. If you are unsure whether your use is lawful, consult qualified counsel.

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-reviews-scraper/changelog.md

# Actor input Schema

## `hotelUrls` (type: `array`):

Booking.com hotel page URLs to scrape reviews from (e.g. https://www.booking.com/hotel/fr/cosy-studio-2p-bastille.en-gb.html).

## `maxReviews` (type: `integer`):

Maximum number of reviews to scrape per hotel. Set 0 for all reviews.

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

How to sort the reviews.

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

Filter reviews by language code (e.g. en, fr, de). Leave empty for all languages.

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

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

## Actor input object example

```json
{
  "hotelUrls": [
    "https://www.booking.com/hotel/fr/mirific.en-gb.html"
  ],
  "maxReviews": 50,
  "sortBy": "f_recent_desc",
  "language": "",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Only source-backed public review records. Failed, blocked, or empty outcomes do not add dataset rows.

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

Run status, source-backed dataset counts, and operational failure 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 = {
    "hotelUrls": [
        "https://www.booking.com/hotel/fr/mirific.en-gb.html"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("w3crawler/booking-com-reviews-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 = {
    "hotelUrls": ["https://www.booking.com/hotel/fr/mirific.en-gb.html"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("w3crawler/booking-com-reviews-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 '{
  "hotelUrls": [
    "https://www.booking.com/hotel/fr/mirific.en-gb.html"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call w3crawler/booking-com-reviews-scraper --silent --output-dataset

```

## MCP server setup

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