Booking.com Hotels, Prices and Reviews Scraper
Pricing
from $1.20 / 1,000 properties
Booking.com Hotels, Prices and Reviews Scraper
Scrape booking.com hotels, apartments, villas and hostels. Search any destination with the site's own filters (type, stars, review score, budget, meals, cancellation, amenities) or paste links. Live prices in 36 currencies, room-level rates, facilities, house rules and guest reviews.
Scrape accommodation from booking.com at scale: hotels, apartments, villas, hostels, guesthouses, B&Bs, campgrounds and everything else the site lists. Name a destination and a stay, or paste links you already built in your own browser, and get back one structured row per property with a live price, the rating, the exact location, the matched room configuration and, optionally, the whole property page and its guest reviews.
Built for people who need the numbers to be right: prices in the currency you asked for, a review score next to the number of reviews behind it, and an honest statement in the log when a destination is bigger than the site will serve.
What you get
Every row, always
| Identity | propertyId, propertyName, propertyUrl, pageName, accommodationTypeId, hostType |
| Rating | starRating, reviewScore, reviewScoreLabel, reviewCount, secondaryReviewScore, externalReviewScore, externalReviewCount |
| Location | address, city, countryCode, latitude, longitude, displayLocation, distanceFromSearchCentre, distanceMetres, isCentrallyLocated, publicTransportDistance, beachDistance |
| Price | price.perStay, price.perNight, price.perStayFormatted, price.beforeDiscount, price.currency, price.chargesInfo, price.badges, plus the property's own currency alongside |
| Rooms | rooms[] with roomId, price, mealPlan, occupancy, freeCancellationUntil, urgencyMessage; matchedUnit with bedrooms, bathrooms, beds, kitchens and floor area |
| Conditions | freeCancellation, noPrepayment, petsAllowedFreeOfCharge, mealPlanIncluded, isAvailableForDates, isSoldOut, isSustainable, isPreferredPartner, hasGeniusRate |
| Stay | checkIn, checkOut, nights, adults, children, roomsRequested |
| Photos | mainPhoto, thumbnailPhoto |
With fetchDetails on, each row also carries the property's own page
facilityGroups (every listed facility, grouped), topFacilities, houseRules (check-in and
check-out times, minimum check-in age, group limit, smoking, parties, city regulations, accepted
credit cards, cash), childrenAndBeds (with the per-age-band price rules), petsPolicy,
damagePolicy, finePrint, photos (up to 40), roomTypes (the full room catalogue with
amenities), questionsAndAnswers, languagesSpoken, brands, chainIds, propertyType,
propertyCurrency, reviewCategoryScores and totalReviewCount.
With maxReviewsPerProperty above 0, each row also carries reviews[]
Score, title, what the guest liked, what they did not, language, the date, the room they stayed in, how many nights, the traveller type, the property's own reply, and the reviewer's public display name and country. No contact details are collected: the review surface exposes none and this actor invents none.
Two ways to run it
Search mode
Name one or more destinations exactly as you would type them into the site's search box, set the stay, and narrow with the site's own filters.
{"mode": "search","destinations": ["Sydney", "Lisbon"],"checkIn": "2026-11-02","checkOut": "2026-11-04","adults": 2,"rooms": 1,"currency": "USD","starRatings": ["4", "5"],"minReviewScore": "8","maxPricePerNight": 350,"reservationPolicies": ["free_cancellation"],"amenities": ["swimming_pool", "free_wifi"],"sortBy": "rating_high_to_low","maxItems": 50}
Filters available: property type, star rating, minimum guest review score, budget per night, meals, reservation policy, property amenities, room amenities, bed preference and travel group. Those are sent to the site as its own filter tokens, so they narrow the search itself.
Three more are applied by this actor after the search, because the site has no working filter for them:
minReviewCountdrops a 10 out of 10 that came from two guests.availableOnlydrops properties that are not bookable for your dates. The site pads a thin result set with these, and it does publish an availability filter, but it ignores it: sending that filter returns exactly the same result set as sending nothing. So this actor identifies the padded rows itself and reports the answer in theisAvailableForDatescolumn, which is the same column the filter reads. Searching a small town for a large group is where this bites: one live check returned 25 cards of which only 2 were bookable.excludeSoldOutdrops properties the site has explicitly flagged sold out. That is a narrower question than the one above, so it stays a separate option.
URL mode
Paste links. A search link is walked with the destination, dates, guests and filter string that link already carries, so what you get is exactly what you saw. A property link returns that one property with its full detail.
{"mode": "url","urls": ["https://www.booking.com/searchresults.html?ss=Lisbon&checkin=2026-11-02&checkout=2026-11-04&nflt=class%3D5","https://www.booking.com/hotel/au/hilton-sydney.html"],"fetchDetails": true,"maxReviewsPerProperty": 50}
Sample output
Illustrative shape, trimmed. Values are placeholders, not a real listing.
{"propertyId": "0000000","propertyName": "Example Harbour Hotel","propertyUrl": "https://www.booking.com/hotel/au/example-harbour-hotel.html","starRating": 4,"reviewScore": 8.6,"reviewScoreLabel": "Excellent","reviewCount": 2793,"address": "1 Example Street","city": "Sydney","countryCode": "au","latitude": -33.8712,"longitude": 151.207,"price": {"currency": "USD","perStay": 412.5,"perNight": 206.25,"perStayFormatted": "$412.50","beforeDiscount": 480.0,"chargesInfo": "Includes taxes and fees","propertyCurrency": "AUD","perStayInPropertyCurrency": 620.0},"rooms": [{ "roomId": "0000001", "occupancy": 2, "price": 412.5, "currency": "USD","mealPlan": "Breakfast included", "freeCancellationUntil": "2026-10-30" }],"matchedUnit": { "bedrooms": 1, "bathrooms": 1, "beds": 1,"area": { "value": 32, "unit": "m2" } },"freeCancellation": true,"checkIn": "2026-11-02","checkOut": "2026-11-04","nights": 2,"houseRules": { "checkInFrom": "3:00 PM", "checkOutUntil": "11:00 AM" },"reviews": [{ "score": 9.0, "positiveText": "Great location and very clean","negativeText": "Check-in was slow", "reviewerCountry": "Australia","travellerType": "COUPLES", "nights": 3, "reviewedAt": "2026-08-25T00:00:00Z" }],"scrapedAt": "2026-09-05T12:00:00Z"}
Things worth knowing before you run it
Prices need a stay. A price only exists for concrete dates, so if you leave checkIn and
checkOut empty the run prices a 2 night stay 30 days out and says which window it used in the log.
Set the dates whenever the dates matter.
Currency is real conversion, not a label. Every price comes back in the currency you picked, and the property's own currency is returned beside it so you can see the original. The budget filter is denominated in the same currency you picked, so the two can never disagree.
One search reaches 1000 properties. The site stops serving new results past that point, whatever total it declares. A destination with 5000 properties will report 5000 and hand over 1000 of them. The run says so in the log rather than pretending it finished. To reach the rest, split the search: by neighbourhood link, by property type, by star rating or by budget band.
Max results decides what you get, sort decides which. With maxItems set and sortBy left on
the default, you get the site's own top picks. Set sortBy to price_low_to_high or
rating_high_to_low when the first N matter.
Reviews are paginated. maxReviewsPerProperty is read 25 at a time, so 100 reviews cost four
extra requests for that property. Reviews and the property page share ONE per-property surcharge, so
turning both on costs the surcharge once.
Recurring runs
Continue an interrupted crawl
Put the previous run's id in resumeFromRunId. Everything that run already collected is skipped, so
you are not charged for it twice.
Monitor a search on a schedule
Turn on incrementalMode. The actor remembers the previous run of the same search by itself and
returns only what changed, each row tagged changeType (NEW, UPDATED, REAPPEARED) with a
changedFields list, firstSeenAt and lastSeenAt. Price moves, rating moves and availability
changes are what you will see most.
Set stateKey to run several independent campaigns. emitUnchanged and emitExpired add rows for
properties that did not change and for ones that disappeared; both are off by default and both bill
as results when on. EXPIRED is only ever emitted after a run that reached the natural end of every
search, so a capped, resumed or partly blocked run never marks a live property as gone.
Send results into your apps (MCP connectors)
Optionally push the results straight into your own tools through Apify's MCP proxy. Set
mcpConnectors to the connectors you have authorised (for example notion or slack), set
notionParentPageUrl when you use Notion so pages are created in the right place, and use
maxNotifyProperties to cap how many properties are exported. The dataset always keeps everything;
the connector export is a side channel and never changes what was scraped.
Output views
The dataset ships four views on the Output tab: Properties (price, rating, location, stay), Property detail (facilities, house rules, room catalogue, photos), Guest reviews (scores and review text) and Changes since the last run (incremental mode).
What you are charged for
You are charged once when the run starts, once for each property returned, and once more for each property whose extra pages (its own page, its reviews, or both) were read and returned data. A property that is suppressed by incremental mode, or whose extra read failed, is not charged the surcharge. A run that returns nothing has nothing to pay for beyond the start. The rates are on the Store page for this actor.
Legal
This actor collects data that booking.com publishes to anyone, without logging in. It does not collect personal contact details. Review text and public reviewer display names are user generated content published by the site; if you process them, do so in line with the terms of the site and with the data-protection law that applies to you.