Monitor Booking.com hotel prices and get only the changes
A revenue manager or a traveller watching a few hotels needs to know when a price moves, not a full price list every morning. Full daily scrapes cost more and bury the changes.
arcadium/booking-prices reads the public price of each hotel for each check-in date and length of stay. In watch mode it compares with the previous run under the same watch key and delivers only rows that are new or whose price, availability or room rates changed. Unchanged rows are not delivered and not charged.
Cost of this example on the Apify Free plan: 5 × $0.0027 = $0.0135 ($0.0129 on the Apify Gold plan and higher), plus $0.001 per GB of memory when the run starts.
What you need
- An Apify account and API token.
- The Booking.com page links (or numeric hotel ids) of the hotels you watch.
Step 1: Run it in the Apify Store (no code)
- Open arcadium/booking-prices on the Apify Store and sign in (a free Apify account works).
- Paste the hotel links into Hotel links.
- Set Check-in range: from to
+7d, to+37dand step (days) to 7, and Nights to 2: five check-in dates per hotel. - Turn on Watch mode: pay only for changes and give it a Watch key such as
paris-watch. - Save the input as a task and add a daily schedule (Console, Saved tasks, Schedule).
- Optional: set a maximum cost per run in the run options as a hard cap.
- Click Start. Rows appear in the Output tab; export them as JSON, CSV or Excel.
The same input as JSON (paste it in the JSON tab of the input form):
{
"startUrls": [
{
"url": "https://www.booking.com/hotel/fr/de-la-paix-paris1.html"
}
],
"checkInFrom": "+7d",
"checkInTo": "+37d",
"checkInStepDays": 7,
"nights": [
2
],
"adults": 2,
"currency": "EUR",
"watch": true,
"watchKey": "paris-watch"
}
Step 2: Call it over the Apify API
One HTTP call runs the actor and returns its rows. It suits runs up to about five minutes; for longer runs start the run asynchronously and read the dataset when it finishes.
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"}],"checkInFrom":"+7d","checkInTo":"+37d","checkInStepDays":7,"nights":[2],"adults":2,"currency":"EUR","watch":true,"watchKey":"paris-watch"}'
Step 3: Run it from Python
With apify-client 3.x, call() returns a Run object: read the dataset id as run.default_dataset_id (older examples use run["defaultDatasetId"], which no longer works).
# pip install "apify-client>=3"
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"}],
"checkInFrom": "+7d", "checkInTo": "+37d", "checkInStepDays": 7,
"nights": [2], "adults": 2, "currency": "EUR",
"watch": True, "watchKey": "paris-watch",
})
for row in client.dataset(run.default_dataset_id).iterate_items(): # apify-client 3.x
if row.get("rowType") != "price":
continue
ch = row.get("change") or {}
print(row["hotelName"], row["checkIn"], row.get("minPrice"), row["currency"],
ch.get("type"), "was", ch.get("previousMinPrice"))
Step 4: Run it 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"
}
],
"checkInFrom": "+7d",
"checkInTo": "+37d",
"checkInStepDays": 7,
"nights": [
2
],
"adults": 2,
"currency": "EUR",
"watch": true,
"watchKey": "paris-watch"
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
Step 5: Ask an AI assistant (MCP)
Apify’s hosted MCP server turns the actor into one tool. Add it to Claude, Cursor, VS Code or any MCP client:
{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com/?tools=arcadium/booking-prices",
"headers": {
"Authorization": "Bearer <APIFY_TOKEN>"
}
}
}
}Then ask, for example:
Use arcadium/booking-prices to get the price for 2 adults, 2 nights, at https://www.booking.com/hotel/fr/de-la-paix-paris1.html for check-in dates every 7 days over the next month, in EUR. Which date is cheapest?
More clients and the local setup on the MCP page.
Get an alert on each change
In the task, add an integration (Console, task, Integrations): a webhook on run succeeded to your endpoint, Slack, or email. Because the dataset holds only changed rows, any non-empty dataset is worth a message.
Output fields
Every row has a rowType; filter on it first. Failed inputs come back as free rows with a code and message. The fields this tutorial uses, from the actor’s dataset schema:
| 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). |
hotelName | Name of the hotel as shown on Booking.com. |
hotelUrl | Link to the hotel page on Booking.com. |
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. |
currency | Three-letter currency code of every price in the row. |
available | True when the hotel can be booked for the stay. |
minPrice | Cheapest total price for the whole stay and all rooms, in the row currency. |
minPricePerNight | Cheapest price per night, in the row currency. |
freeCancellation | True when the cheapest rate can be cancelled for free. |
change | Change-only mode: object with type, previousMinPrice and priceChange since the last run. |
All fields: Booking.com Hotel Prices Scraper guide.
Cost per run
Pay per event: you pay for the rows delivered, at the actor’s live Apify price on 2026-11-01. Error, coverage and summary rows are free.
| What | Rows | Price per row (Free plan) | Subtotal |
|---|---|---|---|
| Price row: first run: 1 hotel x 5 dates; later runs only changed rows | 5 | $0.0027 | $0.0135 |
Cost of this example on the Apify Free plan: 5 × $0.0027 = $0.0135 ($0.0129 on the Apify Gold plan and higher), plus $0.001 per GB of memory when the run starts. Higher Apify plans pay less per row. The Store page always has the current price.
Limitations
- The first run with a new watch key returns every row (it is the baseline) and charges for all of them.
- Keep the input and the watch key the same between runs; use a different watch key for each list you monitor.
- Public prices as an anonymous visitor sees them. No login, no member or Genius prices, no mobile-only rates.
- Prices depend on the currency, the guests and the dates you ask for. Booking.com may show slightly different prices to different countries; the actor reads them from a US connection.
- Destination searches return the cheapest rate of each hotel (set
includeRoomRatesfor all rates). Booking.com returns at most about 1,000 hotels per search; split a bigger market withstarsor the price filters. popularityorder changes from request to request; useprice(default) when you need stable ranks.- Dates up to about 16 months ahead; later dates come back sold out. A past date gives a free error row; stays above 30 nights are rejected when the input is checked.
taxesAndFeesExcludedis what the site lists as taxes and fees on top of the price (for example VAT and city tax); some rates include them already.- Names that exist in several places use the site's best match. Add the country or give the destination id.
Links
- Booking.com Hotel Prices Scraper: fields, price table and sample output
- How to use Booking.com Hotel Prices Scraper: every input field, n8n, LangChain
- arcadium/booking-prices on the Apify Store
- All tutorials