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

Scrape guest reviews from Booking.com hotel page URLs. Returns score, date, title, liked and disliked text, guest country, traveler type, room, nights, stay dates, photo count and owner reply. Filter by language, score, traveler type and date. Optional AI sentiment and topic tags.

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

## Pricing

from $1.75 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

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

Booking.com Reviews Scraper collects guest reviews from Booking.com hotel pages and returns them as structured records. You give it one or more hotel page URLs, for example `https://www.booking.com/hotel/gb/the-savoy.html`. For each review it returns the score, the date, the title, what the guest liked and disliked, the guest's name, country and traveler type, the room they booked, the length and dates of their stay, helpful votes, the property's reply and the number of photos.

The Actor opens each hotel page in a real browser and pages through the reviews using the same review request the site uses when you click "Read all reviews". The data therefore comes from the site's structured review data rather than from the page layout, so fields stay consistent between hotels.

You can sort reviews (newest, oldest, most relevant, highest or lowest score), and filter them by language, traveler type, score band and date. You can optionally add an AI label for the overall sentiment and the topics each review mentions.

Typical uses:

- Tracking what guests say about your own property, week by week.
- Comparing the review scores and guest comments of several hotels side by side.
- Building datasets of hotel reviews for research or for training text classifiers.
- Watching for new negative reviews and whether the property replied.

This Actor is an independent tool. It is not affiliated with, endorsed by or sponsored by Booking.com.

### What data can you get from Booking.com reviews?

Each dataset item is one review with written text. Reviews that only have a score, with no title or comments, are skipped by default (see `includeReviewsWithoutText`). Fields that Booking.com does not show for a review are `null`.

| Field | Description | Example |
| --- | --- | --- |
| `id` | Stable record id, same as `reviewId` | `eff248495b926832` |
| `reviewId` | Booking.com review id | `eff248495b926832` |
| `hotelUrl` | Normalised hotel page URL | `https://www.booking.com/hotel/gb/the-savoy.html` |
| `hotelId` | Numeric Booking.com property id | `58958` |
| `sourceUrl` | Hotel page the review was collected from | `https://www.booking.com/hotel/gb/the-savoy.html` |
| `score` | Guest's review score, 1 to 10 | `10` |
| `reviewDate` | Date the review was written (YYYY-MM-DD) | `2026-09-20` |
| `title` | Review headline | `Beautiful even for a night` |
| `positive` | What the guest liked | `Elegance` |
| `negative` | What the guest disliked | `Not a single thing` |
| `lang` | Language code of the review text | `en` |
| `guestName` | Guest display name, usually a first name | `Wahner` |
| `guestCountry` | Reviewer's country | `United States` |
| `travelerType` | Type of trip | `Couple` |
| `roomType` | Room the guest booked | `The Carnegie Suites` |
| `nights` | Number of nights stayed | `1` |
| `checkIn` | Check-in date (YYYY-MM-DD) | `2026-09-18` |
| `checkOut` | Check-out date (YYYY-MM-DD) | `2026-09-19` |
| `helpfulVotes` | "Helpful" votes the review received | `0` |
| `hasOwnerReply` | Whether the property replied | `true` |
| `ownerReply` | Text of the property's reply | `Dear Guest, ...` |
| `photoCount` | Photos attached to the review | `0` |
| `sentiment` | AI label: `positive`, `neutral`, `negative` or `mixed` | `positive` |
| `topics` | AI labels for the topics mentioned | `["staff", "room"]` |

A few notes on the values:

- `lang` can be a non-standard code such as `xu`, which Booking.com uses for reviews whose language it has not identified.
- `helpfulVotes` is `0` when nobody has voted.
- `sentiment` and `topics` are filled only when AI enrichment is on and the AI service answered for that review. Otherwise they are `null`, as in the example below.

### How to use Booking.com Reviews Scraper

1. Open a hotel on Booking.com in your browser and copy the address from the address bar. Any form works: locale domains such as `booking.co.uk`, language suffixes such as `.de.html` and query parameters such as `?checkin=...` are all normalised to the plain hotel URL.
2. Paste one or more hotel URLs into the **Hotel URLs** field.
3. Set **Max reviews per hotel**. Use a small number such as 20 for a first test, or `0` to collect every review the hotel has.
4. Optionally pick a sort order and add filters for language, traveler type, score band or oldest review date.
5. Click **Start**. When the run finishes, open the **Output** tab to browse the reviews, or export them as JSON, CSV, Excel or HTML.

