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

Scrape guest reviews from any Booking.com hotel — liked/disliked text, score, date, room type, length of stay, and the hotel's management responses, which most alternatives skip. Working date filter and full review-feed capture (not just the first ~30). Runs on Apify residential proxies.

- **URL**: https://apify.com/agilevendor/booking-reviews-scraper.md
- **Developed by:** [Agilevendor](https://apify.com/agilevendor) (community)
- **Categories:** Travel, E-commerce
- **Stats:** 3 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.75 / 1,000 review scrapeds

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

Scrape all guest reviews from any Booking.com hotel page — liked/disliked text, score, date, room type, length of stay — **plus the hotel's management responses**, which most alternatives don't return.

**Why this scraper**

- ✅ **Every review, not just the first ~30** — pagination runs to the end of the feed.
- ✅ **A date filter that actually works** — collect only reviews after (or before) a date, accurately.
- ✅ **Management responses included** — the hotel's official replies, which most scrapers drop.
- ✅ **Rich context on every record** — hotel rating with category breakdown (Staff, Cleanliness, Location…), guest avatar, review photos, room ID, and source URL.
- ✅ **No blocking to deal with** — residential proxies and anti-bot handling are built in and on by default.
- ✅ **Lower price** — $0.80 per 1,000 reviews.

### What it does

- **Full set of reviews.** Pagination runs to the end of Booking's review feed, not just the first ~30 reviews. The Actor reads the hotel's total review count up front and collects every available review.
- **Working date filter (`cutoffDate`).** Collect only reviews newer (or older) than a given date — accurately, without over-fetching. Works with date sorting.
- **Management responses (`ownerResponse`).** The hotel's official reply to a review, whenever one exists.
- **Hotel context on every review.** Overall hotel rating and label (e.g. 9.4 "Superb"), total review count, and a per-category score breakdown (Staff, Cleanliness, Comfort, Location, Value, Wi-Fi) — alongside the guest avatar, any review photos, and the room ID.
- **Flexible sorting and score filter.** Sort by newest, oldest, score, or relevance; keep only the score bands you care about (e.g. superb only, poor only).
- **Reliable by design.** Booking's anti-bot protection is handled automatically — residential proxies and session rotation are built in and on by default, so you just get the reviews.

### How to use

1. Open a hotel on Booking.com and copy its page URL from the browser address bar.
2. Paste one or more such URLs into **Booking.com hotel URLs**.
3. Optionally set how many reviews to collect, the sort order, a cutoff date, or a score filter.
4. Click **Start** and wait for the run to finish.
5. Download the results from the **Output** tab in JSON, CSV, Excel, XML, or HTML.

### Input

| Field | Type | Description |
|---|---|---|
| `startUrls` | array | Booking.com hotel page URLs (required). |
| `maxReviewsPerHotel` | integer | Max reviews per hotel. `0` — all available (default). Set a number to cap how many you collect (and how much you pay). |
| `sortReviewsBy` | enum | `newest` / `oldest` / `highest_score` / `lowest_score` / `relevance`. Default `newest`. |
| `cutoffDate` | string | Date boundary. With `newest` keeps reviews newer than the date; with `oldest`, older than it. Ignored for other sort orders. |
| `reviewScores` | array | Score bands to keep: `ALL`, `REVIEW_ADJ_SUPERB` (9+), `REVIEW_ADJ_GOOD` (7–8.9), `REVIEW_ADJ_AVERAGE_PASSABLE` (5–6.9), `REVIEW_ADJ_POOR` (3–4.9), `REVIEW_ADJ_VERY_POOR` (below 3). Empty or `ALL` — all scores. |
| `proxyConfiguration` | object | Proxy. Defaults to Apify Residential. |
| `customData` | object | Arbitrary JSON attached to every output record. |

Example input:

```json
{
  "startUrls": [
    { "url": "PASTE_BOOKING_HOTEL_URL_HERE" }
  ],
  "maxReviewsPerHotel": 0,
  "sortReviewsBy": "newest",
  "reviewScores": ["ALL"]
}
```

### Output (per review)

Each collected review is one record in the dataset, including the management response (`ownerResponse`) when the hotel has replied.

![Booking.com reviews output: management responses, hotel rating, room and stay details](https://i.imgur.com/lOhiilu.png)

Each record also carries hotel-level context — overall rating, rating label, total review count, and a per-category breakdown (Staff, Cleanliness, Location, …) — plus the guest avatar, any photos attached to the review, the room ID, and the source URL.

Example records (real output from The Ritz London):

```json
[
  {
    "id": "1d2e3a39286aec20",
    "hotelId": "gb/the-ritz-london",
    "hotelIdNumeric": "280539",
    "reviewPage": 1,
    "userName": "Colin",
    "userLocation": "Ecuador",
    "roomInfo": "Junior Suite",
    "stayDate": { "checkin": "2026-06-23", "checkout": "2026-06-24" },
    "nights": 1,
    "reviewDate": 1782332935,
    "reviewDateIso": "2026-06-24T20:28:55.000Z",
    "reviewTitle": "La gente es igual de simpatica, a pesar de las dificultades de la remodelacion.",
    "rating": 9,
    "reviewTextParts": {
      "Liked": "El Junior Suite es mucho mas grande que antes, aprox 75 m2. El restaurante nuevo esta muy bien."
    },
    "ownerResponse": "Dear Colin,\n\nThank you for your kind feedback. We hope to welcome you back soon.\n\nBest regards,\nDuty Managers, The Ritz London",
    "helpfulVotesCount": 0,
    "isApproved": true,
    "reviewLanguage": "es",
    "guestType": "Couple",
    "countryCode": "ec",
    "userAvatar": "https://xx.bstatic.com/xdata/images/xphoto/square64/36403125.jpg",
    "images": [],
    "stayRoomId": 28053908,
    "startUrl": "https://www.booking.com/hotel/gb/the-ritz-london.html",
    "hotelRating": 9.4,
    "hotelRatingLabel": "Superb",
    "hotelReviews": 452,
    "hotelRatingScores": [
      { "name": "Staff", "codeName": "hotel_staff", "score": 9.6 },
      { "name": "Cleanliness", "codeName": "hotel_clean", "score": 9.7 },
      { "name": "Location", "codeName": "hotel_location", "score": 9.8 },
      { "name": "Value for money", "codeName": "hotel_value", "score": 8.6 }
    ],
    "customData": {}
  },
  {
    "id": "290d91602d68ff44",
    "hotelId": "gb/the-ritz-london",
    "hotelIdNumeric": "280539",
    "reviewPage": 1,
    "userName": "Stephen",
    "userLocation": "United Kingdom",
    "roomInfo": "Deluxe Room",
    "stayDate": { "checkin": "2026-04-10", "checkout": "2026-04-11" },
    "nights": 1,
    "reviewDate": 1781364950,
    "reviewDateIso": "2026-06-13T15:35:50.000Z",
    "reviewTitle": null,
    "rating": 10,
    "reviewTextParts": {},
    "ownerResponse": null,
    "helpfulVotesCount": 0,
    "isApproved": true,
    "reviewLanguage": "en",
    "guestType": "Solo traveller",
    "countryCode": "gb",
    "userAvatar": "https://xx.bstatic.com/static/img/review/avatars/ava-s.png",
    "images": [],
    "stayRoomId": 28053902,
    "startUrl": "https://www.booking.com/hotel/gb/the-ritz-london.html",
    "hotelRating": 9.4,
    "hotelRatingLabel": "Superb",
    "hotelReviews": 452,
    "hotelRatingScores": [
      { "name": "Staff", "codeName": "hotel_staff", "score": 9.6 },
      { "name": "Cleanliness", "codeName": "hotel_clean", "score": 9.7 },
      { "name": "Location", "codeName": "hotel_location", "score": 9.8 },
      { "name": "Value for money", "codeName": "hotel_value", "score": 8.6 }
    ],
    "customData": {}
  }
]
```

### Proxy and cost

The Actor is billed pay-per-event: **$0.80 per 1,000 reviews** collected, and nothing else — no charge for run time or platform usage.

Booking.com blocks datacenter IPs, so the Actor uses **residential proxies** (Apify Residential by default). Proxy traffic is billed to the account that runs the Actor.

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

The Actor only reads information that guests have already chosen to publish on Booking.com — review text, score, room type, stay dates, the reviewer's display name, and the management reply. It does not log in, bypass any access restriction, or collect hidden or private data such as email addresses or profile photos. In the United States, courts have held that scraping publicly accessible pages without logging in generally does not break computer-access law (the CFAA), but that is not the whole picture: a site's Terms of Service may still restrict scraping as a matter of contract, copyright can apply to the text of individual reviews, and the rules differ by jurisdiction and by what you do with the results.

A review and its display name can also count as personal data under laws such as the GDPR, even when published publicly. You are responsible for having a lawful basis to collect and use it. The Actor keeps the output to publicly shown, non-identifying fields and does not collect contact details, exact addresses, or profile photos.

This is general information, not legal advice. If you are unsure whether your use case is allowed, check with a lawyer.

### Your feedback

This Actor is actively maintained. If you hit a bug, notice a change on Booking.com that breaks the output, or want a new field or option, open an issue on the <a href="https://console.apify.com/actors/8LwO0dtgEdi3qKvGS/issues" target="_blank" rel="noopener"><strong>Issues</strong> tab</a> of this Actor — it goes straight to the developer.

# Actor input Schema

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

List of Booking.com hotel page URLs to scrape reviews from.

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

How many reviews to collect per hotel. 0 (default) — all available through Booking's review feed. Set a number to cap how many you collect and how much you pay.

## `sortReviewsBy` (type: `string`):

Review order. The date filter (cutoffDate) works only with date sorting (newest/oldest first).

## `cutoffDate` (type: `string`):

Collect reviews relative to this date. Works only with date sorting: "Newest first" — reviews newer than the date; "Oldest first" — older than the date. Ignored for other sort orders.

## `reviewScores` (type: `array`):

Which review scores to include. Empty or All — all scores.

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

Booking.com blocks datacenter IPs, so residential proxies are required. Proxy traffic is billed to the account that runs the Actor.

## `customData` (type: `object`):

Any JSON object that will be attached to every review record under the customData field.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.booking.com/hotel/gb/the-ritz-london.html"
    }
  ],
  "maxReviewsPerHotel": 50,
  "sortReviewsBy": "highest_score",
  "reviewScores": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "customData": {}
}
```

# Actor output Schema

## `reviews` (type: `string`):

Collected hotel reviews in the 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 = {
    "startUrls": [
        {
            "url": "https://www.booking.com/hotel/gb/the-ritz-london.html"
        }
    ],
    "maxReviewsPerHotel": 50,
    "sortReviewsBy": "highest_score"
};

// Run the Actor and wait for it to finish
const run = await client.actor("agilevendor/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": [{ "url": "https://www.booking.com/hotel/gb/the-ritz-london.html" }],
    "maxReviewsPerHotel": 50,
    "sortReviewsBy": "highest_score",
}

# Run the Actor and wait for it to finish
run = client.actor("agilevendor/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": [
    {
      "url": "https://www.booking.com/hotel/gb/the-ritz-london.html"
    }
  ],
  "maxReviewsPerHotel": 50,
  "sortReviewsBy": "highest_score"
}' |
apify call agilevendor/booking-reviews-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/8LwO0dtgEdi3qKvGS/builds/njb8iGrTEylrHtBjv/openapi.json
