Booking.com Scraper – Hotels, Prices & Reviews avatar

Booking.com Scraper – Hotels, Prices & Reviews

Pricing

from $1.50 / 1,000 hotel returneds

Go to Apify Store
Booking.com Scraper – Hotels, Prices & Reviews

Booking.com Scraper – Hotels, Prices & Reviews

Scrape Booking.com hotels for any destination and dates: name, total price, rating, review count, stars, address, coordinates, photo and link, plus each hotel's reviews with score, text, guest nationality and traveller type. Every property Booking lists, no 1,000 cap. No key, no browser.

Pricing

from $1.50 / 1,000 hotel returneds

Rating

0.0

(0)

Developer

Simple Actor

Simple Actor

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Scrape Booking.com as structured data. Give it a destination and your dates and every property Booking lists comes back as a row: name, total price for your stay, guest score and review count, star rating, address, coordinates, property type, photo and a link — in Booking's own order. Turn reviews on and each property's reviews arrive as rows of their own: score, title, what the guest liked and disliked, their nationality and traveller type, stay dates, room, and the hotel's reply.

Built for price monitoring, market research, revenue management and hospitality lead generation — and it reaches every property Booking lists, with no thousand-result ceiling.

No API key, no login, no browser, no account of yours involved. A hundred properties arrive per request, so a typical search finishes in seconds.

$1.50 per 1,000 hotels, $1.00 per 1,000 reviews — $0.15 for a typical 100-hotel search. Apify platform usage included, nothing else to pay. A search that cannot be read is never charged.

Unofficial. Not affiliated with, endorsed by, or sponsored by Booking.com.

Features

  • The price for your exact stay — total for the dates, guests and rooms you searched, in the currency you chose, with a per-night average and a priceBasis on every row that says exactly what the number covers. No ambiguity about nightly versus total, or whose currency.
  • Everything Booking lists — a hundred properties per request and no cap: a city's full 1,500–7,000 properties are reachable. Booking's own count of results is on every row, so you know how many there are.
  • A catalogue without dates — leave the dates empty and every property in the destination is listed without prices, cheaply.
  • Booking's own filters and sorts — star ratings, minimum review score, free cancellation, and any filter string copied from a Booking URL; sorted by Booking's recommendation, price, reviews or stars.
  • Reviews worth having — score, title, liked and disliked text, guest nationality (name and code), traveller type, stay dates, room type, the hotel's reply and helpful votes. Joined to their hotel by hotelId.
  • Stable IDs — Booking's numeric hotelId on every row, for deduplicating across runs and joining reviews to hotels.
  • Paste a Booking link — a search copied from Booking keeps its destination, dates, guests, currency and filters.
  • Honest rows for every outcome. A destination Booking does not know is a not_found row, a bad line a bad_input row, a read that fails a read_failed row — never a silent empty result. The run stays green.

Input

{
"queries": ["Lisbon", "Algarve"], // one destination per line, or Booking search links
"checkIn": "2026-10-10", // leave both dates empty to list without prices
"checkOut": "2026-10-12",
"adults": 2, "children": 0, "rooms": 1,
"currency": "USD",
"maxHotels": 100, // per destination, up to 5,000
"sortBy": "recommended", // recommended | price | review_score_and_price | class
"stars": [4, 5], // optional
"minReviewScore": 8, // optional: 6, 7, 8 or 9
"freeCancellation": false,
"filters": "ht_id=204", // optional: any Booking nflt= string
"includeReviews": false,
"maxReviewsPerHotel": 25,
"reviewSort": "most_relevant" // most_relevant | newest_first
}
FieldTypeDefaultWhat it does
queriesarrayDestinations as you would type them into Booking — a city, region, district, landmark or country — or search-results links copied from Booking.
checkIn, checkOutstringYYYY-MM-DD. Both, or neither. With dates: prices and availability. Without: every property, no prices.
adults, children, roomsinteger2, 0, 1The booking the price is for. childrenAges (array) makes family pricing exact.
currencystringUSDThree-letter code. Booking converts at its own rate.
maxHotelsinteger100Properties per destination, up to 5,000. A hundred per request.
sortBystringrecommendedBooking's sort menu.
stars, minReviewScore, freeCancellationBooking's own filters.
filtersstringAny other Booking filter, as it appears after nflt= in a filtered URL (ht_id=204;mealplan=1).
includeReviewsbooleanfalseCollect each property's reviews as separate rows. Charged per review.
maxReviewsPerHotelinteger25Reviews per property, up to 2,000. Twenty-five per request.
reviewSortstringmost_relevantBooking's most relevant, or newest first.

