Booking.com Reviews Scraper — Hotel Guest Reviews & Ratings avatar

Booking.com Reviews Scraper — Hotel Guest Reviews & Ratings

Pricing

$5.00 / 1,000 review rows

Go to Apify Store
Booking.com Reviews Scraper — Hotel Guest Reviews & Ratings

Booking.com Reviews Scraper — Hotel Guest Reviews & Ratings

Every guest review of any Booking.com hotel: 1-10 score, title, what guests liked and disliked, language, stay dates, room, traveller type, reviewer country, photos and the property's reply. Give Booking.com URLs, hotel names or ids. No browser, no login. Pay per review.

Pricing

$5.00 / 1,000 review rows

Rating

0.0

(0)

Developer

Tedj MEABIOU

Tedj MEABIOU

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

9 hours ago

Last modified

Share

A booking.com reviews scraper — a hotel review scraper for booking.com hotel reviews — that returns every guest review a property has, as structured rows: booking.com ratings on the 1–10 scale and out of five, the title, what the guest liked and what they disliked, the language it was written in, posting and stay dates, room, traveller type, reviewer name and country, guest photos and the property's public reply.

Give it Booking.com hotel URLs, hotel names or Booking's numeric ids. No login, no booking.com api key, no browser. It never loads a Booking.com page — it calls the same review endpoint Booking's own review list uses — so runs are fast, cheap and steady. It bills per review row, and four controls cut what you pay for before you are billed.

Last verified working: 2026-08-29.

What does the Booking.com reviews scraper do?

You give it properties. It gives you their booking.com hotel reviews as rows you can sort, filter and export.

  • review rowsreview_id, rating (1–10, Booking's scale), rating_5 (the same score out of five), title, positives (what the guest liked), negatives (what they disliked), text (both joined into one comment), language, review_date, check_in, check_out, nights, room_type, room_id, traveler_type and traveler_type_code, stay_status, reviewer_name, reviewer_country, reviewer_country_code, anonymous, helpful_votes, photos, approved, response (the property's reply), plus hotel_id, hotel_name, url, locale and fetched_at.
  • hotel rows — free context per property: hotel_id, hotel_name, city, region, country, country_code, latitude, longitude, Booking's seven category scores (score_staff, score_facilities, score_cleanliness, score_comfort, score_value, score_location, score_wifi), review_count, the languages (code and count), traveler_types (type and count) and seasons (bucket and count) its reviews come in, reviews_fetched, url and locale.
  • status rows — free: per input target, the hotel_id and hotel_name, a status of ok, no_reviews or error, how many reviews were delivered, how many were filtered, how many pages were read, Booking's total, a duplicates flag, the error if any, and fetched_at.

Booking.com guest reviews come back in the language they were written in, tagged with the language. One Lisbon boutique hotel returned 24 languages across 892 reviews.

Booking.com reviews by hotel, by URL, by name or by id

  • startUrls — property pages such as https://www.booking.com/hotel/pt/memmo-alfama.html; any language variant (.en-gb.html, .de.html) and any query string is fine. Booking's URLs carry no numeric id, so the slug is resolved through Booking's own autocomplete, held to the country in the URL, and the resolved name comes back in every row so you can check the match.
  • hotelNames — names as you would type them into Booking's search box: "Memmo Alfama Lisbon". Add the city for chains. The first property Booking's autocomplete returns is used.
  • hotelIds — Booking's numeric id, e.g. 536251, which is what an earlier run's hotel_id gives you. This is the booking.com reviews by hotel id path and the fastest one: no lookup at all. Ids carry no name, so hotel_name stays empty unless you also give a URL or name.

A URL, its name and its id count as the same property and are harvested once, so mixing inputs never double-bills.

Booking.com negative reviews without paying for the happy ones

