How to use Booking.com Hotel Prices Scraper
Step by step: in the Apify Store, over the API, from JavaScript or Python, in n8n, and from AI agents through MCP or LangChain.
$2.70 per 1,000 price rows on the Free plan, down to $2.58 on higher plans (live Apify price on 2026-11-01).
1. In the Apify Store (no code)
- Open arcadium/booking-prices and sign in to Apify (a free account works).
- Fill in the input form. The fields below are the ones the example uses.
- Set a maximum cost per run in the run options if you want a hard cap.
- Start the run. Rows appear in the Output tab as they arrive.
- Export the dataset as JSON, CSV or Excel, or connect an integration.
| Input field | Type | Description |
|---|---|---|
startUrls | array | Booking.com hotel page links, for example https://www.booking.com/hotel/fr/de-la-paix-paris1.html. Each hotel gets one row per check-in date and nights value, with every room rate for the date. Optional when you use hotel ids or destinations. Booking.com search-result links (searchresults.html?ss=...) are read as a destination. |
destinationType | string | Only used when a destination is a numeric Booking.com id: whether the id is a city, region, country, district, landmark or airport. Names are resolved automatically. |
maxHotels | integer | How many hotels to return for each destination and check-in date (1 to 1,000, the most the site returns per search). Sold-out hotels are skipped unless 'Include sold-out hotels' is on. Example: 50. Also accepted as maxItems or maxResults (0 = 1,000). |
checkInDates | array | Check-in dates as YYYY-MM-DD, or relative to today such as "+30d" (30 days from now) or "tomorrow". Example: ["2026-12-10", "+45d"]. Dates up to about 16 months ahead. If this and the range below are empty, one stay 30 days from now is used. Also accepted as checkIn + checkOut (voyager, '2 weeks' style dates work) or checkin + checkout. |
nights | array | Lengths of stay in nights, for example [1, 3, 7]. Each value gives its own row per hotel and check-in date. Up to 30 nights. |
childrenAges | array | Age (0-17) of each child, for example [5, 9]. Prices depend on the number and ages of children. Leave empty for none. |
currency | string | Three-letter currency code for all prices, for example EUR, USD or GBP. Booking.com converts the prices. |
includeRoomRates | boolean | Destination searches return the cheapest rate of each hotel. Turn on to also read every room rate of each hotel (one extra request per hotel and date, same price per row). |
watch | boolean | Compare every hotel x stay row with the last run that used the same watch key and output only new rows and rows whose availability, price, meal plan, cancellation or room rates changed, each with a change object (type, fields old -> new, priceChange). Unchanged rows are not output and not charged; one free watch-summary row counts unchanged, changed, new and gone. The first run is a normal run, charged normally. |
watchKey | string | Name of the saved snapshot for watch mode (letters, digits, - and _, up to 60). Use one key per monitored hotel and date list, for example "weekly-check". A new key starts a new baseline. The snapshot is kept in a key-value store in your account. |
digest | boolean | Watch mode only. Adds one free watch-digest row per run that sums up the changes of the last digest days for this watch key: counts by change type, price drops and rises, availability changes, the biggest price moves, and a one-line plain-text summary you can paste into an email or Slack. No extra charge. |
digestDays | integer | How many days the digest row covers (rolling window, 1-90). Runs older than this drop out of the digest. |
Example input:
{
"startUrls": [
{
"url": "https://www.booking.com/hotel/fr/de-la-paix-paris1.html"
}
],
"destinationType": "CITY",
"maxHotels": 20,
"checkInDates": [
"+30d"
],
"nights": [
1
],
"childrenAges": [],
"currency": "EUR",
"includeRoomRates": false,
"watch": false,
"watchKey": "default",
"digest": false,
"digestDays": 7
}
2. Over the Apify API
The synchronous endpoint runs the actor and returns its rows in one call (for runs up to about five minutes; use the asynchronous run endpoint for longer ones).
curl -X POST "https://api.apify.com/v2/acts/arcadium~booking-prices/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"startUrls":[{"url":"https://www.booking.com/hotel/fr/de-la-paix-paris1.html"}],"destinationType":"CITY","maxHotels":20,"checkInDates":["+30d"],"nights":[1],"childrenAges":[],"currency":"EUR","includeRoomRates":false,"watch":false,"watchKey":"default","digest":false,"digestDays":7}'
3. From JavaScript
// npm install apify-client
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('arcadium/booking-prices').call({
"startUrls": [
{
"url": "https://www.booking.com/hotel/fr/de-la-paix-paris1.html"
}
],
"destinationType": "CITY",
"maxHotels": 20,
"checkInDates": [
"+30d"
],
"nights": [
1
],
"childrenAges": [],
"currency": "EUR",
"includeRoomRates": false,
"watch": false,
"watchKey": "default",
"digest": false,
"digestDays": 7
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
4. From Python
# pip install apify-client
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arcadium/booking-prices").call(run_input={
"startUrls": [{
"url": "https://www.booking.com/hotel/fr/de-la-paix-paris1.html",
}],
"destinationType": "CITY",
"maxHotels": 20,
"checkInDates": ["+30d"],
"nights": [1],
"childrenAges": [],
"currency": "EUR",
"includeRoomRates": False,
"watch": False,
"watchKey": "default",
"digest": False,
"digestDays": 7,
})
items = client.dataset(run.default_dataset_id).list_items().items # apify-client 3.x returns a Run object
print(items)
5. In n8n
Paste this node into a workflow (it is a plain HTTP Request node). Create a Header Auth credential with name Authorization and value Bearer <APIFY_TOKEN>; each returned row becomes one item for the next node.
{
"nodes": [
{
"name": "Run arcadium/booking-prices",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
0,
0
],
"parameters": {
"method": "POST",
"url": "https://api.apify.com/v2/acts/arcadium~booking-prices/run-sync-get-dataset-items",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "{\"startUrls\":[{\"url\":\"https://www.booking.com/hotel/fr/de-la-paix-paris1.html\"}],\"destinationType\":\"CITY\",\"maxHotels\":20,\"checkInDates\":[\"+30d\"],\"nights\":[1],\"childrenAges\":[],\"currency\":\"EUR\",\"includeRoomRates\":false,\"watch\":false,\"watchKey\":\"default\",\"digest\":false,\"digestDays\":7}",
"options": {
"timeout": 300000
}
}
}
],
"connections": {}
}
6. From an AI assistant (MCP)
Add Apify’s MCP server to Claude Desktop, Cursor, VS Code or any MCP client, limited to this actor:
{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com/?tools=arcadium/booking-prices",
"headers": {
"Authorization": "Bearer <APIFY_TOKEN>"
}
}
}
}
More on the MCP page.
7. From LangChain
# pip install langchain-apify (reads APIFY_API_TOKEN from the environment)
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("arcadium/booking-prices")
rows = tool.invoke({"run_input": {
"startUrls": [{
"url": "https://www.booking.com/hotel/fr/de-la-paix-paris1.html",
}],
"destinationType": "CITY",
"maxHotels": 20,
"checkInDates": ["+30d"],
"nights": [1],
"childrenAges": [],
"currency": "EUR",
"includeRoomRates": False,
"watch": False,
"watchKey": "default",
"digest": False,
"digestDays": 7,
}})
# or give `tool` to an agent: create_react_agent(llm, [tool])
Sample output
One row, from the example in the actor’s README. Long text is shortened and lists are cut to two items.
{
"rowType": "price",
"platform": "booking",
"hotelId": "55103",
"hotelName": "Hôtel De La Paix",
"hotelUrl": "https://www.booking.com/hotel/fr/de-la-paix-paris1.html",
"stars": 3,
"reviewScore": 8.5,
"reviewCount": 2112,
"city": "Paris",
"countryCode": "fr",
"checkIn": "2026-12-10",
"checkOut": "2026-12-12",
"nights": 2,
"adults": 2,
"children": 0,
"rooms": 1,
"currency": "EUR",
"available": true,
"soldOut": false,
"minPrice": 236.73,
"minPricePerNight": 118.37,
"originalPrice": 338.18,
"taxesAndFeesExcluded": 45.79,
"mealPlan": "ROOM_ONLY",
"freeCancellation": false,
"cancellationPolicy": "non_refundable",
"cheapestRoom": "Standard Double Room",
"roomRates": [
{
"roomName": "Standard Double Room",
"mealPlan": "ROOM_ONLY",
"price": 236.73,
"pricePerNight": 118.37,
"cancellation": "non_refundable",
"cancellationText": "Non-refundable",
"payment": "prepayment_required"
}
],
"rateCount": 12,
"source": "roomTable",
"scrapedAt": "2026-10-21T08:00:00.000Z"
}
| Field | What it holds |
|---|---|
rowType | Kind of row. Filter on this first. 'price': one hotel for one stay (charged). 'error': an input could not be read; see code and message (free). |
hotelId | Booking.com numeric id of the hotel. |
hotelName | Name of the hotel as shown on Booking.com. |
hotelUrl | Link to the hotel page on Booking.com. |
stars | Star rating of the hotel (1-5), null when not rated. |
reviewScore | Guest review score on the 0-10 scale. |
reviewCount | Number of guest reviews behind the score. |
city | City of the hotel. |
countryCode | Two-letter country code of the hotel, lower case. |
checkIn | Check-in date of the stay, YYYY-MM-DD. |
checkOut | Check-out date of the stay, YYYY-MM-DD. |
nights | Length of the stay in nights. |
adults | Adult guests the price is for. |
children | Number of children the price is for. |
rooms | Number of rooms the price is for. |
currency | Three-letter currency code of every price in the row. |
available | True when the hotel can be booked for the stay. |
soldOut | True when Booking.com had no rate for the stay; such a row has no price. |
minPrice | Cheapest total price for the whole stay and all rooms, in the row currency. |
minPricePerNight | Cheapest price per night, in the row currency. |
originalPrice | The same rate before discounts, when the site shows one. |
taxesAndFeesExcluded | Taxes and fees the site lists on top of the price, in the row currency. |
mealPlan | Meal plan of the cheapest rate, for example ROOM_ONLY, BREAKFAST or HALF_BOARD. |
freeCancellation | True when the cheapest rate can be cancelled for free. |
cancellationPolicy | Cancellation of the cheapest rate: free_cancellation or non_refundable. |
cheapestRoom | Name of the room the cheapest rate is for. |
roomRates | Every rate for the stay, cheapest first: room, meal plan, price, per night, taxes, cancellation, payment. |
rateCount | Number of rates found for the stay. |
source | Where the rates come from: roomTable (every rate) or search (cheapest rate of each hotel). |
searchDestination | Destination searches: the destination text you gave. |
searchRank | Destination searches: position of the hotel in the results. |
change | Change-only mode: object with type, previousMinPrice and priceChange since the last run. |
scrapedAt | ISO timestamp of when the row was read. |
code | Error rows: machine-readable error code. |
message | Error rows: short explanation of what could not be read. |
Tutorials
Schedule it
In Apify Console, create a Task from your input and add a Schedule (for example daily). Each run writes a new dataset; integrations can push the rows to Google Sheets, Slack, a webhook or your database.