### Input

| Field | Type | Description |
| --- | --- | --- |
| `startUrls` | array | Booking.com hotel pages as objects, e.g. `[{"url": "https://www.booking.com/hotel/gb/the-savoy.html"}]`. |
| `maxReviewsPerHotel` | integer | Reviews to collect per hotel. Default 50; `0` collects all available reviews. |
| `maxItems` | integer | Optional cap on the total number of reviews across all hotels. |
| `sortBy` | string | `MOST_RELEVANT`, `NEWEST_FIRST` (default), `OLDEST_FIRST`, `SCORE_DESC` or `SCORE_ASC`. |
| `languageFilter` | string | Only reviews written in this language, as a code such as `en`, `de` or `fr`. |
| `travelerTypeFilter` | string or list | One of `FAMILIES`, `COUPLES`, `GROUP_OF_FRIENDS`, `SOLO_TRAVELLERS`, `BUSINESS_TRAVELLERS`. Case-insensitive; short forms such as `couples` or `solo` also work. |
| `reviewScoreFilter` | string or list | One of `REVIEW_ADJ_SUPERB` (9+), `REVIEW_ADJ_GOOD` (7-9), `REVIEW_ADJ_AVERAGE_PASSABLE` (5-7), `REVIEW_ADJ_POOR` (3-5), `REVIEW_ADJ_VERY_POOR` (1-3). Short forms such as `superb` or `9+` also work. |
| `minDate` | string | Skip reviews written before this date (YYYY-MM-DD). With `NEWEST_FIRST`, paging stops at the first older review. |
| `includeReviewsWithoutText` | boolean | Also return score-only reviews that have no title or comments. Off by default. |
| `enrichment` | boolean | Add AI `sentiment` and `topics` labels (billed as an extra event). Off by default. |
| `proxyConfiguration` | object | Apify Proxy settings. The default Apify Proxy works for most runs. |

The run stops immediately with a clear error message if no valid Booking.com hotel URL is given, or if a number or date is invalid. A filter value the Actor does not recognise is ignored with a warning, so the run still returns reviews. If a hotel page no longer exists on Booking.com, it is skipped with a warning.

Example input:

```json
{
    "startUrls": [
        { "url": "https://www.booking.com/hotel/fr/le-bristol-paris.html" },
        { "url": "https://www.booking.com/hotel/us/the-plaza.html" }
    ],
    "maxReviewsPerHotel": 25,
    "sortBy": "NEWEST_FIRST",
    "languageFilter": "en",
    "travelerTypeFilter": "COUPLES",
    "minDate": "2025-01-01",
    "includeReviewsWithoutText": false,
    "enrichment": false
}
```

### Output

One record per review. This is a real record from a run on The Savoy with enrichment off, so `sentiment` and `topics` are `null`:

```json
{
    "id": "c035aefe035f7172",
    "reviewId": "c035aefe035f7172",
    "hotelUrl": "https://www.booking.com/hotel/gb/the-savoy.html",
    "hotelId": 280149,
    "sourceUrl": "https://www.booking.com/hotel/gb/the-savoy.html",
    "score": 10,
    "reviewDate": "2026-09-29",
    "title": "Quality, classic and elegant.",
    "positive": "Location was fantastic,  the history of the hotel and beautiful decor. The staff are lovely,  very kind and friendly. Loved the American Bar and the Spa. The river view is superb. Josh, our butler was fabulous 👌 \nBreakfast in our room overlooking the Thames was a special experience and the food exceptional.",
    "negative": "Going home!",
    "lang": "en",
    "guestName": "Kate",
    "guestCountry": "United Kingdom",
    "travelerType": "Solo traveller",
    "roomType": "Junior King Suite with River View",
    "nights": 3,
    "checkIn": "2026-09-25",
    "checkOut": "2026-09-28",
    "helpfulVotes": 0,
    "hasOwnerReply": true,
    "ownerReply": "Dear Kate, We very much appreciate your comments regarding your recent stay at The Savoy. It is always a pleasure to receive positive feedback and we wish to thank you in particular for your kind recognition of Josh who looked after you so exceptionally. Thank you again for sharing your experience and we hope to warmly welcome you again to The Savoy soon. If we can be of any assistance in the meantime, please let us know. With best regards, Debra Patterson, Quality Leader",
    "photoCount": 8,
    "sentiment": null,
    "topics": null
}
```

