Booking.com Hotels Scraper & Price Tracker
Pricing
from $1.69 / 1,000 properties
Booking.com Hotels Scraper & Price Tracker
Booking.com hotels scraper and hotel price tracker (Booking scraper): hotel prices from Booking.com search results for any destination and dates — stay price, taxes, review score, reviews, stars, type, location, photo. Tracks price changes between runs. One flat row per property, no personal data.
Pricing
from $1.69 / 1,000 properties
Rating
0.0
(0)
Developer
Flatrow Data Studio
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 hours ago
Last modified
Categories
Share
Booking.com Hotels Scraper & Price Tracker – hotel prices and ratings, no personal data
Booking.com hotels scraper and hotel price tracker: get hotel prices, taxes, review scores and availability for any destination and dates, as a clean table or through an API — no login. Use it as a Booking scraper for rate shopping, hotel price monitoring and hotel price comparison across dates and destinations.
No login, no cookies, no personal data: nothing to sign in to, no cookies to paste, nothing about guests or reviewers in the output.
- What you get: one flat row per Booking.com property for any destination and dates, or for the search URLs you paste: total price of the stay, excluded taxes and fees, strike-through price, review score on 10, review count, stars, type, neighbourhood, coordinates, photo and link; a price-monitoring mode that returns only what changed since your previous run. No personal data.
- For whom: hoteliers and revenue managers (rate shopping), travel data and BI teams, deal finders and price-alert tools, AI agents through MCP.
- How much: from $2.50 per 1,000 properties on the Free plan, lower on paid plans; Apify's free monthly credit of $5 covers about 1,999 properties. A fixed price per property saved and nothing else (compute and proxies included, see the Pricing tab); unchanged prices in monitoring mode are never charged;
maxResultscaps every run.
Sample output: one real row from a Lisbon search, key columns only (the full row is under Output example):
{"platformListingId": "2628938","title": "Villa Baixa - Lisbon Luxury Apartments","city": "Lisboa","checkIn": "2026-11-20","checkOut": "2026-11-23","currency": "EUR","priceTotal": 637.43,"taxesAndFees": 62.25,"priceTotalAllIn": 699.68,"rating": 9.6,"reviewCount": 874,"starRating": 4}
Scrape Booking.com search results for any destination and dates and get one flat row per property: hotels, apartments, aparthotels, hostels, guest houses and B&Bs with the total price of the stay, the taxes and fees Booking.com shows as excluded, the strike-through price of deals, the review score on 10 and the number of reviews, the official stars, the accommodation type, coordinates and neighbourhood, bedrooms / beds / bathrooms for apartments, badges such as "Limited-time Deal", the free-cancellation flag and the main photo. Search by destination and stay, up to 50 destinations in one run with locations, or paste Booking.com search URLs with their filters; monitor prices: in price-monitoring mode a scheduled run compares every property with your previous run of the same search and can return only the new properties and the price changes. This Booking.com scraper reads the same search API as the Booking.com website, without logging in, 100 properties per request, removes duplicates and stops exactly at the number of properties you ask for.
No personal data, by design. Nothing about guests or reviewers is collected: no names, no review texts, no profile photos, no ids of persons. The output only contains property-level facts (business names), the average score and the number of reviews. The dataset is safe to store, share and feed to AI agents.
What can you do with Booking.com data?
- Track hotel prices for a destination and dates: rate shopping for hoteliers and revenue managers, deal finders, seasonal price studies, price alerts with a scheduled run. With
monitorPricesandonlyChanges, a daily schedule gives you only the price drops, rises and new properties, and you pay only for those rows. - Build accommodation datasets for a city or a region, with coordinates ready for mapping, stars, type and review scores for segmentation.
- Compare segments: hotels vs apartments vs hostels, 3 vs 4 stars, best reviewed vs cheapest, with the same price basis (same stay, same guests, same currency).
- Feed AI agents, spreadsheets and BI tools with a stable, documented schema shared by the other scrapers of this travel studio (Airbnb Scraper uses the same columns), so stays from several platforms can be compared.
What data does Booking.com Scraper extract?
Every row has every column: a value Booking.com does not show in search results is null (or [] for lists), so CSV and Excel exports keep the same columns from run to run.
| Group | Columns |
|---|---|
| Identity | schemaVersion, platform, platformListingId, url, title, propertyType, roomType |
| Location | city, region, country, countryCode, latitude, longitude |
| Stay | checkIn, checkOut, nights, guests, isAvailable |
| Prices | currency, pricePerNight, priceTotal, priceBeforeDiscount, taxesAndFees, taxesIncluded, priceTotalAllIn, cleaningFee, serviceFee |
| Quality | rating, ratingMax, reviewCount, starRating, badges, isSuperhost, isNew, listedBy, cancellationPolicy, instantBook |
| Size | bedrooms, beds, bathrooms, maxGuests, amenities |
| Photos | imageUrls, imageCount |
| Search context | searchLocation, searchRank, searchPage, viewCountryCode, scrapedAt |
| Price monitoring | changeType, previousPrice, priceDelta, priceDeltaPercent (null unless monitorPrices is on, see below) |
Columns that Booking.com never shows on search result cards stay empty for this Actor: amenities (always []), maxGuests, instantBook, isNew, isSuperhost, listedBy (always null), cleaningFee and serviceFee (Booking.com does not itemise them; taxesAndFees holds the excluded charges). bedrooms, beds and bathrooms are shown for apartments and holiday homes, rarely for hotel rooms. rating is on a 10-point scale (ratingMax is 10).
Which price to compare. On Booking.com, priceTotal is the price of the stay before the taxes and charges Booking.com shows as excluded, which are in taxesAndFees; taxesIncluded is then false (it is true when Booking.com shows an excluded amount of 0, null when it shows no excluded amount). priceTotalAllIn is the total of the stay with them, priceTotal + taxesAndFees (€637.43 + €62.25 = €699.68 in the sample above), and null when the taxes are unknown, never estimated: it is the column to compare stays across platforms, filled with the same rule by every travel scraper of the studio.
How to scrape Booking.com hotels
- Enter a destination as you would type it on Booking.com ("Lisbon, Portugal", "Paris", "Algarve"), a list of destinations in
locations, or paste one or more Booking.com search URLs copied from your browser: their destination, dates, guests, rooms, sort order, filters, currency and language are used as they are. If Booking.com does not recognise a destination text, copy thedest_idfrom a Booking.com search URL into Destination id: that path is always reliable. - Choose the stay: fixed dates (
checkIn/checkOut) for a precise quote, or relative dates (check-in in N days for M nights, the default) for schedules and recurring price checks that must never expire. Set adults, children (with their ages) and rooms: prices depend on them. - Set the maximum number of properties and, if needed, the currency, the language, the sort order and the filters: property types, star ratings, minimum review score, price per night, free cancellation, breakfast included (see Filters below), or any other Booking.com filter string.
- Run and open the Output tab: the Overview, Prices, Location and Changes views show the main columns; export everything as JSON, CSV, Excel or through the API.
- To follow prices, schedule the run, tick
monitorPricesand, to get only what changed,onlyChanges: every run after the first returns only the new properties and the price changes (see Price monitoring below).
Input
Give a list of locations (one or more destinations), a destId or at least one URL in startUrls; location (a single destination) is still accepted. checkIn and checkOut go together, otherwise checkInDaysFromNow and nights apply. Field names and defaults are those of the input form.
The search of our validation run, written with locations: 60 properties in Lisbon for a 3-night stay starting in 30 days, 2 adults, 1 room, prices in EUR, Booking.com's top-picks order (every other field keeps its default; the validation run itself pinned Lisbon by its Booking.com destination id, destId with location):
{"locations": ["Lisbon, Portugal"],"checkInDaysFromNow": 30,"nights": 3,"adults": 2,"rooms": 1,"currency": "EUR","language": "en-us","sortBy": "popularity","maxResults": 60}
Every field, with its type and default:
| Field | Type | Default | Description |
|---|---|---|---|
locations | string[] | [] | One or more destinations as typed on Booking.com (city, region, landmark or address), one per line, searched one after the other with the same dates, guests, rooms, sort, filters, currency and language (up to 50, with location), together with the destId and the search URLs. When set, maxResults applies to each destination and each search URL. Prefilled with ["Lisbon, Portugal"] in the form (clear it to search a destId or search URLs only, otherwise Lisbon is searched too, maxResults each); with no locations, location, destId or startUrls at all, the Actor searches Lisbon. |
location | string | — | Single destination (kept for compatibility; prefer locations), as typed on Booking.com, searched before the destinations of locations. Resolved by Booking.com; give destId when the text is ambiguous. |
destId | integer | — | Booking.com destination id, the dest_id parameter of a search URL, a whole number, negative for cities (e.g. -2167973 for Lisbon). Optional when the text is enough. |
destType | string | "CITY" | Type of the destination id (dest_type of the URL): CITY, DISTRICT, REGION, COUNTRY, LANDMARK, AIRPORT, HOTEL. CITY is validated. |
startUrls | string[] | [] | Booking.com search results URLs copied from your browser (https://www.booking.com/searchresults.html?ss=…). Their destination, dates, guests, rooms, sort, nflt filters, currency and language are used as they are; the fields below fill what a URL does not set. A URL that is not a results page is refused with the reason. |
checkIn | string | — | Check-in date, YYYY-MM-DD. Leave both dates empty to use relative dates. |
checkOut | string | — | Check-out date, YYYY-MM-DD, after check-in. Required when checkIn is set. |
checkInDaysFromNow | integer | 30 | Without fixed dates: check-in this many days from today (UTC). |
nights | integer | 3 | Without fixed dates: length of the stay. |
adults | integer | 2 | Number of adults. |
children | integer | 0 | Number of children (0–17). |
childrenAges | integer[] | [] | Age of each child; a child without a listed age counts as 8 years old. |
rooms | integer | 1 | Number of rooms (units). |
maxResults | integer | 100 | Stop after this many unique properties (100 per request, 1,000 at most): for the whole run, or for each destination and each search URL when locations is set. You are never charged for more. In monitoring mode, the number of properties compared. Prefilled with 20 in the form for a quick first run. |
sortBy | string | "popularity" | popularity (Booking.com's top picks) or price (lowest first), both validated; class, review_score_and_price, distance_from_search, upsort_bh, bayesian_review_score are the other orders of the Booking.com sort bar, not yet verified. |
propertyTypes | string[] | [] | Keep only these accommodation types, several types adding up: hotels (validated), apartments, hostels, guest_houses, bed_and_breakfasts, villas, holiday_homes, aparthotels, homestays (to confirm at the first run). Empty: every type. |
starRatings | integer[] | [] | Official star ratings to keep, from 1 to 5, e.g. [4, 5] for 4 or 5 stars. Empty: any rating. To confirm at the first run. |
minReviewScore | integer | — | Minimum guest review score out of 10: 6, 7, 8 or 9. To confirm at the first run. |
priceMin | integer | — | Lowest price per night, in the currency of the search (whole amount, 0 to 1,000,000,000). To confirm at the first run. |
priceMax | integer | — | Highest price per night, in the currency of the search, greater than priceMin (whole amount, up to 1,000,000,000). To confirm at the first run. |
freeCancellation | boolean | false | Only properties offering free cancellation. To confirm at the first run. |
breakfastIncluded | boolean | false | Only properties with breakfast included. To confirm at the first run. |
filters | string | — | For experts: any other Booking.com filter, the nflt parameter of a search URL, filters separated by ; (e.g. ht_id=204, validated). The filter fields above are added to it without duplicates. |
currency | string | "EUR" | ISO 4217 code of the currency of every price (EUR and USD validated, any Booking.com currency accepted). |
language | string | "en-us" | Booking.com language code for types, neighbourhoods and badges: en-us (validated), en-gb, fr, de, es, it, pt-pt… (pick one from the list or type any code). |
monitorPrices | boolean | false | Compare the total price of every property with the one recorded by your previous run of the same search (changeType, previousPrice, priceDelta, priceDeltaPercent). |
monitorStoreName | string | "booking-price-monitor" | Key-value store of your account that keeps the previous prices (one record per search). Letters, digits and dashes. |
onlyChanges | boolean | false | With monitorPrices: save and charge only the new properties and the price changes; a run without any change succeeds with an empty dataset. |
proxyConfiguration | object | {"useApifyProxy":true} | Apify datacenter proxies by default (enough for the search API in our tests), included in the price; keep them, or bring your own proxy URLs. A proxy country is recorded in viewCountryCode. |
maxRequests | integer | 100 | Safety cap on API requests per run (100 properties per request, plus one to three light requests to resolve a destination given as text, more when Booking.com has to be asked again). |
delayMs | integer | 800 | Pause between two page requests of the same search, in milliseconds. |
debugStoreHtml | boolean | false | Debugging only: store every API response (JSON) in the key-value store. |
Several destinations in one run. List them in locations (with or without location): each destination is searched on its own with the same dates, guests, rooms, sort, filters, currency and language, and maxResults applies to each of them. This input returns up to 50 properties for each of the three cities, 150 at most:
{"locations": ["Paris, France", "Rome, Italy", "Barcelona, Spain"],"checkInDaysFromNow": 30,"nights": 3,"adults": 2,"currency": "EUR","maxResults": 50}
The searchLocation column tells which destination found each property. A property found by two destinations (a city and one of its districts) is saved and charged once, under the first destination of the list. Without locations, maxResults keeps capping the whole run, location (or destId) and search URLs together.
Output example
One real row, produced by the Actor from a Lisbon search (EUR, English, 20–23 November 2026, 2 adults, 1 room). All columns are present, in this order, for every property:
{"schemaVersion": "travel-listing/1.5","platform": "booking","platformListingId": "2628938","url": "https://www.booking.com/hotel/pt/villa-baixa-lisbon-luxury-apartments.html?checkin=2026-11-20&checkout=2026-11-23&group_adults=2&group_children=0&no_rooms=1&selected_currency=EUR&lang=en-us","title": "Villa Baixa - Lisbon Luxury Apartments","propertyType": "Aparthotel","roomType": "entire_place","city": "Lisboa","region": "Santa Maria Maior","country": "Portugal","countryCode": "PT","latitude": 38.7124951804023,"longitude": -9.13769279818235,"checkIn": "2026-11-20","checkOut": "2026-11-23","nights": 3,"guests": 2,"currency": "EUR","pricePerNight": 212.48,"priceTotal": 637.43,"priceBeforeDiscount": 910.61,"cleaningFee": null,"serviceFee": null,"taxesAndFees": 62.25,"taxesIncluded": false,"priceTotalAllIn": 699.68,"rating": 9.6,"ratingMax": 10,"reviewCount": 874,"starRating": 4,"bedrooms": 1,"beds": 2,"bathrooms": 1,"maxGuests": null,"amenities": [],"badges": ["Limited-time Deal"],"isSuperhost": null,"listedBy": null,"instantBook": null,"isNew": null,"isAvailable": true,"cancellationPolicy": "free_cancellation","imageUrls": ["https://cf.bstatic.com/xdata/images/hotel/square600/736934046.webp?k=7cf29ad6bc51ef6ac4fa95219b49ce0a6099661e41c2cbbf1c7ebe149dbd04b0&o="],"imageCount": 1,"searchLocation": "Lisbon, Portugal","searchRank": 1,"searchPage": 1,"viewCountryCode": null,"scrapedAt": "2026-10-19T08:00:00.000Z","changeType": null,"previousPrice": null,"priceDelta": null,"priceDeltaPercent": null}
A hotel room row has roomType hotel_room, bedrooms / bathrooms null, and priceBeforeDiscount null unless the hotel runs a deal; a hostel dorm bed has roomType shared_room.
The last four columns are filled in price-monitoring runs only (see below).
The Output tab offers four views of the same rows: Overview (name, type, stars, city, dates, prices, score, reviews, link, photo), Prices (nights, nightly average, total, strike-through price, excluded taxes, currency, cancellation, deals), Location (city, neighbourhood, country, coordinates, rank) and Changes (price-monitoring runs: change type, dates, total price, previous total, difference, search, link).
Filters
Pick the usual Booking.com filters in the form instead of copying a filter string: each field becomes the element of Booking.com's nflt filter string shown below, the string the website itself puts in its search URLs.
| Field | Booking.com filter | Sent to Booking.com as | Status |
|---|---|---|---|
propertyTypes | Property type (several types add up) | ht_id=204 hotels, ht_id=201 apartments, ht_id=203 hostels, ht_id=216 guest houses, ht_id=208 bed and breakfasts, ht_id=213 villas, ht_id=220 holiday homes, ht_id=219 aparthotels, ht_id=222 homestays | hotels validated; the other types to confirm at the first run |
starRatings | Property rating (several ratings add up) | class=4;class=5 for [4, 5] | to confirm at the first run |
minReviewScore | Review score: 6+, 7+, 8+ or 9+ out of 10 | review_score=80 for 8 | to confirm at the first run |
priceMin, priceMax | Your budget, per night, in the currency of the search | price=EUR-50-150-1 for 50 to 150 EUR (an open bound is sent as 0 or max) | to confirm at the first run |
freeCancellation | Free cancellation | fc=2 | to confirm at the first run |
breakfastIncluded | Breakfast included | mealplan=1 | to confirm at the first run |
4- and 5-star hotels in Paris rated 8 or more, under 250 EUR a night, with free cancellation, for 2 adults and 3 nights starting in 30 days:
{"location": "Paris, France","propertyTypes": ["hotels"],"starRatings": [4, 5],"minReviewScore": 8,"priceMax": 250,"freeCancellation": true,"checkInDaysFromNow": 30,"nights": 3,"adults": 2,"currency": "EUR","maxResults": 50}
This input sends ht_id=204;class=4;class=5;review_score=80;price=EUR-0-250-1;fc=2 to Booking.com.
- Several filters combine like on the website: several values of the same filter add up (4 or 5 stars, hotels or apartments), different filters narrow the search (4 or 5 stars and rated 8+).
- With
filtersand search URLs. The fields are added, without duplicates, to thefiltersstring (for any other Booking.com filter) and to thenfltfilters of every pasted search URL. A URL keeps its own price range and minimum score when it already has one, and the log names the field value left out; the same price range or minimum score given twice in the form with two different values (in the fields and infilters) is refused before the run starts. - Prices are per night, in
currencyor in the currency of a pasted URL, whole amounts, like Booking.com's budget filter;priceTotalin the output is the total of the stay. - To confirm at the first run. Hotels only (
ht_id=204) is the filter validated in our tests; the other values are Booking.com's own filter values, sent as they are. The start line of the run log lists the filters each search sends and the ones not verified yet (filterFields). Check the stars, scores and types of the first rows; if a filter seems ignored, open an issue with your run id. - Empty fields change nothing: with no filter field set, the requests, the rows and the charges are those of a run without them.
Search URLs
Set the destination, dates, guests, sort order and filters on Booking.com, then paste the URL of the results page into startUrls. The Actor converts the parameters it knows to its own search: ss, dest_id and dest_type (destination), checkin and checkout (dates), group_adults, group_children and age (guests), no_rooms (rooms), order (sort), nflt (filters), selected_currency and lang. What a URL does not carry comes from the form: a URL without dates uses the relative dates (checkInDaysFromNow, nights), so a scheduled task made of URLs never expires; the filter fields of the form are added to the URL's nflt filters (see Filters). Tracking parameters are ignored; other unknown parameters are listed in the run log. A URL that is not a Booking.com results page (a property page, the home page, another site) or that names no destination is refused before the run starts, with the reason. Several URLs run one after the other in the same dataset; the form destination runs too when you keep one.
Price monitoring
Tick monitorPrices, then schedule the run (daily is typical). The scraper keeps the last total price of every property it compared in a key-value store of your account named monitorStoreName (booking-price-monitor by default), with one record per search (same destination, stay, guests, rooms, sort, filters, currency and language). The first run of a search is the reference: every property comes back with changeType = "new" (and RUN_STATS.monitorBaseline is true). From the second run on, every property is compared with the recorded one: price_changed rows carry previousPrice (the previous total of the stay), priceDelta and priceDeltaPercent, the others are unchanged. With onlyChanges the dataset holds only the new properties and the price changes, and only those rows are charged; a run where nothing changed succeeds with an empty dataset. In both cases maxResults is the number of properties compared by the run.
A scheduled input that watches the 100 top-pick Lisbon hotels for a stay one month ahead:
{"location": "Lisbon, Portugal","destId": -2167973,"filters": "ht_id=204","checkInDaysFromNow": 30,"nights": 3,"adults": 2,"currency": "EUR","maxResults": 100,"monitorPrices": true,"onlyChanges": true}
A price_changed row, as the Actor produces it from the row of the output example when the previous run had recorded a total of 699 EUR (the other columns are the same as above):
{"platformListingId": "2628938","title": "Villa Baixa - Lisbon Luxury Apartments","checkIn": "2026-11-20","checkOut": "2026-11-23","currency": "EUR","priceTotal": 637.43,"changeType": "price_changed","previousPrice": 699,"priceDelta": -61.57,"priceDeltaPercent": -8.8}
What to know before relying on it:
- Fixed dates compare one stay; relative dates compare a lead time. With
checkIn/checkOut, the record follows the price of that stay until it passes. With relative dates (the default), the record follows the price of the stay N days ahead for M nights: each run searches new dates, so a change mixes the hotel's pricing and the calendar (weekday, season). Both are useful; just know which one you track. ChangingcheckInDaysFromNowornightsstarts a new reference. - The record is written only after a clean run. A blocked or failed search, an unresolved destination, a charge limit reached in the middle of a run or an interrupted run never overwrites the reference, so a bad day cannot erase your prices; the log says when a record was kept unchanged.
- Same currency only. A price is compared only with a previous total in the same currency; when Booking.com answers in another currency, the property is reported
unchangedand the new currency becomes the reference. - Rankings move. Booking.com's top-picks order varies between sessions, so the set of compared properties (the first
maxResultsof the run) drifts a little from run to run; a property that drops out of the results and comes back later is not reported as new (its last price is kept for 90 days). Sort bypriceor narrow the search withfiltersfor a steadier set. - One record per search. Runs sharing a
monitorStoreNameshare the records; changing the destination, stay, guests, rooms, sort, filters, currency or language of a search starts a new reference for it. Each destination oflocationshas its own record; keep the same list, in the same order, from run to run, since a property found by two destinations is compared under the first one. Delete the key-value store in Apify Console to start over.
How much does it cost to scrape Booking.com?
This Actor uses pay-per-event pricing: you pay a fixed price per property saved to your dataset, and nothing else. On the Free plan, properties cost $2.50 per 1,000, so Apify's free monthly credit of $5 covers about 1,999 properties; paid plans pay less per property, and the price of every plan tier is on the Pricing tab of this page.
| What you pay for | How it is counted | Price |
|---|---|---|
result event: one property saved to your dataset | once per unique property of the run, capped by maxResults (per destination with locations) | Pricing tab, per plan tier |
| Run start | a symbolic amount, once per run | Pricing tab |
| Compute, proxies, storage and data transfer | included: no platform usage is passed on to you | — |
The cost of a run is known before you start: 1,000 properties cost 1,000 times the result price of your tier, whatever the number of pages fetched. In price-monitoring mode with onlyChanges, only the new properties and the price changes are charged. One request returns 100 properties in about a second, so a run of several hundred properties takes well under a minute.
Limits and behaviour worth knowing
- One stay per search. Every row of a search shares the same
checkIn,checkOut,guestsandcurrency, which is what makes prices comparable; with several destinations (locations) or search URLs, each one is its own search in the same dataset (searchLocationtells them apart). Schedule several tasks if you prefer separate datasets. - About 1,000 properties per search. Booking.com announces thousands of results for a big city but serves a limited depth per search; the scraper stops at the first empty page and reports it in the log. Narrow the search with the filters (
propertyTypes,starRatings,minReviewScore,priceMin/priceMax) or use district destination ids to cover a whole city. priceTotalis the total of the stay for the unit Booking.com matched to your guests and rooms, after discounts and before the charges Booking.com lists as excluded (taxesAndFees: city tax, VAT or service charges depending on the destination);priceTotalAllInadds them back.pricePerNightis the average per night (priceTotal / nights).priceBeforeDiscountis the strike-through total of a deal.- Rankings move and sponsored cards appear. Booking.com's top-picks order varies between sessions and a sponsored property can be added on top of a page. The scraper keeps one session per search, removes duplicates by property id and counts sponsored cards in the run statistics. The
priceorder is exact. - Text destinations are resolved by Booking.com: without the filters (they apply to the search itself), then through Booking.com's suggestions for the full text and for the city alone, with a few retries when an answer is empty or in error. When the text is still not recognised, the run fails with an explicit message asking for
destId. Thedest_idof a Booking.com search URL always works. - Search cards show a subset of the property. Amenities, maximum guests, room-level cancellation terms beyond the free-cancellation flag and the full photo gallery are not in search results and are therefore
nullor empty. Property pages and availability calendars are not covered by this Actor. - Blocking. The Booking.com search API answered every request from Apify datacenter proxies in our tests. If a response is unusable, the scraper opens a new session and retries once, then gives up on that search and reports it. If a whole run is blocked, raise
delayMsand try again later, or open an issue with your run id: blocking changes are fixed as a priority. - No empty successes. A run that finds no property ends as failed with an explicit message (destination not recognised, dates in the past, filters too strict, or blocked), so that your schedules and integrations notice. The one exception is a price-monitoring run that compared properties and found no change: it succeeds with an empty dataset.
Integrations and API
Start the Actor from Apify Console, schedule it, or call it from the Apify API with any language (the API tab shows ready-made code for Node.js, Python and curl). Webhooks notify your systems when a run finishes; the dataset can be pulled as JSON, CSV, Excel, XML or RSS from the run's Output tab, or pushed to Google Sheets, Make, Zapier, n8n, Slack, Airtable, Google Drive and more through the Apify integrations. AI agents can call the Actor through the Apify MCP server.
For bugs or questions, open an issue in the Issues tab of this Actor with your run id and input: bugs and API changes are fixed as a priority, feature requests (property details, availability calendars, other platforms of the travel studio) are welcome.
Use it from your AI assistant
Add this Actor as a tool to Claude, ChatGPT, Cursor, VS Code or any MCP client with the Apify MCP server URL below (sign in with your Apify account when asked):
https://mcp.apify.com?tools=myth84/booking-hotels-scraper
Then ask in plain words. Copy this prompt and change the details:
Use myth84/booking-hotels-scraper to find 20 hotels in Rome, Italy for 2 adults, 2 nights starting 30 days from today, prices in EUR, cheapest first. Input: {"location": "Rome, Italy", "checkInDaysFromNow": 30, "nights": 2, "adults": 2, "currency": "EUR", "sortBy": "price", "propertyTypes": ["hotels"], "maxResults": 20}. Show the name, total price, excluded taxes, review score, number of reviews and link of each hotel.
For AI agents (MCP)
Through the Apify MCP server this Actor is a tool that answers questions such as "what do hotels in Lisbon cost for two adults from 20 to 23 November?", "list the best-reviewed 4-star hotels in Paris under 200 EUR a night" or "compare hotel prices in Barcelona and Valencia next month".
Minimal input (one or more destinations in locations, maxResults per destination; every other field keeps its default, raise maxResults only when the question needs more rows):
{"locations": ["Barcelona, Spain", "Valencia, Spain"],"checkInDaysFromNow": 30,"nights": 2,"adults": 2,"currency": "EUR","maxResults": 20}
- Key output fields:
platformListingId,title,url,priceTotal,pricePerNight,taxesAndFees,currency,rating(on 10),reviewCount,starRating,propertyType,region,latitude/longitude,cancellationPolicy; in monitoring modechangeType,previousPrice,priceDelta. Every column is always present, in a fixed order;nullmeans Booking.com did not show the value. The full list is in What data does Booking.com Scraper extract? above. - Use it when you need current Booking.com search results for a destination and a stay: total prices, taxes, review scores, review counts, stars, type, location, photo. Pass
locations(one or more destinations, searched one by one,maxResultseach) orlocation(ordestId), the dates (checkIn/checkOut, orcheckInDaysFromNow+nights),adults,childrenwithchildrenAges,currency, optionallysortByand the filters (propertyTypes,starRatings,minReviewScore,priceMin/priceMax,freeCancellation,breakfastIncluded, or a rawfiltersstring), and a smallmaxResults(10–50 is enough for an answer); or pass a Booking.com results URL instartUrls. To report price changes between two calls, passmonitorPrices: true,onlyChanges: trueand the same search andmonitorStoreName. - Do not use it for guest reviews, property descriptions and amenities, availability calendars, booking or anything behind a login: it does not collect personal data and only reads public search results.
- Cost per 1,000 results: 1,000
resultevents, $2.50 per 1,000 on the Free plan and less on paid plans (Pricing tab); nothing else is charged (in monitoring mode withonlyChanges, unchanged prices are free). - Typical time: about a second per request of 100 properties: 20 properties in a few seconds, several hundred in well under a minute.
Alternatives and switching
- Official API. Booking.com's APIs are made for its accommodation and affiliate partners and need an approved partner account; if you have one and need bookings or contracted rates, use it. This Actor reads what any visitor sees in Booking.com search results (public prices, excluded taxes, review scores, stars) with no account, no keys and no approval.
- Your own scraper. Nothing to build or maintain: sessions, retries, pagination, deduplication and Booking.com page changes are handled for you. The columns stay the same from run to run, a run that finds nothing fails with an explicit message instead of succeeding empty, and a scheduled test run catches Booking.com changes early.
- Another scraper from the Store. What you can count on here:
maxResultsis a hard cap (per destination withlocations), the run stops at that number of properties and you are never charged for more; withmonitorPricesandonlyChanges, a scheduled run returns and charges only the new properties and the price changes;priceTotalAllIngives one total, taxes included, to compare with the other platforms. The input names differ from one Actor to the next; the usual ones map to this Actor as follows:
| Usual input | Here | Note |
|---|---|---|
search, query, destination | location, locations for up to 50 places, or destId | Text as typed on Booking.com, or the exact dest_id |
startUrls | startUrls | Booking.com search results URLs, filters included |
maxItems, limit | maxResults | Unique properties per run, never charged beyond |
checkin, checkout | checkIn, checkOut | YYYY-MM-DD; or checkInDaysFromNow + nights for schedules |
adults, children, rooms | adults, children + childrenAges, rooms | Prices depend on them |
minScore | minReviewScore | 6, 7, 8 or 9 out of 10 |
stars, starsCountFilter | starRatings | A list, e.g. [4, 5] |
propertyType | propertyTypes | A list, e.g. ["hotels", "apartments"] |
minMaxPrice, minPrice, maxPrice | priceMin, priceMax | Per night, in the currency of the search |
nflt | filters | Any other Booking.com filter string, e.g. ht_id=204 |
sort | sortBy | popularity or price |
currency, language | currency, language | ISO 4217 code, Booking.com language code |
proxy | proxyConfiguration | Apify proxies, included in the price |
FAQ
Does Booking.com Scraper collect personal data?
No. The scraper reads search result cards only and keeps nothing about guests or reviewers: no names, photos, profile ids, contact details or review texts. It outputs property facts (business names and addresses at the neighbourhood level), the average review score and the number of reviews. Every row goes through a privacy filter before it is saved.
Is it legal to scrape Booking.com?
The Actor only reads search results that Booking.com serves to any visitor without an account, and it stores no personal data. Scraping public data is generally lawful, but you are responsible for how you use the results and for complying with Booking.com's terms of service and the laws that apply to you (including copyright on property texts and photos). Use the data for analysis, not to republish listings.
Why are the prices different from what I see in my browser?
Prices depend on the stay (dates, adults, children ages, rooms), the currency and the moment: Booking.com runs time-limited deals and member rates (never used here: no login). Compare rows obtained with the same input, and check taxesAndFees: Booking.com shows some charges excluded from the headline price, and priceTotalAllIn is the total with them.
What if my runs get blocked? Do I need proxies?
Apify datacenter proxies (the default) worked for every request in our tests and are included in the price. If a run reports blocked requests, increase delayMs and try again later, or bring your own proxy URLs; persistent blocking is fixed as a priority, open an issue with your run id.
How do I get more than 1,000 properties for a city, or fewer duplicates?
Booking.com limits the depth of one search. Split the city: one run per accommodation type (propertyTypes), per star rating (starRatings) or per price range (priceMin / priceMax), or one run per district with its destId. Across runs, deduplicate by platformListingId; inside a run the scraper already does it.
Can I search several cities in one run?
Yes. Put up to 50 destinations in locations, one per line ("Paris, France", "Rome, Italy", "Barcelona, Spain"…), alongside or instead of location. Each destination is a separate search with the same dates, guests, rooms, filters and currency, and maxResults applies to each destination: 3 cities with maxResults 50 give up to 150 properties. Every row says in searchLocation which destination found it, and a property found by two destinations is saved and charged once. Large lists need more requests: raise maxRequests if the log says that some destinations were not searched.
Which currencies, languages and dates can I use?
Any currency Booking.com accepts (currency, ISO 4217 code; EUR and USD validated) and any Booking.com language code (language; en-us validated). Prices are converted by Booking.com into the requested currency; property types, neighbourhoods and badges come in the requested language. For dates, give checkIn and checkOut for a quote on precise dates, or leave them empty: the Actor then searches a stay starting checkInDaysFromNow days from today for nights nights (relative dates), so that a scheduled run or an example task never expires.
The run says the location could not be resolved. What should I do?
The Actor asks Booking.com to recognise your destination text, and tries again on its own when an answer comes back empty or in error; the reason of each attempt is in the log. If the run still fails, run it again a few minutes later, write the destination as "City, Country" (for example "Rome, Italy"), or, for a result that never depends on the text, give destId: open a Booking.com search for the place in your browser and copy the dest_id (and dest_type) of the URL, or paste the whole URL into startUrls. A destination Booking.com does not know at all ends with the same message after the retries.
Which filters are supported? Can I use a Booking.com search URL?
The form has a field for the filters most people use: property types (propertyTypes), star ratings (starRatings), minimum review score (minReviewScore), price per night (priceMin / priceMax), free cancellation (freeCancellation) and breakfast included (breakfastIncluded); Filters above shows what each one sends. Hotels only is validated; the other values are Booking.com's own filter values, to confirm at the first run, and the run log lists them. For any other filter of the website, copy the nflt parameter of a Booking.com search URL into filters (several filters separated by ;), or paste the whole URL into startUrls: its destination, dates, guests, rooms, sort order, nflt filters, currency and language are used as they are, the form fills what the URL does not set (relative dates when it has none), and the filter fields are added to the URL's filters without duplicates.
How often should I run it, and how do I get only price changes?
Every run fetches live search results. Prices and availability change daily, so schedule the Actor as often as your use case needs (daily is typical for price tracking) and compare runs by platformListingId, checkIn and checkOut, or let the Actor compare them for you: tick monitorPrices (and onlyChanges) and schedule the run. The first run records every property of the search and returns it as new; each later run flags the properties that appeared since and the properties whose total price changed, with previousPrice, priceDelta and priceDeltaPercent, and with onlyChanges returns and charges only those rows. A run without any change succeeds with an empty dataset. The previous prices live in the key-value store monitorStoreName of your account; keep the same destination, stay, guests, sort, filters, currency and language from run to run. With relative dates you follow the price of a stay at a constant lead time; with fixed dates, the price of one stay.
More scrapers by Flatrow Data Studio
The travel scrapers of the studio share the same core columns, so stays from several platforms land in one table; compare their prices on priceTotalAllIn, the total of the stay with taxes and fees, filled with the same rule by each scraper (null when a platform does not show the taxes):
- Airbnb Listings Scraper & Price Tracker: Airbnb prices, ratings, review counts and locations for any place and dates, up to 50 destinations per run, with price monitoring.
- Airbnb Listing Details & Availability Calendar: amenities, house rules, six category ratings and a 1–12 month availability calendar for the Airbnb listing URLs you give.
- Expedia Hotels Scraper: Prices & Ratings: Expedia hotel prices per night and for the whole stay, guest ratings and review counts, to compare with the other platforms.
Did this scraper give you the data you needed? A rating on its Store page helps other people find it. For a bug or a missing field, open an issue in the Issues tab.
Legal note
This Actor reads publicly available Booking.com search results without logging in and collects no personal data. You are responsible for your use of the data and for complying with Booking.com's terms and the laws that apply to you.
Not affiliated with, endorsed or sponsored by Booking.com. Booking.com is a trademark of Booking.com B.V.