Booking.com Hotels Scraper & Price Tracker avatar

Booking.com Hotels Scraper & Price Tracker

Pricing

from $1.69 / 1,000 properties

Go to Apify Store
Booking.com Hotels Scraper & Price Tracker

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

Flatrow Data Studio

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 hours ago

Last modified

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; maxResults caps 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 monitorPrices and onlyChanges, 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.

GroupColumns
IdentityschemaVersion, platform, platformListingId, url, title, propertyType, roomType
Locationcity, region, country, countryCode, latitude, longitude
StaycheckIn, checkOut, nights, guests, isAvailable
Pricescurrency, pricePerNight, priceTotal, priceBeforeDiscount, taxesAndFees, taxesIncluded, priceTotalAllIn, cleaningFee, serviceFee
Qualityrating, ratingMax, reviewCount, starRating, badges, isSuperhost, isNew, listedBy, cancellationPolicy, instantBook
Sizebedrooms, beds, bathrooms, maxGuests, amenities
PhotosimageUrls, imageCount
Search contextsearchLocation, searchRank, searchPage, viewCountryCode, scrapedAt
Price monitoringchangeType, 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

  1. 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 the dest_id from a Booking.com search URL into Destination id: that path is always reliable.
  2. 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.
  3. 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.
  4. 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.
  5. To follow prices, schedule the run, tick monitorPrices and, 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:

FieldTypeDefaultDescription
locationsstring[][]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.
locationstring—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.
destIdinteger—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.
destTypestring"CITY"Type of the destination id (dest_type of the URL): CITY, DISTRICT, REGION, COUNTRY, LANDMARK, AIRPORT, HOTEL. CITY is validated.
startUrlsstring[][]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.
checkInstring—Check-in date, YYYY-MM-DD. Leave both dates empty to use relative dates.
checkOutstring—Check-out date, YYYY-MM-DD, after check-in. Required when checkIn is set.
checkInDaysFromNowinteger30Without fixed dates: check-in this many days from today (UTC).
nightsinteger3Without fixed dates: length of the stay.
adultsinteger2Number of adults.
childreninteger0Number of children (0–17).
childrenAgesinteger[][]Age of each child; a child without a listed age counts as 8 years old.
roomsinteger1Number of rooms (units).
maxResultsinteger100Stop 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.
sortBystring"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.
propertyTypesstring[][]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.
starRatingsinteger[][]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.
minReviewScoreinteger—Minimum guest review score out of 10: 6, 7, 8 or 9. To confirm at the first run.
priceMininteger—Lowest price per night, in the currency of the search (whole amount, 0 to 1,000,000,000). To confirm at the first run.
priceMaxinteger—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.
freeCancellationbooleanfalseOnly properties offering free cancellation. To confirm at the first run.
breakfastIncludedbooleanfalseOnly properties with breakfast included. To confirm at the first run.
filtersstring—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.
currencystring"EUR"ISO 4217 code of the currency of every price (EUR and USD validated, any Booking.com currency accepted).
languagestring"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).
monitorPricesbooleanfalseCompare the total price of every property with the one recorded by your previous run of the same search (changeType, previousPrice, priceDelta, priceDeltaPercent).
monitorStoreNamestring"booking-price-monitor"Key-value store of your account that keeps the previous prices (one record per search). Letters, digits and dashes.
onlyChangesbooleanfalseWith monitorPrices: save and charge only the new properties and the price changes; a run without any change succeeds with an empty dataset.
proxyConfigurationobject{"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.
maxRequestsinteger100Safety 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).
delayMsinteger800Pause between two page requests of the same search, in milliseconds.
debugStoreHtmlbooleanfalseDebugging 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.

FieldBooking.com filterSent to Booking.com asStatus
propertyTypesProperty 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 homestayshotels validated; the other types to confirm at the first run
starRatingsProperty rating (several ratings add up)class=4;class=5 for [4, 5]to confirm at the first run
minReviewScoreReview score: 6+, 7+, 8+ or 9+ out of 10review_score=80 for 8to confirm at the first run
priceMin, priceMaxYour budget, per night, in the currency of the searchprice=EUR-50-150-1 for 50 to 150 EUR (an open bound is sent as 0 or max)to confirm at the first run
freeCancellationFree cancellationfc=2to confirm at the first run
breakfastIncludedBreakfast includedmealplan=1to 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 filters and search URLs. The fields are added, without duplicates, to the filters string (for any other Booking.com filter) and to the nflt filters 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 in filters) is refused before the run starts.
  • Prices are per night, in currency or in the currency of a pasted URL, whole amounts, like Booking.com's budget filter; priceTotal in 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. Changing checkInDaysFromNow or nights starts 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 unchanged and 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 maxResults of 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 by price or narrow the search with filters for a steadier set.
  • One record per search. Runs sharing a monitorStoreName share the records; changing the destination, stay, guests, rooms, sort, filters, currency or language of a search starts a new reference for it. Each destination of locations has 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 forHow it is countedPrice
result event: one property saved to your datasetonce per unique property of the run, capped by maxResults (per destination with locations)Pricing tab, per plan tier
Run starta symbolic amount, once per runPricing tab
Compute, proxies, storage and data transferincluded: 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, guests and currency, which is what makes prices comparable; with several destinations (locations) or search URLs, each one is its own search in the same dataset (searchLocation tells 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.
  • priceTotal is 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); priceTotalAllIn adds them back. pricePerNight is the average per night (priceTotal / nights). priceBeforeDiscount is 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 price order 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. The dest_id of 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 null or 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 delayMs and 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 mode changeType, previousPrice, priceDelta. Every column is always present, in a fixed order; null means 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, maxResults each) or location (or destId), the dates (checkIn / checkOut, or checkInDaysFromNow + nights), adults, children with childrenAges, currency, optionally sortBy and the filters (propertyTypes, starRatings, minReviewScore, priceMin / priceMax, freeCancellation, breakfastIncluded, or a raw filters string), and a small maxResults (10–50 is enough for an answer); or pass a Booking.com results URL in startUrls. To report price changes between two calls, pass monitorPrices: true, onlyChanges: true and the same search and monitorStoreName.
  • 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 result events, $2.50 per 1,000 on the Free plan and less on paid plans (Pricing tab); nothing else is charged (in monitoring mode with onlyChanges, 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: maxResults is a hard cap (per destination with locations), the run stops at that number of properties and you are never charged for more; with monitorPrices and onlyChanges, a scheduled run returns and charges only the new properties and the price changes; priceTotalAllIn gives 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 inputHereNote
search, query, destinationlocation, locations for up to 50 places, or destIdText as typed on Booking.com, or the exact dest_id
startUrlsstartUrlsBooking.com search results URLs, filters included
maxItems, limitmaxResultsUnique properties per run, never charged beyond
checkin, checkoutcheckIn, checkOutYYYY-MM-DD; or checkInDaysFromNow + nights for schedules
adults, children, roomsadults, children + childrenAges, roomsPrices depend on them
minScoreminReviewScore6, 7, 8 or 9 out of 10
stars, starsCountFilterstarRatingsA list, e.g. [4, 5]
propertyTypepropertyTypesA list, e.g. ["hotels", "apartments"]
minMaxPrice, minPrice, maxPricepriceMin, priceMaxPer night, in the currency of the search
nfltfiltersAny other Booking.com filter string, e.g. ht_id=204
sortsortBypopularity or price
currency, languagecurrency, languageISO 4217 code, Booking.com language code
proxyproxyConfigurationApify 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.

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):

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.

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.