What the price is

price is the total for the whole stay — every night, every guest, every room you asked for — as Booking quotes it for those exact dates, in the currency you chose. pricePerNight is that total divided by the nights, and originalPrice is the struck-through price before a discount, when Booking shows one. priceBasis spells it out on every row ("total for 2 nights, 2 adults, 1 room, as Booking quotes it") so a spreadsheet never has to guess. Without dates there is no price, and the row says so with nulls rather than a guessed number.

How many properties

A hundred arrive per request and there is no ceiling: maxHotels decides how far to read, and Booking's own count is in totalResults on every row — so a first run at the default 100 tells you a city has 1,819 properties, and a second run at 2,000 collects them all.

Output

One item per property, in the run's dataset — a real row, from a search for a hotel by name ("The Plaza Hotel New York", 16–18 October 2026):

{
"type": "hotel",
"position": 1,
"name": "The Plaza, A Fairmont Hotel",
"hotelId": 58958,
"url": "https://www.booking.com/hotel/us/the-plaza.html?checkin=2026-10-16&checkout=2026-10-18&group_adults=2&no_rooms=1&group_children=0&selected_currency=USD",
"address": "768 5th Avenue",
"city": "New York (New York)",
"countryCode": "us",
"latitude": 40.7644335377821,
"longitude": -73.9742463827133,
"stars": 5,
"reviewScore": 8.6,
"reviewCount": 509,
"accommodationTypeId": 204,
"propertyType": "Hotel",
"price": 3402.5,
"originalPrice": null,
"currency": "USD",
"pricePerNight": 1701.25,
"priceBasis": "total for 2 nights, 2 adults, 1 room, as Booking quotes it",
"checkIn": "2026-10-16",
"checkOut": "2026-10-18",
"nights": 2,
"adults": 2,
"children": 0,
"rooms": 1,
"imageUrl": "https://cf.bstatic.com/xdata/images/hotel/square600/914954799.webp?…",
"destination": "The Plaza, A Fairmont Hotel, New York (The City of New York), New York, United States",
"destinationId": "hotel:58958",
"totalResults": 456,
"query": "The Plaza Hotel New York",
"page": 1,
"retrievedAt": "2026-09-12T04:59:49.890Z"
}

Every hotel field

FieldTypeWhat it is
typestring"hotel" on a property row.
positionintegerThe property's rank in Booking's order for this search, 1 first, counted across pages.
namestringThe property's name as Booking shows it.
hotelIdintegerBooking's numeric ID for the property — stable across runs. Join review rows to hotels on it; deduplicate across runs with it.
urlstringThe property's page on Booking.com, with the dates, guests, rooms and currency of your search already in the link.
addressstring / nullStreet address as Booking states it.
citystring / nullCity.
countryCodestring / nullTwo-letter country code, lower case as Booking uses it (pt, lk, us).
latitude, longitudenumberCoordinates of the property.
starsnumber / nullStar rating 1–5 as Booking states it. Null for properties Booking does not class (many guest houses and homestays).
reviewScorenumber / nullBooking's guest review score out of 10. Null for a property with no reviews yet — never 0.
reviewCountinteger / nullHow many guest reviews the property has.
accommodationTypeIdinteger / nullBooking's numeric property-type code.
propertyTypestring / nullThe type in words for the codes Booking documents: 204 Hotel, 201 Apartment, 203 Hostel, 205 Motel, 206 Resort, 208 Bed and breakfast, 213 Villa, 216 Guest house, 219 Aparthotel, 220 Holiday home, 222 Homestay, 225 Capsule hotel. Null for other codes.
pricenumber / nullThe total for the whole stay — every night, guest and room you searched — as Booking quotes it, in currency. Null when no dates were given, or when Booking quoted no rate for those dates (sold out, minimum stay).
originalPricenumber / nullThe stay's price before Booking's discount, when the property shows one struck through. Null when there is no discount.
currencystring / nullCurrency of price — the one you asked for.
pricePerNightnumber / nullprice divided by nights, an average.
priceBasisstring / nullWhat the price covers, in words — e.g. "total for 2 nights, 2 adults, 1 room, as Booking quotes it" — so a spreadsheet never has to guess.
checkIn, checkOutstring / nullThe dates the price is for, YYYY-MM-DD. Null when no dates were searched.
nightsinteger / nullNights in the stay.
adults, children, roomsinteger / nullThe booking the price is for.
imageUrlstring / nullThe property's main photo on Booking's image host.
destinationstringThe destination as Booking resolved your search — e.g. "Lisbon, Lisbon Region, Portugal", or the property itself when you searched a hotel name.
destinationIdstringBooking's ID for that destination with its type: "city:-2167973", "region:…", "hotel:58958".
totalResultsintegerBooking's own count of properties for this search — how many there are to collect.
querystringThe line of input this row answered.
pageintegerWhich request of the search the row arrived on, 1 first. A hundred properties per request.
retrievedAtstringWhen this run read the search, ISO 8601.

