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

Scrape guest reviews of any Booking.com hotel: score, title, positive and negative text, reviewer country and traveler type, room type, stay dates, hotel response. Sort and filter by language, traveler type and keyword. No login. Pay-per-result.

- **URL**: https://apify.com/santamaria-automations/booking-reviews-scraper.md
- **Developed by:** [NanoScrape](https://apify.com/santamaria-automations) (community)
- **Categories:** Travel, E-commerce, Other
- **Stats:** 3 total users, 2 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/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

## Booking.com Reviews Scraper

Scrape guest reviews of any hotel on [Booking.com](https://www.booking.com). Give it hotel URLs and get one row per review: score, title, positive and negative text, reviewer country, traveler type, room type, stay dates and the hotel's reply. No login required.

### What data can you extract?

- **Review id, score (1-10), title, positive text, negative text** and the **review language**
- **Review date** (ISO 8601)
- **Reviewer name, country and country code**, and **traveler type** (couple, solo, family, group)
- **Room type, number of nights, check-in and check-out date, stay status**
- **Hotel response** and **helpful votes**
- **Hotel id, name and URL**

About 50% of Booking.com reviews are score-only: the guest left a rating but no text, so title, positive and negative text are empty for them (roughly half have a positive or negative text, a quarter have a title). Set `onlyWithText` to skip those.

### Use with AI Agents (MCP)

Connect this actor to any MCP-compatible AI client, including Claude Desktop, Claude.ai, Cursor, VS Code, LangChain and LlamaIndex.

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

Example prompt: "Use `booking-reviews-scraper` to get the 200 newest reviews of https://www.booking.com/hotel/ch/motel-one-zurich.html and summarise the main complaints."

### How to use

```json
{
  "startUrls": ["https://www.booking.com/hotel/ch/motel-one-zurich.html"],
  "maxReviewsPerHotel": 200,
  "sortBy": "newest",
  "languages": ["en", "de"],
  "travelerTypes": ["COUPLES"]
}
```

An empty input `{}` also works: it scrapes 50 reviews of one example hotel.

### Input parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `startUrls` | array | example hotel | Booking.com hotel URLs (`/hotel/<country>/<name>.html`, any language suffix or query) |
| `hotelIds` | array | none | Numeric hotel ids, for hotels whose URL cannot be resolved |
| `maxReviewsPerHotel` | integer | `100` | 1-100,000 reviews per hotel (an empty input runs a 50-review demo on the example hotel) |
| `sortBy` | string | `newest` | `newest`, `oldest`, `highest` or `lowest` |
| `languages` | array | all | Language codes such as `en`, `de`, `fr` |
| `travelerTypes` | array | all | `COUPLES`, `SOLO_TRAVELLERS`, `FAMILIES`, `GROUP_OF_FRIENDS`, `BUSINESS_TRAVELLERS` |
| `keyword` | string | none | Only reviews containing this text |
| `onlyWithText` | boolean | `false` | Skip score-only reviews (no title and no text). Skipped reviews are neither saved nor charged; `maxReviewsPerHotel` then counts saved reviews. A hotel scan stops after 5 x `maxReviewsPerHotel` raw reviews or at the end of its list |

### What you get

One row per review:

| Field | Type | Description |
|-------|------|-------------|
| `review_id` | string | Booking.com review id |
| `hotel_id` | integer | Booking.com hotel id |
| `hotel_url` | string | Hotel page URL (null when only a hotel id was given) |
| `hotel_name` | string | Hotel name (null when only a hotel id was given) |
| `reviewer_name` | string | Reviewer first name or alias |
| `reviewer_country` | string | Reviewer country |
| `reviewer_country_code` | string | Reviewer country code |
| `traveler_type` | string | Couple, Solo traveler, Family or Group |
| `room_type` | string | Booked room type |
| `nights` | integer | Number of nights stayed |
| `checkin_date` | string | Check-in date |
| `checkout_date` | string | Check-out date |
| `stay_status` | string | Stay status |
| `review_date` | string | Review date, ISO 8601 UTC |
| `score` | number | Review score, 1 to 10 |
| `title` | string | Review title (only some guests write one) |
| `positive_text` | string | What the guest liked |
| `negative_text` | string | What the guest disliked |
| `language` | string | Language code of the review text |
| `hotel_response` | string | Reply from the hotel |
| `helpful_votes` | integer | Helpful votes |
| `review_url` | string | Reviews page of the hotel on Booking.com |
| `scraped_at` | string | Scrape time, ISO 8601 UTC |
| `source_platform` | string | Always booking.com |

#### Output example

```json
{
  "review_id": "e1d2eedc5e49225f",
  "hotel_id": 1388383,
  "hotel_url": "https://www.booking.com/hotel/fr/hotelf1-paris-porte-de-montmartre.html",
  "hotel_name": "HotelF1 Paris Saint Ouen Marché Aux Puces",
  "reviewer_name": "Maria",
  "reviewer_country": "Spain",
  "reviewer_country_code": "es",
  "traveler_type": "Couple",
  "room_type": "Cabrio Room with Private Bathroom",
  "nights": 4,
  "checkin_date": "2026-10-11",
  "checkout_date": "2026-10-15",
  "stay_status": "stayed",
  "review_date": "2026-10-20T22:20:47Z",
  "score": 8,
  "title": null,
  "positive_text": "Hotel on the outskirts of Paris, small but cosy rooms, fair value for money",
  "negative_text": "The receptionist was on a video call and ignored us at check-in",
  "language": "es",
  "hotel_response": null,
  "helpful_votes": 0,
  "review_url": "https://www.booking.com/reviews/fr/hotel/hotelf1-paris-porte-de-montmartre.html",
  "scraped_at": "2026-10-21T12:00:00Z",
  "source_platform": "booking.com"
}
```

Fields Booking.com does not publish for a review are `null`.

### Pricing

Pay per result: one result event for every review saved, plus a one-time start event per run. Prices: `review-start` $0.001 per run, `review-result` $0.0003 per review ($0.30 per 1,000 reviews).

| Event | When |
|-------|------|
| `review-start` | Once per run, right before the first review is saved |
| `review-result` | Per review saved to the dataset |

Billing follows what is saved: only rows pushed to the dataset are charged, so score-only reviews dropped by `onlyWithText` cost nothing. Duplicates are never saved or charged twice, runs that find no reviews are not charged, and a restarted run does not charge reviews it already saved.

### Performance

- **Speed**: 25 reviews per request, about 1 second per page, so 1,000 reviews take roughly a minute
- **Traffic**: about 0.8 MB per 1,000 reviews

### Tips

- Hotel URLs are matched to Booking hotel ids by name. If a URL cannot be resolved the run says so; add the numeric id to `hotelIds` instead.
- The `languages` filter matches the language of the review text; reviews with a score only may have an unknown language code.
- `sortBy: newest` is the best choice for scheduled monitoring runs.

### Related actors

- [Booking.com Scraper](https://apify.com/santamaria-automations/booking-com-scraper) - hotel listings with prices, ratings and availability for a destination.
- [TripAdvisor Scraper](https://apify.com/santamaria-automations/tripadvisor-scraper) - hotel and restaurant reviews from TripAdvisor.
- [Google Maps Scraper](https://apify.com/santamaria-automations/google-maps-scraper) - hotel listings and reviews from Google Maps.
- [Trustpilot Scraper](https://apify.com/santamaria-automations/trustpilot-scraper) - company reviews from Trustpilot.

### Data protection

This actor returns only data that is publicly visible on the source pages. Results can include personal data, such as names, phone numbers, email addresses and addresses of private persons, sole traders or contact persons. Where the source labels an entry type, it is included so you can filter the results yourself.

You are responsible for using the data lawfully, including the GDPR/DSGVO, national data-protection laws and unfair-competition rules (e.g. UWG) for marketing and outreach.

# Actor input Schema

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

Booking.com hotel page URLs, e.g. https://www.booking.com/hotel/ch/motel-one-zurich.html. Any language suffix or query string is fine. Defaults to one example hotel when both startUrls and hotelIds are empty.

## `hotelIds` (type: `array`):

Optional numeric Booking.com hotel ids, for hotels whose URL cannot be resolved automatically.

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

Maximum number of reviews to save for each hotel. 25 reviews are fetched per request. Defaults to 100. Empty input runs a 50-review demo on the built-in example hotel.

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

Order of the reviews.

## `languages` (type: `array`):

Optional language codes such as en, de, fr. Only reviews written in these languages are returned.

## `travelerTypes` (type: `array`):

Optional filter by traveler type.

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

Optional text; only reviews containing it are returned.

## `onlyWithText` (type: `boolean`):

Skip reviews that are only a score (no title, positive text or negative text). About half of Booking.com reviews have no text. Skipped reviews are not saved and not charged, and maxReviewsPerHotel counts saved reviews. Scanning stops after 5 times maxReviewsPerHotel raw reviews.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.booking.com/hotel/ch/motel-one-zurich.html"
  ],
  "maxReviewsPerHotel": 50,
  "sortBy": "newest",
  "onlyWithText": false
}
```

# Actor output Schema

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

Dataset containing the scraped reviews

# 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/ch/motel-one-zurich.html"
    ],
    "maxReviewsPerHotel": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/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/ch/motel-one-zurich.html"],
    "maxReviewsPerHotel": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/booking-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 '{
  "startUrls": [
    "https://www.booking.com/hotel/ch/motel-one-zurich.html"
  ],
  "maxReviewsPerHotel": 50
}' |
apify call santamaria-automations/booking-reviews-scraper --silent --output-dataset

```

## MCP server setup

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