Booking.com Reviews Scraper: Hotel Guest Reviews
Pricing
from $0.80 / 1,000 reviews
Booking.com Reviews Scraper: Hotel Guest Reviews
Get the guest reviews of any Booking.com hotel: score, title, liked and disliked text, reviewer country and type of trip, room, dates of stay and the hotel reply. Sort and filter by score, language, guest type or words. Plain HTTP, no browser. Not affiliated with Booking.com.
Pricing
from $0.80 / 1,000 reviews
Rating
0.0
(0)
Developer
Aleksandr Kobtsev
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Share
Get the guest reviews of any Booking.com hotel: the score, the title, what guests liked and disliked, the reviewer's country and kind of trip, the room, the dates of the stay and the hotel's reply. Give it hotel links, hotel numbers, or just a city, and it reads the reviews of the hotels there. One dataset row per review.
There is no login, no Booking.com account, no partner API and no browser. The Actor reads the same review list Booking.com's own hotel page loads, over plain HTTP, which is why it runs in 512 MB, reads about eighty reviews a second and can be priced low. Run it once, put it on a schedule, or call it from the API, and forward the result to Google Sheets, Slack, Make, Zapier or an MCP client.
Who is this Booking.com reviews scraper for?
| You are | What you run | What you get |
|---|---|---|
| A hotel owner or reputation manager | your hotel and four competitors, the last 30 days | what guests say about you and about them, by score, language and kind of trip |
| An analyst or researcher | the most reviewed hotels of a city, a few thousand reviews | review text with scores and metadata, ready for sentiment or topic work |
| A travel agency or destination marketer | a destination, the top hotels | which hotels guests praise and what they complain about |
| Building a product or an AI workflow | hotels through the API, new reviews every day | clean rows to forward to a database, a model or an alert |
What makes this different from other Booking.com review scrapers?
- Three ways in. Paste hotel links, give Booking.com's own hotel numbers, or name a place and let the Actor read the reviews of the hotels Booking.com lists there. No link list is needed for a city.
- Booking.com does the filtering. Sort order, score band, review language, kind of trip and a word search are applied by Booking.com's server, so you read and pay only for the reviews you asked for. A search for the 32 poor reviews of a hotel with 1,200 reviews reads two pages, not fifty.
- Daily runs are cheap. With "newest first" and a start date the Actor stops at the first review that is older, so a daily run for yesterday's reviews costs one request per hotel and bills only what is new.
- Complete and without repeats. Measured on 11 October 2026 on the Apify platform: a hotel with 30,730 reviews was read to its last review, 30,730 rows, all different, in 6 minutes 29 seconds, with a peak of 153 MB of memory.
- It says what it could not do. A hotel link that cannot be matched to a hotel is listed with the reason, not guessed and not billed. A hotel that stopped answering is listed with the number of reviews delivered before that.
What data does it return?
One row per review.
| Field | What it is |
|---|---|
| id | Booking.com's own id of the review. Stable between runs, so it is the key to de-duplicate a schedule on. |
| hotelId, propertyId, hotelName, hotelUrl | The hotel. hotelId is the country and page name from the hotel's link, propertyId is Booking.com's number for it, the same number the Booking.com Scraper Actor returns as hotelId. |
| reviewPage | The page of the review list (25 reviews a page) the review was read from, counted from 1. |
| userName, userLocation, userCountryCode | The reviewer's display name, country and country code. userName is null for an anonymous reviewer. |
| guestType, customerType | The kind of trip as Booking.com words it ("Family") and as its code (FAMILIES, COUPLES, GROUP_OF_FRIENDS, SOLO_TRAVELLERS). |
| roomInfo, roomId | The room the guest stayed in. |
| stayDate, checkInDate, checkOutDate, stayLength, numNights, stayStatus | When they stayed: the month, the dates, the length, and "stayed". |
| reviewDate, reviewedAt | When the review was written, as "October 9, 2026" and as ISO-8601 UTC. |
| reviewTitle | The title of the review, or null when the guest wrote none. |
| rating | The score, 1 to 10. |
| reviewTextParts | The text: Liked and Disliked, each null when empty. |
| reviewLanguage | The language of the text as a code (en, de, ru...), or null when Booking.com could not tell. |
| helpfulVotes | How many guests found the review helpful. |
| propertyReply | The hotel's reply, { text, date }, or null. |
| photoUrls | Links to the photos the guest attached, largest size. |
| customData | What you attached to the hotel link as userData. With a place, customData.destination is the place the hotel came from. |
| scrapedAt | When it was collected, ISO-8601 UTC. |
An example row. The reviewer's name and the text of the hotel's reply are replaced; the rest is as Booking.com returned it.
{"id": "7b598841bbd9be60","hotelId": "ge/radisson-blu-batumi","propertyId": 320991,"hotelName": "Radisson Blu Hotel Batumi","hotelUrl": "https://www.booking.com/hotel/ge/radisson-blu-batumi.html","reviewPage": 1,"userName": "Anna","userLocation": "United Kingdom","userCountryCode": "gb","guestType": "Family","customerType": "FAMILIES","roomInfo": "SPA Suite with Sea View","roomId": 32099106,"stayDate": "October 2026","checkInDate": "2026-10-04","checkOutDate": "2026-10-07","stayLength": "3 nights","numNights": 3,"stayStatus": "stayed","reviewDate": "October 9, 2026","reviewedAt": "2026-10-09T18:20:26.000Z","reviewTitle": "Great hotel for exploring Batumi.","rating": 10,"reviewTextParts": {"Liked": "We had great room. SPA is very relaxing. Proximity to the old town offers many possibilities for dining.","Disliked": "Nothing"},"reviewLanguage": "en","helpfulVotes": 0,"propertyReply": {"text": "Dear Anna, thank you for staying with us and for the kind words. We hope to see you again.","date": null},"photoUrls": [],"customData": {},"scrapedAt": "2026-10-11T12:00:00.000Z"}
A second record, HOTELS in the run's key-value store, has one entry per hotel: how many reviews Booking.com lists for it, how many were delivered, why the read stopped, Booking.com's score breakdown (cleanliness, comfort, facilities, location, staff, value for money) and the number of reviews per language. FAILED_HOTELS lists what could not be read and why.
How do I scrape Booking.com reviews?
- Add what you want to read: hotel links in Hotel links, Booking.com hotel numbers in Hotel numbers, or places in Places. They can be mixed.
- Choose how many reviews per hotel (the default is 100) and the order.
- Add filters if you want a slice: a start date, score bands, languages, kinds of trip, a word.
- Run it. Download the dataset as JSON, CSV or Excel, or read it through the API.
| Field | Default | What it does |
|---|---|---|
startUrls | none | Links of Booking.com hotel pages, with any language and any parameters. Add userData to a link to get it back as customData. |
hotelIds | none | Booking.com's numbers of hotels, such as 320991. Exact and needs no lookup. |
destinations | none | Places: a city, region, district, landmark, airport or country by name, or a pasted Booking.com search results link. Up to 50. |
maxHotelsPerDestination | 10 | How many hotels to read for each place, 1 to 1,000. Hotels with no reviews are left out and do not count. |
hotelSort | popularity | Which hotels of a place: Booking.com's ranking (popularity), the hotels with the most reviews (most_reviewed) or its best-score order (top_rated). |
maxReviewsPerHotel | 100 | The most reviews per hotel, 1 to 1,000,000. With the filters below it counts the reviews that pass them. |
sortReviewsBy | f_relevance | Booking.com's own orders: f_relevance, f_recent_desc (newest first), f_recent_asc, f_score_desc, f_score_asc. |
cutoffDate | none | Only reviews written on or after this day: 2026-01-01, or a period back from today such as 30 days, 6 months. With newest first the Actor stops at the first older review. |
reviewScores | all | Score bands: review_adj_superb (9+), review_adj_good (7 to 9), review_adj_average_passable (5 to 7), review_adj_poor (3 to 5). Each band is read separately. |
reviewLanguages | all | Language codes: en, de, fr, es, it, ru, tr, ar, he, zh. |
guestTypes | all | COUPLES, FAMILIES, GROUP_OF_FRIENDS, SOLO_TRAVELLERS, BUSINESS_TRAVELLERS. |
searchText | none | Only reviews whose text contains this word or phrase. Booking.com does the search. |
skipReviewsWithoutText | false | Leave out reviews that are only a score. They are not billed. |
concurrency | 6 | Requests at the same time across all hotels, 1 to 16. |
proxy | Apify datacenter | What the Actor is priced on. Other Apify proxy groups are refused; your own proxies are accepted. |
Examples
The newest 100 reviews of one hotel:
{ "startUrls": [{ "url": "https://www.booking.com/hotel/ge/radisson-blu-batumi.html" }], "maxReviewsPerHotel": 100, "sortReviewsBy": "f_recent_desc" }
Yesterday's new reviews of three hotels, every day (put it on a schedule and de-duplicate on id):
{ "hotelIds": [320991, 359372, 1054549], "maxReviewsPerHotel": 1000, "sortReviewsBy": "f_recent_desc", "cutoffDate": "1 day" }
Only the complaints, English and German, of one hotel:
{ "hotelIds": [320991], "reviewScores": ["review_adj_poor", "review_adj_average_passable"], "reviewLanguages": ["en", "de"], "maxReviewsPerHotel": 500 }
What guests say about breakfast, in the 20 most reviewed hotels of Lisbon:
{ "destinations": ["Lisbon"], "hotelSort": "most_reviewed", "maxHotelsPerDestination": 20, "searchText": "breakfast", "maxReviewsPerHotel": 200 }
Where do I get hotel numbers?
Booking.com's review list is keyed on a number for each hotel (Radisson Blu Hotel Batumi is 320991), and a hotel's link does not contain it. Three ways to give the Actor what it needs:
- A place in
destinations. The hotels come with their numbers, so every hotel found is read. - The
hotelIdcolumn of the Booking.com Scraper Actor's output, which lists hotels by place with prices. Pass the column tohotelIds. This is exact. - A link in
startUrls. The Actor looks the hotel up by the name in the link and accepts a match only when the page name and the country are the same as the link's. A link keeps the name a hotel had when its page was made, so renamed hotels and long transliterated names are not always found. On a mixed sample of 150 hotels from twelve big cities, about two links in three were found. The links that are not found are listed inFAILED_HOTELSwith the reason and are not billed; give those as numbers.
How much does it cost to scrape Booking.com reviews?
One billed row is one review. Nothing else is charged except the platform's own two small events.
| Event | Price | When |
|---|---|---|
| Review | $0.0015, falling to $0.0008 by plan | Per review row that reaches the dataset |
| Actor start | $0.00005 | Once per run; at 512 MB it is a single start event |
| Result | $0.00001 | Per stored row, about one cent per thousand rows |
The review price steps down with your Apify plan: $0.0015 on the free plan and on Bronze, $0.0012 on Silver, and $0.0008 on Gold and above.
What that means for real jobs, all three charges included:
| Job | Rows | Free plan | Gold and above |
|---|---|---|---|
| 100 reviews of one hotel | 100 | $0.15 | $0.08 |
| 1,000 reviews of one hotel | 1,000 | $1.51 | $0.81 |
| Every review of a hotel with 1,200 reviews | 1,200 | $1.81 | $0.97 |
| The 10 most reviewed hotels of a city, 100 reviews each | 1,000 | $1.51 | $0.81 |
| Every review of a hotel with 30,000 reviews | 30,000 | $45.30 | $24.30 |
Reviews you filter out, reviews that are only a score when you skip them, and hotels that cannot be read are not billed. Set Maximum total charge on the run to cap the cost; the Actor stops cleanly when it is reached and says so in FAILED_HOTELS.
What should I know about the data?
- Booking.com lists the reviews of the last three years. The oldest review measured was dated exactly three years back. Older reviews are not there for anyone, and a hotel's review count includes only the listed ones.
- About half of the reviews are only a score. Measured on two hotels: 43% and 53% of the reviews had any text. They are delivered by default so that your count matches Booking.com's, and
skipReviewsWithoutTextleaves them out. - Hotel replies to the newest reviews can be missing. Measured on 11 October 2026: the reply to the two newest reviews of one hotel was there in some requests and not in others, while every older page was identical every time. A reply posted in the last day may not be in a run that reads it right away; a later run has it.
- The language code is Booking.com's.
nullmeans it could not tell. Review text is delivered as written, not translated. - Place lists hold the hotels that have a room tomorrow. That is how Booking.com's search works: a fully booked hotel is not listed. One search reaches about 1,000 hotels of a place; for a hotel that is not listed, give its number.
- Reviewer names are public on Booking.com and are personal data in many countries. The Actor collects what a visitor of the hotel page sees. What you may do with names and countries is your decision under the rules that apply to you; if you do not need them, drop the columns.
- Booking.com can change the page. Every response is checked, and a hotel whose answer is not a review list is reported instead of billed.
FAQ
Do I need a Booking.com account or a partner API key? No. The Actor reads what any visitor of a hotel page can read.
How do I get only new reviews? Run it on a schedule with sortReviewsBy set to f_recent_desc and cutoffDate set to a period slightly longer than the schedule ("2 days" for a daily run), and de-duplicate on id. The Actor stops at the first review older than the cutoff, so the run is short and bills only the recent reviews.
Why was a hotel link not read? The reason is in FAILED_HOTELS. Most often the name in the link does not match what the hotel is called now. Give its number in hotelIds.
Can I read reviews in one language? Yes: reviewLanguages, for example ["en"]. The HOTELS record shows how many reviews each language has.
Why do I get fewer reviews than the hotel's total? The total on the hotel page counts what Booking.com lists under your filters; maxReviewsPerHotel stops the read at the number you set, and reviewsOnBooking in HOTELS is the hotel's whole count.
Is it allowed? The Actor reads public pages of Booking.com without logging in. Booking.com's terms and the data protection rules of your country apply to what you do with the data; read them before you build on it. This Actor is not affiliated with or endorsed by Booking.com.
Other Actors for Booking.com data
- Booking.com Scraper: the hotels of a city, region, landmark or airport with prices, ratings and availability for your dates. Its
hotelIdcolumn is what this Actor takes as a hotel number. - Booking.com Hotel Price Monitor: one hotel's price and availability for each date of the next year.
- Booking.com Hotel Price Calendar Scraper: every room rate of a hotel with its cancellation and prepayment terms.