The **Output** tab has two views: **Overview**, with the most useful fields (hotel, date, score, title, liked and disliked text, guest, traveler type, room and sentiment), and **All fields**, with every field listed above.

### How much does it cost to scrape Booking.com reviews?

The Actor uses pay-per-event pricing, so the cost depends on how many reviews you collect rather than on compute time. Each review returned is charged as one result. AI enrichment is off by default; if you turn it on, each enriched review is billed as an additional event. See the **Pricing** tab on this page for current prices. You can cap spending with `maxReviewsPerHotel`, `maxItems` or the maximum cost per run setting in Apify Console.

### Use with the API

You can start the Actor and read its results from any language through the Apify API. Set the `APIFY_TOKEN` environment variable to your token from the Apify Console integrations settings.

**Python** (with the `apify-client` package):

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("axiomworks/booking-reviews-scraper").call(run_input={
    "startUrls": [{"url": "https://www.booking.com/hotel/gb/the-savoy.html"}],
    "maxReviewsPerHotel": 20,
    "sortBy": "NEWEST_FIRST",
})
for review in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(review["reviewDate"], review["score"], review["title"])
```

**JavaScript** (with the `apify-client` package):

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('axiomworks/booking-reviews-scraper').call({
    startUrls: [{ url: 'https://www.booking.com/hotel/gb/the-savoy.html' }],
    maxReviewsPerHotel: 20,
    sortBy: 'NEWEST_FIRST',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, 'reviews');
```

**cURL** (runs the Actor and returns the dataset items in one call):

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~booking-reviews-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":[{"url":"https://www.booking.com/hotel/gb/the-savoy.html"}],"maxReviewsPerHotel":20}'
```

The Actor also works with the standard Apify integrations: webhooks, schedules, and connections to Google Sheets, Slack, Zapier, Make and other tools. A schedule with `sortBy` set to `NEWEST_FIRST` and a `minDate` is a simple way to collect only recent reviews on a regular basis.

### Use with AI agents (MCP)

You can call Booking.com Reviews Scraper from AI assistants such as Claude or Cursor through the Apify MCP server. Add this server to your MCP client configuration:

```json
{
    "mcpServers": {
        "apify": {
            "url": "https://mcp.apify.com?tools=axiomworks/booking-reviews-scraper"
        }
    }
}
```

The server asks you to sign in with your Apify account the first time. Example prompts:

- "Get the 30 newest Booking.com reviews for https://www.booking.com/hotel/gb/the-savoy.html and summarise the main complaints."
- "Compare the last 50 English reviews of Le Bristol Paris and The Plaza New York on staff and cleanliness."
- "List Booking.com reviews of this hotel with a score below 5 written since January 2025, and say which ones got a reply from the hotel."

The agent reads the input schema to learn which fields it can set, so it can apply sorting and filters on its own.

### FAQ

**Which URLs can I use?**
Hotel (property) pages in the form `https://www.booking.com/hotel/{country}/{name}.html`. Links from other Booking.com domains, with a language suffix or with booking parameters are accepted and normalised. Search result pages and city pages are not supported; open the hotel and copy its address instead.

**What if a hotel URL no longer works?**
Booking.com sometimes renames property pages. When a URL shows "Page not found", the Actor searches Booking.com for the words in the URL and continues with a property in the same country whose name matches them. The reviews then carry that property's `hotelUrl`. If no property matches, the hotel is skipped and the log names it.

**How many reviews can I get per hotel?**
As many as Booking.com shows for the hotel. Set `maxReviewsPerHotel` to `0` to collect them all.

**Why are some fields empty?**
Guests don't always write a title or both the "liked" and "disliked" parts, and some reviews are anonymous or have no stay details. Those fields are `null` rather than guessed.

**Why do I get fewer reviews than the hotel's review count?**
Many Booking.com reviews are only a score, with no written text. The Actor skips those by default, so the reviews you get are the ones with comments. Turn on **Include score-only reviews** (`includeReviewsWithoutText`) to get them as well; their `title`, `positive` and `negative` fields are then `null`.