And, with includeReviews on, one item per review — a real one, of the same property, with the hotel's reply:

{
"type": "review",
"position": 5,
"hotelId": 58958,
"hotelName": "The Plaza, A Fairmont Hotel",
"url": "https://www.booking.com/hotel/us/the-plaza.html?checkin=2026-10-16&checkout=2026-10-18&group_adults=2&no_rooms=1&group_children=0&selected_currency=USD",
"reviewScore": 10,
"title": "Most amazing stay",
"positiveText": "The location, the service, the luxury",
"negativeText": "Nothing",
"language": "xu",
"reviewedAt": "2026-09-03T10:14:12.000Z",
"guestName": "Haya",
"guestCountryCode": "kw",
"guestCountry": "Kuwait",
"travellerType": "Solo traveler",
"customerType": "SOLO_TRAVELLERS",
"stayCheckIn": "2026-08-04",
"stayCheckOut": "2026-08-07",
"nights": 3,
"roomType": "Grand Luxe Family Queen Room with Sofa Bed",
"hotelReply": "Dear Guest, \n\nWe are delighted to hear that you had an exceptional experience. Thank you for your kind words and we look forward to having you with us again soon. \n\nWarm regards, \n\nSam Ioannidis\nManaging Director",
"helpfulVotes": 0,
"query": "The Plaza Hotel New York",
"retrievedAt": "2026-09-12T04:59:49.890Z"
}

Every review field

FieldTypeWhat it is
typestring"review" on a review row.
positionintegerThe review's position in the hotel's list, in the order you chose.
hotelIdintegerThe hotel the review is of — joins to the hotel row's hotelId.
hotelNamestringThe hotel's name, repeated for convenience.
urlstringThe hotel's Booking page.
reviewScorenumberThe guest's score out of 10.
titlestring / nullThe review's title, when the guest gave one.
positiveTextstring / nullWhat the guest liked.
negativeTextstring / nullWhat the guest disliked.
languagestring / nullThe language the review is written in (en, de, fr…). Booking's code xu means the text was machine-translated.
reviewedAtstringWhen the review was posted, ISO 8601.
guestNamestring / nullThe guest's first name as shown.
guestCountryCodestring / nullThe guest's country, two-letter code — nationality, for segmenting.
guestCountrystring / nullThe guest's country in words.
travellerTypestring / nullWho travelled, as Booking labels it: Family, Couple, Solo traveler, Group…
customerTypestring / nullBooking's code for the same: FAMILIES, COUPLES, SOLO_TRAVELLERS, GROUP_OF_FRIENDS
stayCheckIn, stayCheckOutstring / nullThe guest's own stay dates.
nightsinteger / nullHow many nights the guest stayed.
roomTypestring / nullThe room the guest stayed in.
hotelReplystring / nullThe property's public reply to the review, when there is one.
helpfulVotesinteger / nullHow many people marked the review helpful.
querystringThe line of input the hotel came from.
retrievedAtstringWhen this run read the reviews, ISO 8601.

Error rows

A search that could not be read is its own row rather than a failed run:

