# Booking.com Rates Scraper (`piotrv1001/booking-com-rates-scraper`) Actor

The Booking.com Rates Scraper prices named hotels across a whole range of check-in dates, lengths of stay and occupancies in one run, returning total and per-night rates, taxes, cancellation terms, sold-out dates and ~100 competitor rates per stay — ideal for revenue management and rate shopping.

- **URL**: https://apify.com/piotrv1001/booking-com-rates-scraper.md
- **Developed by:** [FalconScrape](https://apify.com/piotrv1001) (community)
- **Categories:** Travel, Automation, E-commerce
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 rate rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### 📈 Booking.com Rates Scraper

Track **Booking.com hotel rates across a whole calendar in a single run**. Name the properties you care about, give a range of check-in dates, the lengths of stay and the occupancies you sell — and get back one clean row per combination, ready to chart. Sold-out dates come back as rows too, so your rate history never has silent gaps. Try it right now with the default input.

Most Booking.com scrapers price **one stay per run**, which forces you to fake a rate calendar by scheduling sixty near-identical jobs and stitching the results together. This one takes the whole matrix as input.

Running on the [Apify platform](https://apify.com) means you also get a REST API, scheduled runs, webhook integrations, proxy rotation and run monitoring — without maintaining any of it yourself.

### ✨ Features

- 🗓️ **Whole date ranges, not single stays** — give a first and last check-in date and every date in between is priced. Booking.com sells roughly 450 days ahead, and the Actor covers all of it.
- 🌙 **Multiple lengths of stay** — price 1, 2, 3, 7, 14 or 28 nights side by side and see exactly where minimum-stay pricing kicks in.
- 👥 **Multiple occupancies** — 1 to 6 adults, each priced separately, so you can see where the rate jumps to a larger unit.
- 🚫 **Sold-out dates are real rows** — `soldOut: true` with a null price. "Sold out" and "we failed to fetch" mean opposite things commercially, and this Actor never confuses them.
- 🏨 **Competitor rates for the same stay** — switch on *Include competitor rates* and every cell also returns around 100 nearby properties priced for the exact same dates, occupancy and length of stay. That is a like-for-like comp set, not a separate search.
- 🔎 **Paste anything to identify a property** — a hotel name, a Booking.com property URL, or a property ID. All three resolve to the same property.
- 💱 **20 currencies** — rates are quoted in the currency you choose, not converted after the fact.
- ⚡ **Fast and cheap** — no browser needed. A 180-cell rate calendar for one hotel finishes in seconds.

### 🛠️ How to use Booking.com Rates Scraper

1. **List your properties** — one per line: a hotel name (`The Savoy, London`), a Booking.com property URL, or a property ID.
2. **Set the check-in date range** — the first and last check-in date you want priced. Leave it empty for the next 14 days.
3. **Pick lengths of stay and occupancies** — every combination is priced. Two lengths of stay and two occupancies over 30 dates is 120 rate rows.
4. **Decide on competitor rates** — leave *Include competitor rates* off for your own properties only, or switch it on to benchmark every rate against its local market.
5. **Set a limit** and click **Start**. Rows stream into the dataset as they arrive.
6. **Download** as JSON, CSV, Excel or HTML — or pull them from the API and load them straight into your BI tool.

### 📥 Input

Configure everything from the **Input** tab. Only the property list is required.

| Field | Type | Description |
| --- | --- | --- |
| `hotels` | array | **Required.** Properties to price — hotel names, Booking.com property URLs, or property IDs. |
| `checkinFrom` | string | First check-in date, `YYYY-MM-DD`. Defaults to tomorrow. |
| `checkinTo` | string | Last check-in date, `YYYY-MM-DD`. Defaults to 14 days of dates. Clamped to Booking.com's ~450-day horizon. |
| `losNights` | array | Lengths of stay in nights. Each check-in date is priced once per length. Default `["1", "2"]`. |
| `occupancy` | array | Adult counts. Each date and length of stay is priced once per occupancy. Default `["2"]`. |
| `currency` | string | Currency for all rates. Default `USD`. |
| `includeCompetitors` | boolean | Also return ~100 nearby properties priced for the same stay. Default `false`. |
| `maxItems` | integer | Stop after this many rate rows for your properties. Default `100`. |
| `proxyConfiguration` | object | Proxy settings. Datacenter proxies are sufficient. |

Example input — a 90-day rate calendar for two hotels at two lengths of stay:

```json
{
    "hotels": ["The Savoy, London", "https://www.booking.com/hotel/gb/claridge-s.en-gb.html"],
    "checkinFrom": "2026-09-01",
    "checkinTo": "2026-11-29",
    "losNights": ["1", "2"],
    "occupancy": ["2"],
    "currency": "GBP",
    "includeCompetitors": false,
    "maxItems": 400
}
```

### 📊 Output

One row per property × check-in date × length of stay × occupancy. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

```json
[
    {
        "hotelId": 280149,
        "hotelName": "The Savoy",
        "hotelUrl": "https://www.booking.com/hotel/gb/the-savoy.en-gb.html",
        "slug": "the-savoy",
        "stars": 5,
        "reviewScore": 9.4,
        "reviewsCount": 1446,
        "checkin": "2026-08-19",
        "checkout": "2026-08-21",
        "nights": 2,
        "adults": 2,
        "rooms": 1,
        "soldOut": false,
        "currency": "USD",
        "totalPrice": 2107.47,
        "pricePerNight": 1053.73,
        "priceBeforeDiscount": null,
        "taxesAndCharges": null,
        "roomName": null,
        "mealPlan": null,
        "breakfastIncluded": false,
        "freeCancellation": true,
        "freeCancellationUntil": "2026-08-17T23:00:00Z",
        "noPrepayment": true,
        "geniusRateAvailable": false,
        "address": "Strand",
        "district": "Westminster Borough, London",
        "distanceFromCentre": "0.6 km from centre",
        "city": "London",
        "countryCode": "gb",
        "latitude": 51.5102983,
        "longitude": -0.1208603,
        "isCompetitor": false,
        "comparedToHotelId": null,
        "comparedToHotelName": null,
        "scrapedAt": "2026-08-15T09:39:12.534Z"
    },
    {
        "hotelId": 10550,
        "hotelName": "Hotel Okura Amsterdam",
        "checkin": "2026-09-10",
        "checkout": "2026-09-12",
        "nights": 2,
        "adults": 2,
        "soldOut": true,
        "currency": "EUR",
        "totalPrice": null,
        "pricePerNight": null,
        "isCompetitor": false,
        "scrapedAt": "2026-08-15T09:47:03.881Z"
    }
]
```

#### Data fields

| Field | Description |
| --- | --- |
| `hotelId`, `hotelName`, `hotelUrl`, `slug` | Property identity and link |
| `checkin`, `checkout`, `nights`, `adults`, `rooms` | The exact matrix cell this rate belongs to |
| `soldOut` | `true` when the property has no availability for this cell — the price fields are then null |
| `totalPrice`, `pricePerNight`, `currency` | Cheapest available rate for this cell, for the whole stay and per night |
| `priceBeforeDiscount`, `taxesAndCharges` | Pre-discount rate and excluded taxes/fees, where Booking.com publishes them |
| `roomName`, `bedrooms`, `beds` | The room type the rate was matched to |
| `mealPlan`, `breakfastIncluded` | What the rate includes |
| `freeCancellation`, `freeCancellationUntil`, `noPrepayment`, `geniusRateAvailable` | Booking conditions attached to the rate |
| `stars`, `reviewScore`, `reviewsCount` | Property quality signals, for normalising comparisons |
| `address`, `district`, `distanceFromCentre`, `city`, `countryCode`, `latitude`, `longitude` | Location |
| `isCompetitor`, `comparedToHotelId`, `comparedToHotelName` | `false` for your properties; on competitor rows, which property they were pulled alongside |
| `scrapedAt` | When the rate was captured — the timestamp your time series is keyed on |

### 💰 How much does it cost to scrape Booking.com rates?

This Actor uses **pay per event** pricing — you pay for the rates you receive, not for time spent running.

| Event | Price | Fires |
| --- | --- | --- |
| Rate row | $0.0015 | Per priced stay for one of your properties, sold-out dates included |
| Competitor rate row | $0.0001 | Per nearby property priced for the same stay, only when competitor rates are on |

That works out at **$1.50 per 1,000 rates** — well below the going rate for Booking.com price data, because a rate calendar is a high-volume product by nature.

| Job | Rate rows | Cost |
| --- | --- | --- |
| One hotel, 90 check-in dates, 2 lengths of stay | 180 | **$0.27** |
| Ten hotels, 90 check-in dates, 2 lengths of stay | 1,800 | **$2.70** |
| Ten hotels, 90 dates, 2 lengths of stay, daily for a month | 54,000 | **$81** |
| One hotel, 90 dates, 2 lengths of stay, with competitor rates | 180 + ~18,000 | **$2.09** |

Apify's free plan includes $5 of monthly usage, which covers roughly 3,300 rates at no cost.

### 💡 Tips

- **Start small.** Run one property over a few dates first to confirm it resolves to the property you meant — the log prints the name it matched.
- **Property URLs and IDs are the safest input.** A hotel name is resolved through Booking.com's own search, which is reliable but ambiguous for chains with many branches in one city.
- **Watch the multiplication.** Rate rows are properties × dates × lengths of stay × occupancies. Ten hotels over 90 dates with 3 lengths of stay and 2 occupancies is 5,400 rows. `maxItems` is your seatbelt.
- **Schedule it daily.** Run the same input on a schedule and key on `scrapedAt` — the difference between runs is your rate movement, and the difference between your rate and the comp set is your position.
- **Sold-out rows are data.** Keep them. A property that goes sold-out 60 days out on every weekend in October is telling you something a missing row cannot.
- **Competitor rows are near-free.** They cost nothing extra to fetch, which is why they are priced 15× lower than your own rates. Switch them on when you want market context, off when you only need your own calendar.
- **The horizon is real.** Booking.com loads inventory about 450 days ahead. Dates beyond that are clamped rather than returned as a wall of false "sold out".

### ❓ FAQ

**Is scraping Booking.com legal?**
This Actor collects only publicly available information — the same rates any visitor sees without logging in. It does not collect private personal data and does not bypass any login. Web scraping of public data is broadly legal, but how you use the data is your responsibility. Consult a lawyer if you are unsure.

**Does it return every room type and rate plan?**
No. Each cell returns the cheapest available rate matching that occupancy, which is what rate shopping actually compares. A full room-type × meal-plan × cancellation-policy grid is not part of this Actor.

**Why is `roomName` sometimes empty?**
Booking.com does not always attach a room label to the cheapest matched offer, particularly for hotels. The price is still the rate for that stay.

**Why did a price not change when I went from 1 adult to 2?**
Because the same room was matched for both. Rates move when the occupancy forces a larger unit — that is Booking.com's own pricing behaviour, not a gap in the data.

**How many competitors do I get?**
Around 100 per cell, drawn from the same city as your property and priced for the identical stay. They vary slightly by date and availability.

**Do I need residential proxies?**
No. Datacenter proxies — the default — are sufficient and cheaper.

**Can I track a whole city instead of named properties?**
Not with this Actor — it is built around named properties and their comp sets. For city-wide listings with prices, use the Booking.com Listings Scraper instead.

**Something is broken or missing.**
Open an issue on the **Issues** tab of this Actor and it will be looked at. Need a custom version, a different output shape, or another data source? Get in touch — custom solutions are available.

# Actor input Schema

## `hotels` (type: `array`):

Properties to price — a hotel name, a Booking.com property URL, or a Booking.com property ID. One per line.

## `checkinFrom` (type: `string`):

Start of the check-in date range, in YYYY-MM-DD format. Leave empty to start tomorrow.

## `checkinTo` (type: `string`):

End of the check-in date range, in YYYY-MM-DD format. Leave empty to cover 14 days. Booking.com sells about 450 days ahead; later dates are clamped.

## `losNights` (type: `array`):

Every check-in date is priced once for each length of stay you pick.

## `occupancy` (type: `array`):

Every check-in date and length of stay is priced once for each occupancy you pick.

## `currency` (type: `string`):

Currency the rates are returned in.

## `includeCompetitors` (type: `boolean`):

Also return the rates of nearby properties for exactly the same stay, so every rate can be benchmarked against its local market. Adds roughly 100 extra rows per rate row and is billed separately.

## `maxItems` (type: `integer`):

Stop after this many rate rows for your properties. Competitor rows are extra and are not counted here.

## `proxyConfiguration` (type: `object`):

Proxy settings. Datacenter proxies are enough for this Actor.

## Actor input object example

```json
{
  "hotels": [
    "The Savoy, London"
  ],
  "losNights": [
    "1",
    "2"
  ],
  "occupancy": [
    "2"
  ],
  "currency": "USD",
  "includeCompetitors": false,
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "hotels": [
        "The Savoy, London"
    ],
    "losNights": [
        "1",
        "2"
    ],
    "occupancy": [
        "2"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("piotrv1001/booking-com-rates-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "hotels": ["The Savoy, London"],
    "losNights": [
        "1",
        "2",
    ],
    "occupancy": ["2"],
}

# Run the Actor and wait for it to finish
run = client.actor("piotrv1001/booking-com-rates-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "hotels": [
    "The Savoy, London"
  ],
  "losNights": [
    "1",
    "2"
  ],
  "occupancy": [
    "2"
  ]
}' |
apify call piotrv1001/booking-com-rates-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,piotrv1001/booking-com-rates-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/NdPQ4ezMbx0kwJGJg/builds/9DuDDlafmpZ01Mdt5/openapi.json
