# Booking.com Reviews Scraper — Most Comprehensive (`scrapersdelight/booking-reviews-scraper`) Actor

From $0.20 per 1,000 reviews — 10× cheaper than typical $2/1k actors. Scrape Booking.com hotel reviews: title, positive/negative text, 0–10 score, stay date, room, nights, traveler type, country, with date/language/keyword filters + a new-review monitor with alerts. No login or API key.

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

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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 Reviews Scraper — Most Comprehensive

**Scrape Booking.com hotel reviews — title, positive AND negative text, 0–10 score, stay date, room type, nights, traveler type, country, plus the hotel's full sub-score breakdown — at $0.20 per 1,000 reviews. Filter by date range (with early-stop), language, keyword, score band, or traveler type, and run it on a schedule as a new-review monitor with Slack/email/webhook alerts.**

### Why this one?

| | **This actor** | Leading Booking.com reviews scraper |
|---|---|---|
| **Price per 1,000 reviews** | **$0.20** (pay-per-event) | $2.00 (pay per result) |
| Positive / negative text split | ✅ separate fields | ✅ |
| Review title + 0–10 score | ✅ | ✅ |
| Hotel sub-score breakdown (cleanliness, comfort, location, facilities, staff, value, Wi-Fi) | ✅ on every row | not advertised |
| Stay metadata (room type, nights, stay month, trip type, traveler type, mobile flag) | ✅ parsed into separate fields | not advertised |
| Reviewer country + review/helpful counts | ✅ | partial |
| Language filter (server-side, 35+ languages or ALL) | ✅ | ✅ |
| Date-range filter with **early-stop** (stops paginating — you don't pay for skipped pages) | ✅ | not advertised |
| Keyword filter ("breakfast", "noise", "bed bugs"…) | ✅ | not advertised |
| Score-band filter (e.g. only 0–5 complaints) | ✅ | not advertised |
| Sort control (newest / oldest / featured / best / worst) | ✅ | not advertised |
| **New-review monitor** + Slack / email / webhook alerts | ✅ built in | ❌ |
| GDPR toggle (`stripPersonalData`, ON by default) | ✅ | ❌ |
| Failure handling | per-page retry with fresh browser fingerprint + rotating proxy session — a single bad page never kills the run | unknown |
| Login / API key needed | none | none |

***

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

It reads Booking.com's own server-rendered review pages (no login, no API key, no fragile headless browser) and returns clean, structured review rows you can export to **JSON, CSV, Excel, or fetch via the Apify API**. Paste any hotel URL — that's it.

- 📝 **The full review** — title, the positive ("liked") and negative ("disliked") texts as separate fields, plus the raw tag list.
- ⭐ **Scores** — the review's 0–10 score, and the hotel's overall score **with the complete category breakdown** (cleanliness, comfort, location, facilities, staff, value for money, free Wi-Fi) on every row.
- 🧳 **Stay context** — room type, number of nights, stay month, leisure vs business, couple/solo/family/group, submitted-from-mobile.
- 🌍 **Reviewer context** — country + country code, age group when shown, how many reviews and helpful votes the reviewer has (first name only if you opt out of `stripPersonalData`).
- 🗓️ **Date filters that save money** — `dateFrom`/`dateTo` with newest-first early-stop: pagination halts the moment reviews get older than your window.
- 🔎 **Keyword & score filters** — isolate every "breakfast" complaint or every ≤5/10 review across thousands of stays.
- 🔔 **New-review monitor** — schedule it and get **Slack / email / webhook alerts** for each fresh review per hotel (reputation watch for your own or competitor hotels).

### What data does it extract?

One dataset row per review:

- 🆔 `review_id` (stable dedup hash), `page_number`, `scraped_at`
- 🏨 `hotel_name`, `hotel_cc`, `hotel_slug`, `hotel_url`, `reviews_url`
- ⭐ `hotel_score`, `hotel_total_reviews`, `hotel_reviews_in_language`, `hotel_score_breakdown {cleanliness, comfort, location, facilities, staff, value_for_money, free_wifi}`
- 📝 `title`, `title_is_scoreword`, `positive_text`, `negative_text`, `owner_response`\*
- 🔢 `score` (0–10), `score_best`
- 🗓️ `review_date` (ISO), `review_date_raw`, `stayed_date` (e.g. "June 2026")
- 🧳 `nights`, `trip_type` (leisure/business), `traveler_type` (couple/solo/family/group), `room_type`, `submitted_via_mobile`, `tags_raw[]`
- 🌍 `reviewer_country`, `reviewer_country_code`, `reviewer_age_group`, `reviewer_review_count`, `reviewer_helpful_votes`, `reviewer_name` (null unless you disable `stripPersonalData`)
- 🌐 `language` (the language scope you requested), ✨ `is_new` (monitor mode)

*\* Booking.com's review pages only rarely include property responses; the field is populated whenever the page shows one.*

### Who is it for?

- 🏨 **Hoteliers & revenue managers** watching their own and competitors' guest sentiment in near-real-time.
- 📊 **Hospitality analysts & consultants** building sentiment datasets across markets, brands, or seasons.
- 🤖 **AI / NLP teams** that need labeled positive/negative hotel text at scale (the pos/neg split is free labeling).
- 🛎️ **Reputation & CX tools** wiring new reviews into Slack, dashboards, or ticketing via webhook.
- 🏠 **OTA / travel product teams** doing competitive research on inventory quality.

### How to use it (step by step)

1. Click **Try for free**.
2. Paste one or more **hotel URLs** — any form works: `https://www.booking.com/hotel/gb/royal-national.html`, the reviews URL, or just `gb/royal-national`.
3. *(Optional)* set filters: date range, language (`all` = every language), keyword, score band, trip/traveler type.
4. Click **Start**, then open the **Dataset** tab to view/export.
5. *(Optional)* set `monitorMode: true` + an Apify **Schedule** + a Slack/webhook/email channel to get pinged on every new review.

#### Quick start

```json
{
  "startUrls": ["https://www.booking.com/hotel/gb/royal-national.html"],
  "maxReviewsPerHotel": 200
}
```

#### Competitor reputation monitor

```json
{
  "startUrls": [
    "https://www.booking.com/hotel/us/pod.html",
    "https://www.booking.com/hotel/us/your-competitor.html"
  ],
  "monitorMode": true,
  "slackWebhookUrl": "https://hooks.slack.com/services/…"
}
```

#### Complaint mining (last 90 days, low scores only)

```json
{
  "startUrls": ["https://www.booking.com/hotel/gb/royal-national.html"],
  "maxReviewsPerHotel": 0,
  "dateFrom": "2026-03-14",
  "maxScore": 5,
  "language": "all"
}
```

### Input

| Field | What it does |
|-------|--------------|
| `startUrls` | hotel page URLs (or `cc/slug` shorthand), one per hotel |
| `maxReviewsPerHotel` | cap per hotel (0 = all reviews; default 50) |
| `sortBy` | `newest` (default) · `oldest` · `featured` · `score_high` · `score_low` |
| `language` | server-side language scope: `all` (default, most reviews), `en`, `fr`, `de`, … or `default` |
| `dateFrom` / `dateTo` | review-date window (YYYY-MM-DD); newest-first runs early-stop below `dateFrom` |
| `keyword` | only reviews mentioning this word (title/positive/negative/room) |
| `tripType` / `travelerType` | leisure/business · couple/solo/family/group |
| `minScore` / `maxScore` | 0–10 score band |
| `stripPersonalData` | ON by default — drops the reviewer's first name (GDPR-friendly) |
| `maxRetriesPerPage` | anti-WAF retry budget per page (default 10) |
| `monitorMode`, `alertOnNewReview` | recurring new-review watcher |
| `webhookUrl`, `slackWebhookUrl`, `emailRecipients` | alert channels |
| `proxyConfiguration` | Apify proxy (datacenter works; RESIDENTIAL for very large runs) |

### Output

Example record (truncated):

```json
{
  "hotel_name": "Royal National Hotel",
  "hotel_score": 7.9,
  "hotel_total_reviews": 19601,
  "hotel_score_breakdown": { "cleanliness": 8.3, "comfort": 8.3, "location": 9.1, "facilities": 7.8, "staff": 8.6, "value_for_money": 7.9, "free_wifi": 8.2 },
  "title": "Clean rooms, great location and pleasant staff.",
  "positive_text": "The location was ideal. Walking distance to Russell Square Underground…",
  "negative_text": "Our tv did not work correctly…",
  "score": 8, "score_best": 10,
  "review_date": "2026-06-12", "stayed_date": "June 2026",
  "nights": 3, "trip_type": "leisure", "traveler_type": "Couple",
  "room_type": "Standard Plus Double Room", "submitted_via_mobile": true,
  "reviewer_country": "Ireland", "reviewer_country_code": "ie",
  "reviewer_review_count": 1, "reviewer_helpful_votes": 0,
  "personal_data_stripped": true
}
```

### How much does it cost?

Pay-per-event — you pay for what you pull, no subscription:

| Event | What it covers | Price |
|-------|----------------|-------|
| `lot-scraped` | each review returned | **$0.0002** (= **$0.20 / 1,000 reviews**) |
| `monitor-run-completed` | each scheduled watch run | $0.02 / run |
| `new-lot-detected` | each new review found by the monitor | $0.005 / review |
| `alert-delivered` | each Slack/email/webhook push | $0.002 / alert |

*(Final per-event prices are set on the actor's pricing page.)*

**That's $0.20 per 1,000 reviews — about 10× cheaper than the typical $2.00/1k Booking reviews actor.** A daily monitor on 5 hotels costs roughly $0.10/day plus the new reviews it actually finds.

### Is it legal? (GDPR & ToS note — read this)

- **Personal data:** reviews can contain personal data (the reviewer's first name and nationality). By default this actor **strips the reviewer's name** (`stripPersonalData: true`). Only disable that if you have a lawful basis under GDPR/your local privacy law to process reviewer names, and honor deletion requests.
- **Terms of Service:** Booking.com's ToS does not welcome automated collection; this is a **gray area** that this actor does not resolve for you. The data scraped is publicly visible without any login, and courts have repeatedly found scraping public pages lawful (e.g. *hiQ v. LinkedIn*) — but **you are responsible for your own use case, jurisdiction, and volume**. Use the data for analysis/monitoring, don't republish reviews wholesale.

### FAQ

**Do I need a Booking.com account, login, or API key?**
No. The reviews are served on public pages — the actor reads them directly. No login or API key.

**Which hotels can it scrape?**
Any property on Booking.com with guest reviews — paste its hotel page URL in any country/locale form.

**How many reviews can I get per hotel?**
All of them (set `maxReviewsPerHotel: 0`). Pages hold 25 reviews each and the actor paginates gaplessly until the end, your cap, or your date window.

**Does it get non-English reviews?**
Yes — the default `language: "all"` returns every language (e.g. 19,601 vs only 6,547 English reviews for a large London hotel). Set a 2-letter code to scope to one language.

**Can I get only recent reviews?**
Yes — `dateFrom` (+ default newest-first sort) stops pagination the moment it reaches older reviews, so a "last 30 days" pull on a 20k-review hotel costs only a few pages.

**Can I monitor a hotel for new reviews?**
Yes. `monitorMode: true` + an Apify Schedule. The actor remembers what it has seen per hotel (in a persistent named store) and outputs/alerts **only new reviews**, to Slack, email, or any webhook.

**Does it include review scores and sub-scores?**
Every review carries its 0–10 score, and every row carries the hotel's full category breakdown (cleanliness, comfort, location, facilities, staff, value, Wi-Fi). Booking.com does not publish per-review category scores on its review pages.

**Does it include the hotel's reply to a review?**
The `owner_response` field is populated whenever Booking.com's review page shows one — most properties' responses are not exposed there, so expect it to be null for most rows.

**Why do I see "WAF/odd response … retry" lines in the log?**
Booking.com randomly challenges ~2 of 3 requests with an AWS WAF page. The actor retries with a fresh browser fingerprint, cookie jar, and proxy session — a clean page typically arrives within 1–4 tries. That's normal and already priced in.

**What if one hotel URL fails?**
The run keeps going — each hotel is isolated, and whatever was collected is always pushed. A failed page logs a warning instead of crashing the run.

**Is the reviewer's name included?**
Not by default (`stripPersonalData: true`). Disable it only if you have a lawful basis to process names; nationality, review counts, and helpful votes are kept either way.

**How do I export the data?**
JSON, CSV, Excel, HTML, or RSS from the Dataset tab, or via the Apify API. Webhooks/Slack/email for monitor alerts.

**Can I run it from my own code / Make / Zapier / n8n?**
Yes — call it via the Apify API or client libraries, or wire the alert webhook into any automation tool.

### You might also like

- 🛫 Airline & travel review scrapers
- 🏠 Vacation-rental review & listing scrapers
- ⭐ Google Maps / TripAdvisor review scrapers

### Feedback

Found a missing field or want a new filter? Open an issue on the actor — fast fixes and feature requests welcome.

# Actor input Schema

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

Booking.com hotel page URLs — any of these forms works: https://www.booking.com/hotel/gb/royal-national.html, https://www.booking.com/reviews/gb/hotel/royal-national.html, or the shorthand 'gb/royal-national'. One entry per hotel.

## `maxReviewsPerHotel` (type: `integer`):

Hard cap on reviews collected per hotel (cost/safety guard). Defaults to 50 for a fast first run — set 0 for ALL reviews of each hotel.

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

Server-side review ordering. 'Newest first' is best for monitors and date-range scrapes (enables early-stop).

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

Server-side language filter (Booking's own r\_lang). 'all' = every language (most reviews). Use a 2-letter code like en, fr, de, es, it, nl, zh, ja… 'default' lets Booking pick.

## `dateFrom` (type: `string`):

Only reviews posted ON/AFTER this date. With 'Newest first' the actor stops paginating as soon as it reaches older reviews (early-stop = fewer requests).

## `dateTo` (type: `string`):

Only reviews posted ON/BEFORE this date.

## `keyword` (type: `string`):

Only reviews whose title/positive/negative text or room type contains this word (case-insensitive). E.g. 'breakfast', 'noise', 'bed bugs'.

## `tripType` (type: `string`):

Only leisure or business trips.

## `travelerType` (type: `string`):

Only reviews by this traveler type.

## `minScore` (type: `integer`):

Only reviews scored at/above this. Combine with maxScore to isolate e.g. complaints (0–5).

## `maxScore` (type: `integer`):

Only reviews scored at/below this.

## `stripPersonalData` (type: `boolean`):

ON (default): drop the reviewer's first name from the output (nationality, age group, and review counts are kept — they don't identify a person). Turn OFF only if you have a lawful basis to process reviewer names.

## `maxRetriesPerPage` (type: `integer`):

Booking.com's AWS WAF challenges requests at random (~2 of 3). Each retry uses a fresh cookie jar + proxy session; a clean page usually arrives within 1–4 tries. Raise this if you see 'no clean reviews page' warnings.

## `monitorMode` (type: `boolean`):

Recurring watcher: diff against the prior run's seen reviews (per hotel) and output/alert ONLY new reviews. Pair with an Apify Schedule and Sort by = Newest first.

## `alertOnNewReview` (type: `boolean`):

In monitor mode, deliver an alert for each new review via the channels below.

## `webhookUrl` (type: `string`):

POST endpoint for new-review alert payloads (Make / Zapier / n8n / custom). One JSON body per alert.

## `slackWebhookUrl` (type: `string`):

Slack incoming-webhook URL for formatted new-review cards.

## `emailRecipients` (type: `array`):

Email addresses for the new-review digest (sent via apify/send-mail).

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

Proxy settings. Booking.com's WAF challenges requests at random — the retry loop beats it with datacenter proxies; switch to RESIDENTIAL for large bulk runs if you see many retries.

## `diagnose` (type: `boolean`):

Dev only. Dumps the raw reviews HTML to the key-value store (DEBUG\_REVIEWS\_HTML), logs the parsed first review + a pagination check, then exits. Leave off for normal runs.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.booking.com/hotel/gb/royal-national.html",
    "https://www.booking.com/hotel/us/pod.html"
  ],
  "maxReviewsPerHotel": 50,
  "sortBy": "newest",
  "language": "all",
  "tripType": "all",
  "travelerType": "all",
  "stripPersonalData": true,
  "maxRetriesPerPage": 10,
  "monitorMode": false,
  "alertOnNewReview": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "diagnose": false
}
```

# Actor output Schema

## `items` (type: `string`):

The dataset of scraped Booking.com reviews (one review per row).

# 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 = {
    "startUrls": [
        "https://www.booking.com/hotel/gb/royal-national.html",
        "https://www.booking.com/hotel/us/pod.html"
    ],
    "maxReviewsPerHotel": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/booking-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 = {
    "startUrls": [
        "https://www.booking.com/hotel/gb/royal-national.html",
        "https://www.booking.com/hotel/us/pod.html",
    ],
    "maxReviewsPerHotel": 50,
}

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

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://www.booking.com/hotel/gb/royal-national.html",
    "https://www.booking.com/hotel/us/pod.html"
  ],
  "maxReviewsPerHotel": 50
}' |
apify call scrapersdelight/booking-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=scrapersdelight/booking-reviews-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9alsri5uL2xMdwYTc/builds/JwlvuDH29brdG32u0/openapi.json