Four controls run before billing, and together they are the reason a complaints feed is affordable:

  • maxRating keeps only reviews at or below a score on Booking's 1–10 scale. It also changes how the property is read: lowest score first, stopping at the first review above the threshold. A property with 892 reviews and 24 of them at 6 or below costs one page, not thirty-six.
  • requireText drops score-only reviews. Booking lets guests leave a score with no words — about four in ten do — and those are worthless for reading and free with this switch on.
  • languages, travelerType and keyword are applied by Booking itself, so the reviews you skip are never even fetched.

Filtered reviews are never charged. Neither are hotel rows, status rows, properties with no reviews, or lookups that fail.

Hotel review data for revenue, ops and analysts

  • Revenue and reputation managers run the complaints feed daily across a comp set and read only what changed: maxRating: 6, reviewsSort: "most_recent", maxReviewsPerHotel: 50.
  • Operations search by topic — keyword: "breakfast", keyword: "noise" — and see which room types the complaints cluster in (room_type is on every row).
  • Analysts pull the full corpus for sentiment work: maxReviewsPerHotel: 0, requireText: true, one language at a time so the model gets clean input.
  • Owners and hosts read response to see which complaints the property answered and which it left hanging.

Every row carries traveler_type, reviewer_country, check_in and nights, so "what do business travellers from Germany say in winter" is a filter, not a project.

Input

fieldwhat it does
startUrlsBooking.com property URLs, resolved through Booking's autocomplete.
hotelNamesProperty names as typed into Booking's search; the first hotel hit is used.
hotelIdsBooking's numeric property ids. No lookup; no name.
maxReviewsPerHotel0 = every review (25 per page); N = the first N in the chosen order. The main cost control. Default 200.
reviewsSortmost_recent (default), oldest, highest_rated, lowest_rated or most_relevant.
languagesLanguage codes to keep (en, de, fr, es, it, pt, nl, ru, ja, zh, ko, tr …), filtered by Booking. Empty = all.
travelerTypeall (default), families, couples, friends, solo or business, filtered by Booking.
keywordOnly reviews mentioning a word or phrase, searched by Booking. Empty = all.
maxRating0 = all; 1–10 = only reviews at or below it, read lowest first. Filters before billing.
requireTextOnly reviews where the guest wrote something. Filters before billing.
localeSite locale for Booking's labels (traveller type, country names), e.g. en-US, de-DE. Reviews stay in their original language.
includeHotelRowEmit the free hotel context row (default on).
sessionsParallel proxy sessions (default 4).
perIpRequests per second per session (default 1).
proxyConfigurationApify Proxy; the default datacenter group is enough.

Example: a scheduled complaints feed

{
"startUrls": ["https://www.booking.com/hotel/pt/memmo-alfama.html", "https://www.booking.com/hotel/pt/the-lumiares.en-gb.html"],
"maxReviewsPerHotel": 50,
"reviewsSort": "most_recent",
"maxRating": 6,
"requireText": true
}

Run it every morning. Each run reads the properties lowest score first, stops at the first review above 6, and bills only the reviews it delivers.

Example: the full English corpus for a competitor set

{
"hotelNames": ["Memmo Alfama Lisbon", "The Lumiares Lisbon", "Hotel Valverde Lisboa"],
"maxReviewsPerHotel": 0,
"languages": ["en"],
"requireText": true
}

Example: what families say about breakfast, by id

{
"hotelIds": ["536251"],
"maxReviewsPerHotel": 100,
"travelerType": "families",
"keyword": "breakfast",
"locale": "en-GB"
}

Output

One review row, exactly as delivered:

{
"type": "review",
"url": "https://www.booking.com/hotel/pt/memmo-alfama.html",
"locale": "en-US",
"review_id": "c90f61915f999a43",
"rating": 10.0,
"rating_5": 5.0,
"title": "Best place to stay in Lisbon!",
"positives": "Great location and amazing terrace.",
"negatives": null,
"text": "Great location and amazing terrace.",
"language": "en",
"review_date": "2026-08-28",
"check_in": "2026-08-24",
"check_out": "2026-08-27",
"nights": 3,
"room_type": "Premium Double or Twin Room",
"room_id": "53625108",
"traveler_type": "Couple",
"traveler_type_code": "COUPLES",
"stay_status": "stayed",
"reviewer_name": "Jean",
"reviewer_country": "Canada",
"reviewer_country_code": "ca",
"anonymous": false,
"helpful_votes": 0,
"photos": null,
"approved": true,
"response": null,
"hotel_id": "536251",
"hotel_name": "Memmo Alfama - Design Hotels",
"fetched_at": "2026-08-29T10:12:04+00:00"
}

