Booking.com Review Scraper avatar

Booking.com Review Scraper

Pricing

from $1.50 / 1,000 results

Go to Apify Store
Booking.com Review Scraper

Booking.com Review Scraper

Which room type gets the complaints? What do guests really say about your breakfast? Scrape Booking.com reviews at room level — score, liked/disliked texts, stay details, traveler type, management replies — with score-band filters and topic search. Deduplicated, LLM-ready.

Pricing

from $1.50 / 1,000 results

Rating

0.0

(0)

Developer

NoraView Intelligence

NoraView Intelligence

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Categories

Share

💬 Booking.com Review Scraper

Room-level guest review corpus for any Booking.com hotel — up to a few hundred of the newest reviews per hotel, one clean record per review. Built as a data foundation for revenue managers and LLM pipelines: sampling, summarization and sentiment analysis happen downstream; this actor's job is to return a complete, deduplicated, structured corpus — fast and cheap.

Instead of rendering heavy hotel pages, this actor queries the same internal review endpoint Booking's own review panel uses. One page load per hotel, then light JSON calls (25 reviews per call) — a fraction of the proxy cost of page-scraping actors.

Why this scraper?

  • 🛏️ Room-level granularity — every review carries the room stayed in, plus Booking's booking_room_id, so you can join reviews directly against room-level price data (e.g. the sibling Booking.com Room-Level Price Tracker)
  • 🎯 Server-side score filter — pull only the bands you need (Superb 9+ / Good 7-9 / Passable 5-7 / Poor 3-5 / Very poor 1-3). Booking does the filtering, you don't pay for pages you'll throw away
  • 🔍 Topic search — same as Booking's "Search guest reviews by topic" bar: breakfast, noise, wifi, pool... Combines with the score filter
  • 🧳 Full stay context — nights, stay month, traveler type (solo/couple/family/group/business), reviewer country, review language
  • 💬 Management responses — property replies included
  • 🧹 Corpus-ready — stable Booking review IDs, deduplicated, newest-first, score-only reviews kept and flagged (has_text) so they count toward evidence totals without polluting your LLM prompts

📥 Input

FieldTypeRequiredDefaultDescription
hotelUrlsarrayBooking.com hotel URLs to scrape reviews for
maxReviewsPerHotelinteger200Newest reviews to collect per hotel (~8 pages at 200)
cutoffMonthsinteger24Stop paginating once reviews are older than this — beyond that, a review no longer describes the hotel as it is today
sortstringNewest firstNewest first, Oldest first, Highest/Lowest score first, Most relevant
reviewScoreFilterarrayAllScore bands to include (server-side). Multiple bands = one pass per band, merged and deduplicated
searchTextstringTopic search (Booking semantic search, like the site's own search bar)
useApifyProxybooleantrueApify residential proxy — Booking blocks datacenter IPs
proxyCountriesarray["FR"]Proxy source market. Reviews are geo-independent — one country is normal
proxyUrlstringExternal proxy (only if Apify Proxy is off)
delayBetweenRequestsinteger2Seconds between review page fetches

Example input

{
"hotelUrls": ["https://www.booking.com/hotel/th/karon-homes.html"],
"maxReviewsPerHotel": 200,
"cutoffMonths": 24,
"sort": "f_recent_desc",
"reviewScoreFilter": ["all"],
"searchText": "",
"useApifyProxy": true,
"proxyCountries": ["FR"],
"delayBetweenRequests": 2
}

Example: pain-point mining

Only negative reviews mentioning the air conditioning, last 12 months:

{
"hotelUrls": ["https://www.booking.com/hotel/ma/savoy-le-grand.html"],
"maxReviewsPerHotel": 300,
"cutoffMonths": 12,
"reviewScoreFilter": ["passable", "poor", "very_poor"],
"searchText": "air conditioning"
}

📤 Output

Review records (record_type: "review") — one per review

FieldTypeDescription
review_idstringBooking's own stable review ID — reliable dedup across runs
booking_hotel_idstringBooking's internal hotel ID
hotel_url / hotel_namestringSource hotel
review_datestringYYYY-MM-DD (UTC)
review_scorenumber1–10
titlestringReview title (often null — Booking rarely returns titles anymore)
positive_textstring"Liked" text, in the reviewer's language
negative_textstring"Disliked" text
has_textbooleanfalse = score-only review: kept for evidence totals, skip it in LLM prompts
languagestringReview language code from Booking (en, ru, ar...; xu = undetermined)
booking_room_idintegerBooking's room ID — join key against room-level price data
room_namestringRaw room name ("Stayed in: …")
room_name_cleanstringBed-type suffix stripped
nightsintegerLength of stay
stay_monthstringYYYY-MM — month of the stay (not the review date)
traveler_typestringsolo, couple, family, group or business
traveler_type_rawstringBooking's raw enum (SOLO_TRAVELLERS, COUPLES...)
reviewer_countrystringISO-2 country code (BR, DE...)
mgmt_response_textstringProperty's reply, if any
mgmt_response_dateAlways null — Booking no longer exposes the reply date via this endpoint
helpful_votes_countinteger"Helpful" votes (null on score-only reviews)
scrape_timestampstringUTC timestamp of the run

Hotel summary records (record_type: "hotel_summary") — one per hotel

Run metadata: reviews_count_on_booking, reviews_scraped, pages_fetched, duplicates_dropped, sort, cutoff_months, score_filter, search_text, per_band breakdown, and stop_reason (max_reviews, cutoff, last_page…).


🔍 How it works

  1. Bootstrap — loads the hotel page once to resolve Booking's internal hotel ID and destination ID
  2. Fetch — calls Booking's internal review endpoint (the one powering the on-site review panel): 25 reviews per call, newest first
  3. Stop conditionsmaxReviewsPerHotel reached, no more reviews, or the oldest review on the page passes cutoffMonths (reviews arrive newest-first, so everything beyond that point is out of range too)

Filters are applied server-side, exactly like Booking's own UI: the score filter maps to Booking's score bands, and searchText uses Booking's semantic topic search — not a literal substring match, so it catches related wording (breakfast also matches "morning meal"). Match highlights are stripped from the text automatically.

Anti-block infrastructure

Rotating user-agents/viewports/timezones, a fresh browser context and proxy IP per hotel, resource blocking (images/fonts/tracking), cookie-consent and WAF challenge handling, exponential backoff on retry. Failed hotels produce an error record — one bad IP never sinks the run.


🚀 Use cases

  • LLM sentiment pipelines — feed has_text: true reviews into summarization; keep score-only reviews in the evidence counts
  • Room-level complaint analysis — join on booking_room_id / room_name_clean against the price tracker to find which room types get complaints, and whether they're priced accordingly
  • Competitor benchmarking — track review velocity, score trends and topic mix across a comp set
  • Pain-point mining — score filter + topic search to isolate exactly the reviews that cost you stars

⚠️ Notes & limitations

  • mgmt_response_date is always null — Booking exposes the reply text only
  • Booking's topic search is semantic (same behavior as booking.com's own search bar); match counts are approximate by design
  • Review title is often null — Booking rarely returns titles anymore

📝 Changelog

v1.1.0

  • Server-side score-band filter (Superb/Good/Passable/Poor/Very poor, multi-band merge + dedup)
  • Server-side topic search (searchText), combinable with the score filter
  • <mark> highlight stripping, search_text in summary records

v1.0.0

  • Initial release — review corpus, pagination, 24-month cutoff, dedup by Booking review ID, proxy + retry infrastructure