Arcadium Data Scrapers
Home / Guides / Booking.com Hotel Prices Scraper

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)

  1. Open arcadium/booking-prices and sign in to Apify (a free account works).
  2. Fill in the input form. The fields below are the ones the example uses.
  3. Set a maximum cost per run in the run options if you want a hard cap.
  4. Start the run. Rows appear in the Output tab as they arrive.
  5. Export the dataset as JSON, CSV or Excel, or connect an integration.
Input fieldTypeDescription
startUrlsarrayBooking.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.
destinationTypestringOnly 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.
maxHotelsintegerHow 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).
checkInDatesarrayCheck-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.
nightsarrayLengths 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.
childrenAgesarrayAge (0-17) of each child, for example [5, 9]. Prices depend on the number and ages of children. Leave empty for none.
currencystringThree-letter currency code for all prices, for example EUR, USD or GBP. Booking.com converts the prices.
includeRoomRatesbooleanDestination 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).
watchbooleanCompare 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.
watchKeystringName 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.
digestbooleanWatch 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.
digestDaysintegerHow 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"
}
FieldWhat it holds
rowTypeKind 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).
hotelIdBooking.com numeric id of the hotel.
hotelNameName of the hotel as shown on Booking.com.
hotelUrlLink to the hotel page on Booking.com.
starsStar rating of the hotel (1-5), null when not rated.
reviewScoreGuest review score on the 0-10 scale.
reviewCountNumber of guest reviews behind the score.
cityCity of the hotel.
countryCodeTwo-letter country code of the hotel, lower case.
checkInCheck-in date of the stay, YYYY-MM-DD.
checkOutCheck-out date of the stay, YYYY-MM-DD.
nightsLength of the stay in nights.
adultsAdult guests the price is for.
childrenNumber of children the price is for.
roomsNumber of rooms the price is for.
currencyThree-letter currency code of every price in the row.
availableTrue when the hotel can be booked for the stay.
soldOutTrue when Booking.com had no rate for the stay; such a row has no price.
minPriceCheapest total price for the whole stay and all rooms, in the row currency.
minPricePerNightCheapest price per night, in the row currency.
originalPriceThe same rate before discounts, when the site shows one.
taxesAndFeesExcludedTaxes and fees the site lists on top of the price, in the row currency.
mealPlanMeal plan of the cheapest rate, for example ROOM_ONLY, BREAKFAST or HALF_BOARD.
freeCancellationTrue when the cheapest rate can be cancelled for free.
cancellationPolicyCancellation of the cheapest rate: free_cancellation or non_refundable.
cheapestRoomName of the room the cheapest rate is for.
roomRatesEvery rate for the stay, cheapest first: room, meal plan, price, per night, taxes, cancellation, payment.
rateCountNumber of rates found for the stay.
sourceWhere the rates come from: roomTable (every rate) or search (cheapest rate of each hotel).
searchDestinationDestination searches: the destination text you gave.
searchRankDestination searches: position of the hotel in the results.
changeChange-only mode: object with type, previousMinPrice and priceChange since the last run.
scrapedAtISO timestamp of when the row was read.
codeError rows: machine-readable error code.
messageError 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.