The free hotel row for the same property carries review_count: 892, score_staff: 9.57, score_location: 9.6, score_value: 8.8, score_wifi: 8.59, a languages list such as [{"code": "en", "count": 490}, {"code": "de", "count": 139}, …] and traveler_types such as [{"type": "COUPLES", "count": 590}, …].

The dataset has five views — Overview, Reviews, Complaints (negatives first), Hotels and Status — and exports to CSV, Excel, JSON or XML from the run page or the API.

How much does it cost?

You pay per delivered review row. Everything else is free: hotel rows, status rows, reviews dropped by maxRating or requireText, properties with no reviews, and lookups that fail. The number of reviews you asked for is the number you pay for, capped by maxReviewsPerHotel and by whatever spending limit you set on the run. A 50-review complaints feed across ten properties is at most 500 review rows a day and usually far fewer, because most properties have few new complaints.

Booking.com reviews scraper in Python, JavaScript, curl, n8n, Make or an AI agent

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("kestrel/booking-reviews-scraper").call(run_input={
"startUrls": ["https://www.booking.com/hotel/pt/memmo-alfama.html"],
"maxReviewsPerHotel": 100,
"reviewsSort": "most_recent",
})
reviews = [r for r in client.dataset(run["defaultDatasetId"]).iterate_items() if r["type"] == "review"]
for r in reviews[:5]:
print(r["rating"], r["traveler_type"], r["title"], "|", r["negatives"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('kestrel/booking-reviews-scraper').call({
hotelNames: ['Memmo Alfama Lisbon'], maxReviewsPerHotel: 0, maxRating: 6, requireText: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const complaints = items.filter(r => r.type === 'review');
console.log(complaints.length, 'complaints;', complaints.filter(r => r.response).length, 'answered by the hotel');

curl:

curl -X POST "https://api.apify.com/v2/acts/kestrel~booking-reviews-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"hotelIds": ["536251"], "maxReviewsPerHotel": 25, "languages": ["en"]}'

n8n: an HTTP Request node to the URL above (Header Auth with your token) on a Schedule trigger, then a Code node that keeps type === 'review' and drops the review_id values you have already seen, then Slack, Google Sheets or email. Make: the Apify "Run an Actor" module with the same JSON. AI agents: the actor is listed on Apify's MCP server, so a Claude, Cursor or LangChain agent can call it by name — the input and output schemas above are what the agent reads.

The actor reads publicly visible guest reviews through the same request Booking's own page makes, with no login and no personal accounts. Reviews are the guests' public words about a business; names appear as Booking shows them (first name or "Anonymous"). Whether you may use the data for your purpose depends on your jurisdiction, on Booking.com's terms and on data-protection law (GDPR in the EU treats reviewer names as personal data) — read them and take advice before scraping at scale or republishing. Use the data for analysis and monitoring; do not repost reviews as your own content.

Limits and honest notes

  • Score-only reviews are real. Booking lets guests rate without writing; in a recent sample 11 of 25 reviews had no words. requireText drops them before billing.
  • Ids carry no name. An id resolves to reviews and scores but not to a name — Booking's lookup runs from name to id, not back. Give a URL or a name if you need hotel_name filled.
  • Unknown ids look like empty properties. Booking answers a wrong id with zero reviews, which is reported as no_reviews (free). A URL or a name that Booking cannot find is reported as error (also free).
  • Filters are Booking's. Language codes must be the ones Booking uses (the hotel row lists them with counts); a code Booking rejects fails that property with a clear message rather than silently harvesting everything.
  • No room-level or topic filter. Booking's endpoint accepts language, traveller type and keyword; score and topic filters are applied by this actor after fetching (maxRating reads ascending so it rarely over-fetches).
  • Pace. Booking answered ten calls a second from one IP in testing; the default of one call per second per session is conservative. Each call returns 25 reviews.

FAQ

Does it need a Booking.com API key or login?

No. There is no public Booking.com reviews API for reading reviews; the actor uses the request Booking's own review list makes, which needs no key, no cookies and no browser.

Can I download Booking.com reviews as CSV or Excel?

Yes. Every run writes an Apify dataset; open the Reviews or Complaints view and export booking.com reviews csv, Excel, JSON or XML, or fetch the same through the API with ?format=csv.

How do I get only Booking.com negative reviews?

Set maxRating to 6 (Booking's own wording: 5 is "Poor", 7 is "Good"). The property is read lowest score first and paging stops at the threshold, so you pay only for the complaints. Add requireText: true to skip score-only ratings.

Do I need the hotel id, or can I use the URL?

Either — or the name. URLs and names are resolved through Booking's autocomplete and the matched name comes back in every row; ids skip the lookup. Once you have a hotel_id from a run, use it for the fastest repeat runs.

How many reviews can one hotel return?

All of them. Booking pages reviews 25 at a time and the actor keeps going until the property is exhausted or maxReviewsPerHotel is reached. A large city hotel with 15,000 reviews is 600 calls.

Are reviews translated, and which languages come back?

Reviews come back as written, with language set — multi language hotel reviews from one property, or booking.com reviews by language when you set languages. The hotel row lists every language the property's reviews come in, with counts, so you can pick what to fetch with languages. Booking's labels (traveller type, country names) follow locale.

Does it include the hotel's replies?

Yes — response carries the property's public reply when there is one.

What is traveler_type_code?

Booking's own guest category on the booking behind the review: COUPLES, FAMILIES, GROUP_OF_FRIENDS, SOLO_TRAVELLERS or BUSINESS_TRAVELLERS. traveler_type is the same thing in the site language.

Can I scrape Booking.com reviews without an API?

That is what this is — booking.com reviews without api keys: scrape booking.com reviews by URL, name or id, no key, no browser, pay per review.

Can I use it for hotel sentiment analysis?

Yes. positives and negatives are already split, text joins them for a single column, every row is tagged with language, rating and traveler_type, and requireText keeps the corpus clean.

What does bulk work cost?

Reviews only. A bulk hotel reviews pull of one hundred properties at 200 reviews each is at most 20,000 review rows; with requireText on it is typically 12,000, because score-only reviews are free.

Review monitoring across a portfolio

Put every property you manage into startUrls, set reviewsSort: "most_recent" and maxReviewsPerHotel: 30, and schedule the run daily. Keep the review_id values you have seen; anything new is a new review. Route rows with rating at or below 6 to the people who answer complaints, and rows with response: null older than three days to the people who should have.

Guest feedback data that keeps its structure

Because every row carries room_type, traveler_type, reviewer_country, check_in and nights, a hotel reputation monitoring table falls out of a pivot: score by room type, by season, by market. The hotel row's category scores (score_cleanliness, score_value …) are Booking's own aggregates, refreshed every run — a hotel review data feed you can chart without computing anything.

What this does not do

It does not scrape Booking.com prices, availability or search results, and it does not read Booking.com's HTML pages at all. For booking.com competitor reviews it is exactly right; for rates, use the hotel price actors below.

Choosing between sort orders

most_recent for schedules, lowest_rated (or maxRating) for complaints, highest_rated for marketing copy, most_relevant for Booking's own pick, oldest for a full history pull in chronological order. Sort affects which reviews you get when maxReviewsPerHotel caps the run; with 0 it only affects order.

Booking.com reviews are one voice of the guest. These read the others, and they share the same row shape, the same pay-per-delivered-row billing and the same scheduling story:

All of them bill per delivered row, never charge for rows a filter or a spending limit removed, and write an Apify dataset you can export to CSV, Excel or JSON.