FieldWhat it is
type"error"
queryThe line of input that could not be searched.
errorbad_input (the line cannot be searched — a hotel-page link, a bad date), not_found (Booking knows no such destination) or read_failed (Booking's answer could not be read after retries).
errorDescriptionThe reason in words.
retrievedAtWhen it was tried.

Error rows are never charged. The run itself stays green either way, and its status message says how many searches could not be read — so if you run on a schedule, check for type: "error" rows rather than trusting the run status.

An empty dataset means every search was read and Booking lists nothing for it. A destination Booking does not know comes back as a not_found row, never as silence.

How to use

From Apify Console

  1. Open the Actor and click Try for free / Start.
  2. Put one destination per line into Destinations, or paste a Booking search link.
  3. Set Check-in and Check-out for prices, or leave them empty to list every property without prices.
  4. Set Hotels per destination — 100 is one request; totalResults on the rows tells you how many there are.
  5. Turn on Also collect each hotel's reviews if you want them, and cap Reviews per hotel.
  6. Click Start, then open the Dataset tab — the Hotels view shows a photo of each, the Reviews view the reviews — and export as JSON, CSV or Excel.

From the API

curl -s "https://api.apify.com/v2/acts/simple.actor~booking-hotels/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"queries": ["Lisbon"], "checkIn": "2026-10-10", "checkOut": "2026-10-12", "maxHotels": 200}'

Price monitoring with the JavaScript client:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('simple.actor/booking-hotels').call({
queries: ['Lisbon'],
checkIn: '2026-10-10',
checkOut: '2026-10-12',
currency: 'EUR',
stars: [4, 5],
maxHotels: 500,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
// Track price by hotelId over runs; join reviews to hotels on the same key.

Use cases

  • Price monitoring — the same destination and dates every day, keyed by hotelId, to see how rates move.
  • Market research — every property in a city with score, stars, type and price band, and how many there are.
  • Revenue management — where a property sits against its competitors for the same dates and guests.
  • Hospitality lead generation — every property of a type in an area, with its Booking page and coordinates.
  • Review analysis — thousands of reviews with nationality, traveller type and the hotel's reply, for sentiment or service benchmarking.

Pricing

Simple pay-per-result pricing — no subscription and no start fee.

EventPrice
Hotel returned$0.0015
Review returned$0.0010

What that comes to:

  • A search at the default depth, 100 hotels: $0.15.
  • Every property in a big city, around 1,800: about $2.70.
  • 100 hotels with 25 reviews each: $2.65 — $0.15 for the hotels, $2.50 for the 2,500 reviews.
  • 1,000 reviews, however many hotels they come from: $1.00.

Error rows are never charged, and a search Booking has nothing for costs nothing.

Limits worth knowing

  • Hotel-page details are not included — amenities, the named rooms with their individual prices, the description and the photo gallery live on pages that need a browser. Each row's url opens them.
  • Prices are Booking's quote for one booking as you defined it. Booking shows different prices for different guest counts and dates; change the input, not the arithmetic.
  • Reviews cost per review. A property with a thousand reviews is a thousand rows; maxReviewsPerHotel caps it.
  • A destination is resolved to Booking's best match. Every row carries the resolved destination, so an ambiguous name ("Paris") is visible as what Booking took it to be.

FAQ

Is scraping Booking.com legal? Results come from Booking.com and are subject to Booking's terms — check them, and your own use, before relying on the data. This Actor reads the same listing data Booking shows anyone searching, without logging in.

Do I need a Booking.com API key or partner account? No. There is no key, no login, no browser and no quota of your own to manage.

Why is price null on some rows? Either no dates were given (then no row has a price), or Booking quoted no rate for that property for those dates — sold out, or minimum-stay rules. It is left null rather than guessed.

Can I get a specific hotel? Yes — type its name as a destination. Booking resolves it to the property itself, which arrives as the first row (with destinationId hotel:…), followed by its neighbours. Turn reviews on to get that hotel's reviews. Hotel-page links cannot be read directly, but the hotel's name can.

How do I know a search failed if the run stays green? Check for rows with type: "error" — that is the failure channel by design, so one bad search never costs the rest of the job. The run's status message also counts how many searches could not be read.

Results come from Booking.com and are subject to Booking's terms. Unofficial, and not affiliated with Booking.com.