**Are reviews translated?**
No. Texts are returned in the language the guest wrote them in, and `lang` tells you which language that is. Use `languageFilter` to collect only one language.

**What does the AI enrichment do?**
It sends the review title and texts to a third-party AI processor, which labels the overall sentiment and the topics mentioned (cleanliness, staff, location, food, room, value, noise, facilities). The same processor is used, rarely, to recover a score or date if the normal parsing leaves it empty. If the AI service is unavailable, the run continues without the labels and they are not charged.

**Do I need a Booking.com account?**
No. The Actor only reads reviews that anyone can see without logging in.

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

Guest reviews on Booking.com are publicly visible without an account, and this Actor collects only that public content. Reviews still contain personal data such as guest first names and countries, so data protection laws like the GDPR may apply to how you store and use the results. Check Booking.com's terms and your local laws for your use case, and ask a lawyer if you are unsure. Collect only what you need, and don't use the data to identify or contact individual guests.

### Feedback

Found a bug, a hotel that doesn't work, or a field you would like added? Open an issue on the **Issues** tab of this Actor's page and include the hotel URL and your run ID. We read every report and use it to improve the Actor.

# Actor input Schema

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

Booking.com hotel page URLs as objects, e.g. \[{"url": "https://www.booking.com/hotel/gb/the-savoy.html"}]. Locale domains, language suffixes and query parameters are accepted. Hotel names are not accepted.

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

Maximum number of reviews to collect for each hotel, e.g. 50. Use 0 to collect every available review. Default 50.

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

Optional cap on the total number of reviews across all hotels, e.g. 100. Leave empty for no total cap.

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

Order in which reviews are collected, e.g. 'NEWEST\_FIRST'. Defaults to NEWEST\_FIRST.

## `languageFilter` (type: `string`):

Only return reviews written in this language, as a code such as 'en', 'de' or 'fr'. Leave empty for all languages.

## `travelerTypeFilter` (type: `array,string,integer`):

Only return reviews from one traveler type: 'FAMILIES', 'COUPLES', 'GROUP\_OF\_FRIENDS', 'SOLO\_TRAVELLERS' or 'BUSINESS\_TRAVELLERS' (case-insensitive; a string or one-item list, short forms also work).

## `reviewScoreFilter` (type: `array,string,integer`):

Only return reviews in one score band: 'REVIEW\_ADJ\_SUPERB' (9+), 'REVIEW\_ADJ\_GOOD' (7-9), 'REVIEW\_ADJ\_AVERAGE\_PASSABLE' (5-7), 'REVIEW\_ADJ\_POOR' (3-5) or 'REVIEW\_ADJ\_VERY\_POOR' (1-3) (case-insensitive; a string or one-item list, short forms also work).

## `minDate` (type: `string`):

Skip reviews written before this date, in YYYY-MM-DD format, e.g. '2025-01-01'. With NEWEST\_FIRST sorting, paging stops at the first older review.

## `includeReviewsWithoutText` (type: `boolean`):

Also return reviews that have a score but no written title or comments. Off by default, so every returned review has text.

## `enrichment` (type: `boolean`):

Add sentiment and topic labels to each review using a third-party AI processor. Off by default. Each enriched review is billed as an extra event on top of the per-review charge.

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

Proxy used to reach Booking.com. Apify Proxy (datacenter) is used by default, with automatic fallback to residential IPs if a page is blocked.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.booking.com/hotel/gb/the-savoy.html"
    }
  ],
  "maxReviewsPerHotel": 20,
  "sortBy": "NEWEST_FIRST",
  "includeReviewsWithoutText": false,
  "enrichment": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `overview` (type: `string`):

No description

# 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-savoy.html"
        }
    ],
    "maxReviewsPerHotel": 20,
    "sortBy": "NEWEST_FIRST",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/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-savoy.html" }],
    "maxReviewsPerHotel": 20,
    "sortBy": "NEWEST_FIRST",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/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": [
    {
      "url": "https://www.booking.com/hotel/gb/the-savoy.html"
    }
  ],
  "maxReviewsPerHotel": 20,
  "sortBy": "NEWEST_FIRST",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call axiomworks/booking-reviews-scraper --silent --output-dataset

```

## MCP server setup

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