Booking.com Hotels Scraper avatar

Booking.com Hotels Scraper

Pricing

Pay per event

Go to Apify Store
Booking.com Hotels Scraper

Booking.com Hotels Scraper

Scrape Booking.com hotel search results with live prices in a currency you choose, guest review scores, star ratings, addresses and distance. Filter-slicing returns ~180 hotels per destination where a naive scraper gets 25.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Muhammad Ahmed

Muhammad Ahmed

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Share

Scrape Booking.com hotel search results — live prices in a currency you pin, guest review scores, star ratings, addresses and distance from the centre — for any destination, date range and occupancy.

Why this one goes deeper

Booking hands a headless browser 25 properties per search and offers no way to page further: no "Load more" button, no pagination links, and the offset parameter is ignored outright (offsets 0, 25 and 50 all return the same first property — verified).

This Actor gets past that by slicing each search into disjoint filtered queries — Booking's own ranking first, then five star classes, then five price bands — each of which returns its own 25. Duplicates are removed by hotel ID across slices.

Measured on Paris, one date range: 180 unique hotels in 51 seconds, every one with a price. Against 25 for a naive scraper.

Slicing pays a second dividend: a hotel found in the 4-star slice is 4-star. That matters more than it sounds — Booking omits star markup from its cards entirely when the request comes from a datacenter IP, so the class filters are the only place a star rating comes from on the default proxy. Star ratings are taken from the slice that establishes them, and are null — never guessed — where nothing does.

What you get

  • Prices in a fixed currency. Booking prices by the requesting IP's location; on a datacenter host that means results arrive in PKR or similar. This Actor pins selected_currency, so USD means USD wherever the run executes.
  • Guest scores and review counts parsed to numbers (8.1, 1621), not left as "Scored 8.1".
  • Address and distance"14th arr., Paris", "3.7 km from downtown".
  • Full occupancy control — check-in/out, adults, children, rooms, sort order, language.
  • Requires a real browser; plain HTTP gets an HTTP 202 challenge.

Input

FieldTypeDescription
destinationsarrayCity, region or property name as typed into Booking's search box
checkIn / checkOutstringYYYY-MM-DD; defaults to a 2-night stay 30 days out
adults / children / roomsintegerOccupancy — changes which rooms and prices appear
currencystringThree-letter code. Pin this or prices follow the server's location
languagestringBooking locale, e.g. en-us, de
sortBystringBooking's sort key, or empty for its default ranking
maxResultsPerDestinationintegerUp to ~180 per destination via slicing (default 100)
maxItemsintegerTotal cap (0 = no limit)
proxyConfigurationobjectRequired — datacenter proxy by default

Example

{
"destinations": ["Paris", "Tokyo"],
"checkIn": "2026-10-01",
"checkOut": "2026-10-03",
"adults": 2,
"currency": "USD",
"maxResultsPerDestination": 150
}

Output

{
"name": "Montparnasse Alésia",
"url": "https://www.booking.com/hotel/fr/montparnasse-alesia.html",
"hotelId": "montparnasse-alesia",
"price": 440,
"priceText": "US$440",
"currency": "USD",
"reviewScore": 8.1,
"reviewCount": 1621,
"stars": 3,
"address": "14th arr., Paris",
"distanceFromCentre": "3.7 km from downtown",
"image": "https://cf.bstatic.com/xdata/images/hotel/…",
"destination": "Paris",
"checkIn": "2026-10-01",
"checkOut": "2026-10-03"
}

A destination that returns nothing produces an item with error rather than vanishing.

Notes and limits

  • price is the total for your date range, as Booking displays it, not a per-night rate.
  • Star ratings are filled for most, not all, results — about 43 of 60 on a typical run. After the requested number of hotels is reached the Actor keeps running the star-class filters purely to fill this column in, but each filter itself only returns 25 hotels, so a property ranked deep inside its class can go unmatched. Anything the filters do not establish stays null rather than being guessed from card markup, and self-catering places genuinely have no star rating at all.
  • Coverage is deep, not exhaustive. Slicing reaches ~180 hotels per destination and date range, not every property in a city. Scrape more date ranges or narrower destinations for wider coverage.
  • Availability and price depend on your dates and occupancy, so two runs with different inputs are not comparable — that is Booking's behaviour, not the Actor's.
  • A proxy is required and enabled by default. Booking returns nothing to the bare container IP. Apify's datacenter proxy works and is the default. Residential costs roughly 9x more and is worth it for one reason only: Booking sends star markup to residential IPs, so every row gets a star rating directly instead of relying on the class filters.
  • Images are not downloaded. Hotel photo URLs are still returned, but the files themselves are blocked — they are the bulk of the page weight and none of the data.

Local development

npm install
npx playwright install chromium
npm run build
CHROME_PATH=/path/to/chrome node dist/main.js

CHROME_PATH is optional — it lets a self-hosted run reuse an existing Chromium. On Apify the Playwright image supplies the browser.