# Booking Scraper — Rate Intelligence, Comp-Set & Price Drops (`ryanclinton/booking-scraper`) Actor

Booking.com rate-intelligence engine. Returns a ranked value queue — which hotels are underpriced vs comparable properties, whose rates dropped, where demand is softening — with Saved Rate Memory, comp-set position, and watchlist deltas. Drop-in replacement for voyager/booking-scraper.

- **URL**: https://apify.com/ryanclinton/booking-scraper.md
- **Developed by:** [Ryan Clinton](https://apify.com/ryanclinton) (community)
- **Categories:** Travel, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Scraper — Rate Intelligence, Comp-Set & Price Drops

![Booking Scraper — rate intelligence, comp-set and price-drop signals](https://apifyforge.com/readme-assets/ryanclinton-booking-scraper/hero.png)

Find underpriced hotels. Track competitor rate changes. See where hotel demand is rising or falling.

Booking Scraper turns Booking.com data into hotel rate intelligence. Paste a destination and dates, get back the hotels worth paying attention to: ranked by value, with a reason and a recommended next step on each one.

### Why another Booking scraper?

Because scraping Booking is solved. The hard part is deciding what matters. Most scrapers return rows. This actor returns decisions. The real competitor isn't another scraper. It's the spreadsheet.

It is built on four concepts. Everything else is detail:

- **Value Queue** - the hotels worth your attention for your dates, ranked, with why.
- **Saved Rate Memory** - Booking shows today's rate; this actor remembers every rate it has ever seen, so you can see which rates dropped, where demand is softening, and how rates for stays like this moved toward the date. Nobody else on Apify keeps the history.
- **Competitor Movers** - which hotels in your comp-set changed rate since the last run.
- **Benchmark My Hotel** - where your own property ranks in its market.

### What you get in 60 seconds

Input: `{ "mode": "rates", "destination": "London", "checkIn": "2026-08-10", "checkOut": "2026-08-12", "rankBy": "value" }`

An example `rates` run returns something like (illustrative, with an invented sample hotel):

- 200+ hotels analysed for your dates
- a handful flagged underpriced vs comparable rated properties
- recent rate drops surfaced first
- the tightest-availability hotels flagged as selling out
- top value: The Northbank Hotel, 18% below comparable 4-star properties, `rateValueScore` 78 (B), action "Review for these dates"

![240 Booking rows in, 5 hotels to act on, each with the reason and the next step](https://apifyforge.com/readme-assets/ryanclinton-booking-scraper/before-after.png)

### Who uses this?

- **Revenue managers** - rate-shop the comp-set and see which competitors moved rates since the last run.
- **Hotel operators** - benchmark your own property: where it ranks in its market on rate, value, occupancy pressure, and pricing discipline.
- **Short-let and hotel investors** - find softening markets and underpriced or undermanaged properties.
- **Travel deal and price-comparison sites** - surface underpriced hotels and recent rate drops automatically.
- **OTA and travel analysts** - monitor a destination's rate and demand trajectory over time.

### Ready-to-run examples

Each example is a preset you can run in one click, then swap in your own destination, dates, or hotel URLs:

- [Find Best-Value Hotels](https://apify.com/ryanclinton/booking-scraper/examples/find-best-value-hotels) - rank a destination's hotels by value for your dates.
- [Hotel Price Drop Tracker](https://apify.com/ryanclinton/booking-scraper/examples/hotel-price-drop-tracker) - surface the hotels that just cut their rates, deepest drop first.
- [Cheap Hotel Finder by Dates](https://apify.com/ryanclinton/booking-scraper/examples/cheap-hotel-finder) - the lowest rates for a city and dates, with a value score on each.
- [Hotel Rate Comparison Tool](https://apify.com/ryanclinton/booking-scraper/examples/hotel-rate-comparison) - compare specific hotels side by side on rate, comp position, and history.
- [Hotel Demand by Destination](https://apify.com/ryanclinton/booking-scraper/examples/hotel-demand-by-destination) - a destination's rate and demand read with the value, demand, and opportunity indices.

See all examples on the [actor's examples tab](https://apify.com/ryanclinton/booking-scraper/examples).

### In one sentence

Booking Scraper is a stateful Booking.com rate-intelligence engine on Apify that takes a destination and dates or hotel URLs and returns a ranked value queue: which hotels are underpriced vs comparable properties, whose rates just dropped, where demand is softening, and what changed in your comp-set since the last run.

**Category:** Booking.com scraper. Hotel rate intelligence and comp-set monitoring. Hotel price-drop and demand tracking.
**Primary use case:** Rank a destination's hotels by value for your dates, then schedule a watchlist so the rate memory compounds. Can also be used for one-shot comp-set rate-shopping, date-range value scans, and benchmarking your own hotel against its market.

**Also known as:** booking scraper, booking.com scraper, hotel rate monitor, hotel price drop tracker, hotel comp set tool, booking rate intelligence

### What this actor does

- **What it is:** A stateful Booking.com rate-intelligence engine that turns a scrape into a ranked list of which stays are good value and whose rates moved.
- **What it checks:** Where each hotel's rate sits vs comparable properties for your dates, what changed since the last run (rate, availability, rating), and how the destination's rates and demand are trending.
- **What it returns:** A value queue per hotel (`attentionPriority`, `rateValueScore`, `demandPressure`, `rateVelocity`, `whyNow`, `recommendedAction`), comp-set position, Saved Rate Memory (rate history), date-scan rate calendar, and watchlist deltas.
- **What it does NOT do:** It does not book or reserve anything, it does not tell you when to book or predict future rates, it does not read login or member-only rates, and it harvests no reviewer personal data.
- **Who it's for:** Hotel revenue managers, short-let and hotel investors, OTA and travel analysts, price-comparison and travel-deal sites, corporate travel and TMC teams.

### Overview

Booking Scraper is an Apify actor that answers a question raw Booking scrapers leave on the table: of all these hotels for my dates, which ones are actually good value, and whose rates just moved? Paste a destination and dates and the actor returns a ranked value queue in about 60 seconds, each row carrying a plain-English reason and a recommended action. It functions as a hotel rate-intelligence API, not a row dump.

The real competitor isn't another scraper. It's the spreadsheet. Voyager and the other Booking actors hand you the ingredients (per-date room rates, comp ratings, availability) and make you cook the decision in Excel. Booking Scraper cooks it. Paste a destination + dates or Booking URLs and you get back which hotels are underpriced vs comparable properties, whose rates just dropped, where demand is softening, and what changed in your comp-set since last run. Same input + fields as `voyager/booking-scraper`, one actor instead of the suite.

**In short:** Voyager gives you Booking rows. This actor tells you which stays are good value and whose rates moved.

**What it is:** A Booking.com rate-intelligence engine that ranks hotels by value and tracks how rates move.
**Who it's for:** Hotel revenue managers, investors, travel analysts, and price-comparison sites.
**When to use it:** When you need a decision about hotel rates for your dates, not a spreadsheet of rows to interpret by hand.

**What it does** - Scrapes a destination's hotels for your dates and returns a ranked value queue with a reason and action per hotel.
**Best for** - Comp-set rate-shopping, finding underpriced stays, tracking rate drops, scanning dates for value, benchmarking your hotel.
**Speed** - A default `rates` run returns its value queue in about 60 seconds.
**Pricing** - Pay per event: $0.006 per hotel analysed (the per-property rate intelligence) plus $0.02 per run for the destination market read. Apify platform compute is billed separately by Apify.
**Output** - JSON, CSV, or Excel. Value queue, comp-set position, Saved Rate Memory, rate calendar, watchlist deltas.

**Key limitation:** Rates are date-dependent. Booking only returns complete per-date pricing with dates, so a dateless run gives thin data and lower confidence.
**What it is not:** Not a booking or checkout tool, not a rate forecaster, and not a replacement for enterprise hospitality dashboards' full feature set.
**Does not include:** Booking-flow or payment-page data, login or member-only rates, reviewer personal data, or any forward price prediction.
**Results may be incomplete when:** No dates are provided, a destination has too few comparable hotels to form a comp-set, or a property is private or removed.

### The hero feature: Saved Rate Memory

Booking shows today's rate. This actor remembers the rate history. Rates are the most ephemeral thing in hotel pricing, they change daily by date and occupancy, and nobody keeps the history. Booking Scraper banks a timestamped snapshot of public rate, availability, and rating on every property and date any run touches, keyed by hotel and stay-date.

That accumulated history is what lets you see which rates dropped, where demand is softening, and how rates for stays like this usually move toward the date. A competitor can scrape the current rate; they cannot reproduce accumulated rate history. Popular destinations accrue deep history; an unseen one returns `firstSightFallback` honestly rather than inventing a past. The clock starts on day one and cannot be backfilled.

### What you get from one call

**Input:** `{ "mode": "rates", "destination": "London", "checkIn": "2026-08-10", "checkOut": "2026-08-12", "rankBy": "value" }`
**Returns:**
- A ranked value queue: each hotel with `attentionPriority`, `rateValueScore` (0-100 + grade), `demandPressure`, `rateVelocity`, `whyNow`, and a verb-fenced `recommendedAction`
- Comp-set position per hotel: `compSet` with the comp median rate, your rate's position vs it, and a rank ("4th-cheapest of 31 comparable 4-stars")
- Saved Rate Memory per hotel: `history` with the rate trajectory, drop count, peak-vs-current, and rate volatility
- A run summary with the headline, daily briefing, executive highlights, and store-wide leaderboards

**Typical time to first result:** about 60 seconds for a default `rates` run.
**Typical time to integrate:** minutes if you already read a standard Booking scraper's output, since the substrate fields match.

![Rate memory that compounds, ranked not dumped, comp-set position, descriptive never a forecast](https://apifyforge.com/readme-assets/ryanclinton-booking-scraper/feature-callouts.png)

### What makes this different

- **Rate value, not a row dump** - every hotel arrives ranked by `rateValueScore` with a comp-set position and a plain-English reason, not a per-date price you still have to interpret.
- **Rate memory that compounds** - Booking Scraper banks per-hotel and per-destination rate history across runs, so trajectory, rate velocity, and outcome history unlock as you keep running it.
- **An honest decision layer** - every hotel carries a `whyNow` reason and a verb-fenced `recommendedAction`, and every record travels with a data-quality `confidence` grade.

### Quick answers

**What is it?** Booking Scraper is a stateful Booking.com rate-intelligence engine that ranks a destination's hotels by value for your dates and tracks how rates move across runs.
**How do I rate-shop hotels for my dates?** Run Booking Scraper in `rates` mode with a destination, `checkIn`, `checkOut`, and `rankBy: "value"`. You get a ranked value queue back in about 60 seconds.
**What makes it different?** It ships a decision layer on top of the scrape: comp-set rate position, value scoring, rate-drop and demand signals, and Saved Rate Memory, instead of raw rows.
**What data sources does it use?** Public Booking.com search and hotel pages, fetched over residential proxies. No login, no member-only rates, no booking-flow or payment pages.
**What does it return?** A value queue per hotel, comp-set position, rate history, a date-scan rate calendar, and watchlist deltas, in JSON, CSV, or Excel.
**How much does it cost?** Pay-per-event, on two charges. A per-hotel charge of $0.006 for each property's rate intelligence (value score, comp-set position, rate history, signals). A per-run charge of $0.02 for the destination market read (the Value, Demand, Volatility and Opportunity indices, the market regime, and the market map). A typical destination run of 50 hotels is about $0.32. Apify platform compute is billed separately by Apify.

### At a glance

**Quick facts:**
- **Input:** A destination + dates (`rates` / `market` / `watchlist` / `date_scan`), hotel URLs (`properties`), or your own hotel URL (`benchmark`).
- **Output:** Value queue, comp-set position, Saved Rate Memory, rate calendar, watchlist deltas, run summary.
- **Modes:** rates, properties, market, benchmark, watchlist, date_scan.
- **Output profiles:** signals (default), compat (voyager parity), minimal.
- **Ranking:** value (default), rateValueScore, rateDrop, demand, softMarket, rating, recency, rate.
- **Batch size:** Up to 240 hotels per destination (`maxProperties`); `coverageGrade` reports whether the run was full, partial, or thin.
- **Data source:** Public Booking.com search and hotel pages over residential proxies. No login.

**Input to output:**
- Input: a destination + dates, hotel URLs, or your own hotel URL.
- Process: collect the public substrate for your dates, build comp-sets, score value, detect rate and demand signals, fence thin data as low confidence, and persist rate memory.
- Output: a ranked value queue plus comp-set position, rate history, and a run summary.

**Best fit:** Comp-set rate-shopping, finding underpriced stays, tracking rate drops, date-range value scans, benchmarking your own hotel.
**Not ideal for:** Booking or checkout, member-only rates, rate forecasts, or a full census of a destination above 240 hotels.
**Does not include:** Booking-flow data, reviewer PII, forward price predictions, or any in-Booking action.

**Problems this solves:**
- How to tell which hotels are underpriced for my dates instead of reading per-date rows by hand.
- How to track which competitors cut their rates since the last check.
- How to find the cheapest or best-value dates across a range, with a seasonality calendar.
- How to monitor a comp-set over time and get back only what changed.

**Data trust:** Rates, availability, and ratings are observed and timestamped, keyed by hotel and stay-date with occupancy. Comp-set medians and positions are derived. `historicalOutcomeProfile` is descriptive cohort history over past similar stays, never a forward prediction. A dateless run is penalised in `confidence` because Booking only returns complete pricing with dates. Thin or cold-start data surfaces as `null` plus a reason, never a fabricated rate.

### What is a hotel rate-intelligence tool?

A hotel rate-intelligence tool turns a Booking.com scrape into decisions: where each hotel's rate sits vs comparable properties, whose rates are moving, and how the market is trending. Most Booking actors stop at rows; Booking Scraper ships the comp-set position, the value score, the rate signals, and the accumulated rate history that those rows leave for the buyer to build in a spreadsheet. The real competitive set is hospitality intelligence tooling, the kind that charges enterprise prices for rate intelligence; this actor brings that decision layer to the Booking data you already use.

### What data can you extract?

| Data point | Source | Availability | Example |
|------------|--------|--------------|---------|
| **Rate value score** | Derived | Best with dates | `{ score: 78, grade: "B" }` |
| **Comp-set position** | Derived | When comp-set forms | `4th-cheapest of 31 comparable 4-stars` |
| **Demand pressure** | Derived | Every run | `{ score: 88, occupancyBand: "high" }` |
| **Rate (nightly)** | Observed | With dates | `184` |
| **Currency** | Observed | Every run | `GBP` |
| **Stars** | Observed | Every run | `4` |
| **Review score** | Observed | Every run | `8.6` |
| **Reviews count** | Observed | Every run | `1402` |
| **Rooms / offers** | Observed | With dates | `[{ roomType, bedType, persons, price }]` |
| **Rate history** | Saved Rate Memory | Compounds per run | `{ daysTracked: 42, dropCount: 2, trajectory: "cooling" }` |
| **Rate velocity** | Saved Rate Memory | After history accrues | `-3.1` |
| **Validated URL** | Observed | Every run | `https://www.booking.com/hotel/gb/...html` |

![Sample value queue output: hotel, rate value score, rate position, demand, recommended action](https://apifyforge.com/readme-assets/ryanclinton-booking-scraper/output-table.png)

### The six modes

One actor, six entry points. Pick a mode and one set of targets. Lead with the canonical first run.

#### Mode: rates (default, recommended)
Rank a destination's hotels by value for your dates. The 60-second first run:
```json
{ "mode": "rates", "destination": "London", "checkIn": "2026-08-10", "checkOut": "2026-08-12", "rankBy": "value" }
````

#### Mode: properties

Analyse specific hotel URLs and get rate intelligence per hotel.

```json
{ "mode": "properties", "propertyUrls": ["https://www.booking.com/hotel/gb/the-savoy.html"], "checkIn": "2026-08-10", "checkOut": "2026-08-12" }
```

#### Mode: market

Return a destination's rate and demand trajectory plus its standout stays. Run on a schedule with a `marketId` and it becomes a market subscription that accumulates observations.

```json
{ "mode": "market", "destination": "Paris", "marketId": "paris_4star" }
```

#### Mode: benchmark

The question most hotel operators actually ask is not "which hotel is good value?" but "how am I doing?" Benchmark mode answers it. Input your own hotel URL and its destination, and get your property ranked within its market on every dimension at once: `marketRank` (where your rate sits among comparable hotels), `pricingPosition` vs the comp median, `valueRank`, `occupancyPressureRank`, `pricingDiscipline` (how steadily you move rates vs erratic peers), and `compSetDrift` (whether you have become cheaper or dearer vs your peers over time). One run, your standing on every axis.

```json
{ "mode": "benchmark", "myHotelUrl": "https://www.booking.com/hotel/gb/my-hotel.html", "destination": "London" }
```

#### Mode: watchlist

Track a comp-set over time and get back what changed since the last run. Composable on any mode; with a competitor hotel set it is the revenue manager's comp-shop. The retention moat.

```json
{ "mode": "rates", "destination": "London", "checkIn": "2026-08-10", "checkOut": "2026-08-12", "watchlistName": "london-compset" }
```

![What changed since last run: competitors cut rates, a property dropped, demand rising, a new property entered the comp-set](https://apifyforge.com/readme-assets/ryanclinton-booking-scraper/change-feed.png)

#### Mode: date\_scan

Scan a range of check-in dates for the cheapest or best-value dates, plus a seasonality rate calendar.

```json
{ "mode": "date_scan", "destination": "London", "dateScan": { "startDate": "2026-08-01", "nights": 2, "daysToScan": 14 } }
```

### Choose your output

The `outputProfile` input controls how much of the envelope each record carries:

| Profile | What it returns | Best for |
|---------|-----------------|----------|
| `signals` (default) | Full envelope: substrate + rate value score + comp position + signals + attention + rate history + delta | Most users who want the decision layer |
| `compat` | Exact `voyager/booking-scraper` field set with validated URLs and IDs, no signal fields | Verifying migration parity |
| `minimal` | Name, URL, rate, and value score only | Lightweight pulls |

### Reranking

Booking's native sort is not what buyers want. The `rankBy` input reorders the value queue by `value` (default composite), `rateValueScore`, `rateDrop` (biggest cuts), `demand` (tightest availability), `softMarket` (buyer's-market trajectory), `rating`, `recency`, or `rate` (cheapest first). The `value` and `rateValueScore` axes are the wedge no other Booking actor ships.

### Dataset views (progressive disclosure)

![Discovery products: Best-Value Finder and Benchmark My Hotel, each a ranked list with reasons](https://apifyforge.com/readme-assets/ryanclinton-booking-scraper/discovery-cards.png)

The dataset opens on the Value Queue. Deeper views answer a specific question without cluttering the 5-second read.

| View | What it shows | Audience |
|------|---------------|----------|
| **Value Queue** (default) | Hotels ranked by value with what to review first and why | Every buyer |
| **Ignore Queue** | Records the actor deprioritised (overpriced, no movement, soft value) | "Don't waste time here" |
| **Rate Drops** | Hotels with rate-drop signals by depth | Investors / travellers |
| **Best Value** | Hotels by `rateValueScore` with comp-set context | Travellers / deal sites |
| **Demand / Scarcity** | Hotels by `demandPressure` | Revenue managers |
| **Rate Shop Matrix** | Current rate vs previous vs comp median, position, action | Revenue managers |
| **Date Scan / Rate Calendar** | Best dates plus a seasonality heatmap | Travellers / owners / analysts |
| **Soft Markets** | Hotels and destinations with a buyer's-market trajectory | Investors / buyers |
| **Market Trajectory** | Destination lifecycle, regime, momentum, and indices | Analysts |
| **New Since Last Run** | Records whose change flags are non-empty since the prior run | Watchlist / comp-shop |
| **Competitor Movers** | Watchlisted hotels that changed rate, by change % x days | Revenue managers |
| **Rate Feed** | Events by importance for Slack, Zapier, and agents | Automation |
| **voyager Compat** | Exact incumbent field set | Migrators |
| **Coverage & Errors** | Coverage block and error records | Trust / debug |
| **Summary** | The run rollup | Exec |

### Drop-in migration from voyager/booking-scraper

Switching from `voyager/booking-scraper` is frictionless because three things hold:

1. **Same input shape.** Pass a destination, Booking hotel URLs, and `checkIn` / `checkOut` as you do today and it runs.
2. **Same output substrate.** Every field a standard Booking scraper ships (`name`, `type`, `stars`, `price`, `currency`, `rating`, `reviews`, `rooms[]` with `roomType` / `bedType` / `persons` / `price`, validated `url`) ships here with identical name and type. Code reading `item.price` works unchanged.
3. **The signal layer is additive.** The default `outputProfile: "signals"` adds rate value score, comp position, signals, and rate history on top. For the exact original field set with validated URLs and IDs, set `outputProfile: "compat"`.

Same rows, plus which stays are actually good value and whose rates moved, one actor instead of the suite.

### Features

Booking Scraper layers a decision envelope on a faithful Booking substrate. The substrate matches a standard Booking scraper field-for-field; the layers below add the decisions.

#### Scrapes a faithful Booking substrate

- **Faithful substrate:** `name`, `type`, `stars`, `price` (nightly rate for the dates), `currency`, `rating` (0-10 review score), `reviews`, `rooms[]` ({ available, roomType, bedType, persons, price, currency, features }), and a validated `url` that always resolves to a public `/hotel/<country>/<slug>.html` path.
- **Validated links:** a record whose URL does not resolve to its id is dropped, not emitted. Never a broken or booking-flow link.

#### Ranks hotels by rate value

- **rateValueScore** per hotel: a 0-100 score plus an A-F grade, broken into components (below-comp, rating-per-rate, rate-drop depth, amenity value, location value) and penalties (small comp-set, low confidence, no dates), so the score is auditable, not a black box.
- **demandPressure** (occupancy pressure): a 0-100 read of scarcity plus rate-rise plus falling availability, with an `occupancyBand` and an `availabilityTrend`. 88 = selling out; 20 = soft and discountable.

#### Detects rate and demand shifts as typed signals

- **11 signal event types:** rate\_drop, sustained\_rate\_drop, underpriced\_vs\_comp, overpriced\_vs\_comp, scarcity, demand\_surge, soft\_demand\_trajectory, rate\_increase, new\_property, rating\_shift, demand\_shock. Each carries a heuristic strength (not a probability), a decay status, evidence keyed by stay-date and occupancy, and a plain-English reason.
- **8 property archetypes:** best-value, rate-dropper, selling-out, overpriced, premium-stable, soft-market, new-on-market, unclassified.

#### Builds an auditable comp-set

- **compSet** per hotel: the comp median rate, your rate's position vs it (negative = under), rate-per-star vs comp, and a competitive rank ("4th-cheapest of 31 comparable 4-stars"). Deterministic, comparable hotels for the same dates, area, and star-band. No LLM.

#### Remembers rate history

- **Saved Rate Memory** (`history`) per hotel: days tracked, the rate trajectory, drop count, peak-vs-current, a climbing / flat / cooling read, `rateVelocity`, `rateVolatility` with a pricing-discipline band, and `compSetDrift` (has this hotel become cheaper or dearer vs its peers over time).
- **Rate Outcome Engine** (`historicalOutcomeProfile`): descriptive cohort frequencies over past similar stays (similar stays, median rate drop toward the date, sold-out frequency, typical booking-window band). Honest-null until enough closed stays.

#### Tracks a comp-set across runs

- **Watchlist deltas:** with a `watchlistName`, every record gains `changeFlags` (NEW, RATE\_DROP, RATE\_SPIKE, SOLD\_OUT, BACK\_IN\_STOCK, UNCHANGED), a `rateChange` delta, and `newSignalsSinceLastRun`. First run uses first-sight framing, no fabricated history.
- **Competitor Movers:** a rollup of watchlisted hotels that changed rate, by change % x days, so revenue managers see who moved.

#### Reads the market and grades its own trust

- **Market trajectory:** `marketLifecycle`, `marketRegime` (buyers\_market / sellers\_market / balanced), `marketRateMomentum`, and Destination Indices (value, demand, volatility, opportunity) per destination.
- **Confidence on every record:** `{ overall, grade, drivers, limitations }`. A no-dates run is low confidence with a reason; cohorts below 10 members return null with `insufficient-cohort`.

### Use cases for hotel rate intelligence

Each use case maps to a mode and the fields you read for the answer.

#### Best for comp-set rate-shopping

Use when a revenue manager prices the comp-set daily. Run `rates` (or a watchlist) with `outputPack: "revenue-manager"`. Each hotel returns its rate vs the comp median, its position, and a Rate Shop Matrix row. Revenue manager teams use the Competitor Movers view to see who moved their rates overnight. Key outputs: `compSet`, `rateChange`, `demandPressure`, `attention`.

#### Best for finding underpriced stays

Use when a traveller or deal site wants the best value for fixed dates. Run `rates` with `rankBy: "value"`. Key outputs: `rateValueScore`, `whyThisMatters`, `compSet.competitivePosition`.

#### Best for tracking hotel rate drops

Use when an investor or deal site watches for cuts. Run `rates` with `rankBy: "rateDrop"`, or a watchlist with `alerts.rateDropMinPct`. Key outputs: `signalEvents` (rate\_drop / sustained\_rate\_drop), `history`, `rateVelocity`.

#### Best for date-range value scans

Use when a traveller or owner asks "which dates are cheapest and how does this destination move seasonally?" Run `date_scan`. Key outputs: `bestDates`, `rateCalendar` (seasonality index, cheapest and priciest week, month medians).

#### Best for benchmarking your own hotel

Use when an operator asks "am I priced right?" Run `benchmark` with your hotel URL and destination. Key outputs: `benchmark` (market rank, pricing position, value rank, occupancy-pressure rank, pricing discipline, comp-set drift).

#### Best for market trajectory reads

Use when an analyst tracks where a destination is heading. Run `market`. Key outputs: `marketLifecycle`, `marketRegime`, `marketRateMomentum`, `destinationIndices`.

### When to use Booking Scraper

**Best for:**

- Rate-shopping a comp-set daily or weekly and acting on who moved.
- Finding underpriced stays for fixed dates where comp-set position matters more than a raw price list.
- Tracking rate drops and demand shifts across a destination over time.
- Feeding a Rate Feed into an automation or AI agent that routes only critical-severity events.

**Not ideal for:**

- Booking, reserving, or any checkout action; this actor reads public content only.
- Member-only or login-gated rates; it reads public rates only.
- A full census of a destination above 240 hotels; the actor caps the sample and reports the fraction honestly.

### How to rate-shop hotels on Booking.com

1. **Enter your target** - type a destination in the `destination` field (for example, `London`), and set `checkIn` and `checkOut` for your dates.
2. **Configure options** - leave `mode` as `rates` and `rankBy` as `value` for the recommended first run; optionally add a `watchlistName` to start tracking the comp-set.
3. **Run the actor** - click Start. A default `rates` run returns its value queue in about 60 seconds.
4. **Download results** - open the Dataset tab and export JSON, CSV, or Excel. The default view is the Value Queue, sorted by attention and value.

### First run tips

- **Start with the demo** - leave the fields empty for the London demo, or paste `{ "mode": "rates", "destination": "London", "checkIn": "2026-08-10", "checkOut": "2026-08-12", "rankBy": "value" }` to see a ranked queue before you scale.
- **Always pass dates** - Booking only returns complete per-date rates with `checkIn` and `checkOut`. A dateless run gives thin data and is penalised in `confidence`; a high value score on dateless data would be misleading, so the actor fences it.
- **Don't expect rate history on run 1** - `rateVelocity`, trajectory, and `historicalOutcomeProfile` need accumulated history. Run 1 finds comp outliers; the deeper reads unlock as Saved Rate Memory accrues. A fresh hotel returns `firstSightFallback: true` rather than inventing a past.
- **Name your watchlist consistently** - watchlist state keys on `watchlistName`; a stable name keeps the memory clock running, a rename starts a fresh one.
- **Mind the date-scan fetch budget** - `date_scan` fetches roughly `daysToScan x properties`. The worst-case fetch count is logged before the scan and capped by `limits.maxDateScanFetches`.

### Typical performance

Observed in internal testing (June 2026, small sample). Values vary by destination size, dates, and Booking conditions.

| Metric | Typical value |
|--------|---------------|
| Records per `rates` run | Up to 240 hotel records plus a summary |
| Run time (default `rates`) | about 60 seconds to first value queue |
| Run time (full 240-hotel destination) | a few minutes |
| Comp-set size when formed | reported in `compSet.compCount` |
| Coverage when capped | reported in `coverageGrade` and `coveragePct` |

### Input parameters

Everything below this point is reference: the full input parameters, the output field contract, and the API. The sections above cover what the actor does and who it is for.

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `mode` | string | No | `rates` | Entry point: `rates`, `properties`, `market`, `benchmark`, `watchlist`, `date_scan`. |
| `destination` | string | Conditional | `London` | City or area for rates, market, watchlist, and date\_scan. |
| `checkIn` | string | Conditional | `""` | Stay start date (YYYY-MM-DD). Required for complete per-date rates. |
| `checkOut` | string | Conditional | `""` | Stay end date (YYYY-MM-DD). |
| `propertyUrls` | array | Conditional | `[]` | Booking `/hotel/<country>/<slug>.html` URLs for properties and date\_scan modes. |
| `myHotelUrl` | string | Conditional | `""` | Your own property's URL for benchmark mode. |
| `adults` | integer | No | `2` | Guests used to size the search and the rate (1-16). |
| `rooms` | integer | No | `1` | Rooms used to size the search (1-8). |
| `rankBy` | string | No | `value` | `value`, `rateValueScore`, `rateDrop`, `demand`, `softMarket`, `rating`, `recency`, `rate`. |
| `intent` | string | No | `find_value` | Preset shortcut: `find_value`, `monitor_rates`, `analyze_property`, `comp_shop`, `market_trends`. |
| `intentEnabled` | boolean | No | `false` | Turn on to let the intent preset fill mode + rankBy + output pack. |
| `outputPack` | string | No | `traveller` | Persona lens: `traveller`, `revenue-manager`, `investor`, `analyst`, `raw`. |
| `outputProfile` | string | No | `signals` | `signals`, `compat`, `minimal`. |
| `watchlistName` | string | No | `""` | Stable name for a comp-set; persists rate history across runs and unlocks deltas. |
| `watchlistMemory` | string | No | `shared` | `shared` feeds public aggregates; `private` keeps this comp-set out of the shared graph. |
| `marketId` | string | No | `""` | Id for a scheduled market subscription, e.g. `london_4star`. |
| `deltaWindowDays` | integer | No | `7` | Comparison window for delta intelligence (1-90). |
| `alerts` | object | No | `{}` | `{ minValueScore, onlyNewSinceLastRun, rateDropMinPct, scarcityThreshold, alertWhenValueImproves }`. |
| `filters` | object | No | `{}` | Property-attribute filters only: `{ starBand, propertyType, maxRate, minRating, breakfastIncluded }`. |
| `limits` | object | No | `{ maxProperties: 60, maxDetails: 30, maxDateScanFetches: 60 }` | Result and fetch caps (`maxProperties` <= 240). |
| `rateMemory` | object | No | `{ enabled: true, retentionDays: 365, includeInCommunityBenchmarks: true }` | Saved Rate Memory controls. |
| `dateScan` | object | No | `{ nights: 2, daysToScan: 14, weekdaysOnly: false }` | Date-scan range controls (`startDate`, `nights`, `daysToScan`, `weekdaysOnly`). |
| `maxRuntimeSeconds` | integer | No | `3600` | Soft runtime budget; auto-clamps and emits partial output before timeout. |
| `proxyConfiguration` | object | No | RESIDENTIAL | Apify proxy; residential is the default. |

#### Input examples

- **Recommended first run (rates):** `{ "mode": "rates", "destination": "London", "checkIn": "2026-08-10", "checkOut": "2026-08-12", "rankBy": "value" }`
- **Revenue-manager comp-shop (watchlist):** `{ "mode": "rates", "destination": "London", "checkIn": "2026-08-10", "checkOut": "2026-08-12", "watchlistName": "london-compset", "outputPack": "revenue-manager" }`
- **Cheapest-dates scan:** `{ "mode": "date_scan", "destination": "Paris", "dateScan": { "startDate": "2026-09-01", "nights": 2, "daysToScan": 21, "weekdaysOnly": true } }`

#### Input tips

- **Start with defaults** - `rates` mode with `rankBy: "value"` covers most rate-shopping and value-finding needs.
- **Pass dates for real rates** - rates are date-dependent; without `checkIn` and `checkOut` the data is thin and confidence is penalised.
- **Use a watchlist name to track over time** - a stable `watchlistName` keeps the rate-history clock running across runs.
- **Pick an output pack for your lens** - `revenue-manager` weights comp-shop and rate moves; `investor` weights soft markets; `analyst` weights demand and discovery.

### Output example

A single hotel record from a `rates` run (default `signals` profile, abbreviated):

```json
{
  "schemaVersion": "1.0",
  "recordType": "property",
  "eventId": "gb/the-northbank-hotel",
  "name": "The Northbank Hotel",
  "url": "https://www.booking.com/hotel/gb/the-northbank-hotel.html",
  "stars": 4,
  "price": 184,
  "currency": "GBP",
  "rating": 8.6,
  "reviews": 1402,
  "attention": {
    "attentionPriority": "high",
    "whyNow": ["Rate for Aug 10-12 dropped 18% in 10 days", "Now 12% under comparable 4-star comps"],
    "recommendedAction": "Review and compare to comp-set within 3 days",
    "respondWithinDays": 3
  },
  "rateValueScore": {
    "score": 78,
    "grade": "B",
    "components": { "belowComp": 22, "ratingPerDollar": 18, "rateDropDepth": 16, "amenityValue": 12, "locationValue": 10 },
    "penalties": { "smallCompSet": 0, "lowConfidence": 0, "noDatesProvided": 0 }
  },
  "demandPressure": { "score": 41, "occupancyBand": "moderate", "availabilityTrend": "flat", "marketOccupancyPercentile": 38 },
  "rateVelocity": -3.1,
  "compSet": { "compMedianRate": 209, "compCount": 31, "ratePositionPct": -12.0, "ratePerStarVsComp": -0.9, "competitivePosition": { "rank": 4, "of": 31 }, "method": "same-dates-area-starband" },
  "signalEvents": [
    { "type": "rate_drop", "signalStrength": 0.82, "decayStatus": "fresh", "reason": "Rate for Aug 10-12 fell 18% vs this hotel's own recent history.", "evidence": { "rateBefore": 224, "rateAfter": 184, "forDates": "2026-08-10/2026-08-12" } }
  ],
  "propertyProfile": { "label": "best-value", "strength": 0.74, "version": "1.0", "evidence": ["underpriced_vs_comp", "rating at/above comp median"] },
  "history": { "daysTracked": 42, "firstSeen": "2026-06-09", "dropCount": 2, "peakRate": 238, "currentVsPeakPct": -22.7, "trajectory": "cooling", "rateVelocity": -3.1, "rateVolatility": 34, "pricingDiscipline": "moderate", "firstSightFallback": false },
  "confidence": { "overall": 0.82, "grade": "high", "drivers": ["31 comparable hotels", "same dates + occupancy", "42 days rate history"], "limitations": [] }
}
```

The destination record adds `marketLifecycle`, `marketRegime`, `marketRateMomentum`, and `destinationIndices`. The summary record adds the headline, daily briefing, executive highlights, value queue, and store-wide leaderboards.

### Output fields

| Field | Type | Description |
|-------|------|-------------|
| `recordType` | string | `property`, `destination`, `rateCard`, `event`, `rateFeed`, `marketSnapshot`, `coverage`, `summary`, `watchlistBriefing`, `comparison`, or `error`. |
| `attention.attentionPriority` | string | `high`, `medium`, `low`, `none`; the queue sort column. |
| `attention.whyNow` | array | Up to 3 paste-ready reasons this record needs attention. |
| `attention.recommendedAction` | string | Verb-fenced next step (Review, Compare, Re-check, never Book or Reserve). |
| `rateValueScore.score` | number | 0-100 value score with an A-F `grade` and auditable components. |
| `demandPressure.score` | number | 0-100 occupancy pressure; 88 = selling out, 20 = soft. |
| `rateVelocity` | number | Rate-of-change of the value score over the tracked window. |
| `compSet.competitivePosition` | object | This hotel's rank among comparable properties (e.g. 4th of 31). |
| `compSet.ratePositionPct` | number | Percent under (negative) or over the comp median. |
| `signalEvents` | array | Typed, evidenced rate and demand shift events with strength and decay. |
| `propertyProfile.label` | string | One of 8 archetypes (best-value, rate-dropper, selling-out, and so on). |
| `history` | object | Saved Rate Memory: trajectory, drop count, peak-vs-current, volatility, drift. |
| `historicalOutcomeProfile` | object | Descriptive cohort history over past similar stays; honest-null until enough closed stays. |
| `confidence.grade` | string | `high`, `medium`, `low`; low when no dates are provided. |
| `marketRegime.regime` | string | `buyers_market`, `sellers_market`, or `balanced` (destination records). |
| `destinationIndices` | object | Value, demand, volatility, and opportunity indices, each 0-100 (destination records). |
| `changeFlags` | array | Watchlist flags: NEW, RATE\_DROP, RATE\_SPIKE, SOLD\_OUT, BACK\_IN\_STOCK, UNCHANGED. |
| `coverageGrade` | string | `full`, `partial`, or `thin`; never claims full on a capped run. |

### Rate-shop hotels using the API

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("ryanclinton/booking-scraper").call(run_input={
    "mode": "rates",
    "destination": "London",
    "checkIn": "2026-08-10",
    "checkOut": "2026-08-12",
    "rankBy": "value",
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item.get("recordType") == "property":
        rvs = item.get("rateValueScore", {})
        att = item.get("attention", {})
        print(f"{item.get('name')}: value={rvs.get('score')} action={att.get('recommendedAction')}")
```

#### JavaScript

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

const client = new ApifyClient({ token: "YOUR_API_TOKEN" });

const run = await client.actor("ryanclinton/booking-scraper").call({
    mode: "rates",
    destination: "London",
    checkIn: "2026-08-10",
    checkOut: "2026-08-12",
    rankBy: "value",
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
    if (item.recordType === "property") {
        console.log(`${item.name}: value=${item.rateValueScore?.score} action=${item.attention?.recommendedAction}`);
    }
}
```

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/ryanclinton~booking-scraper/runs?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "mode": "rates", "destination": "London", "checkIn": "2026-08-10", "checkOut": "2026-08-12", "rankBy": "value" }'

curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_API_TOKEN&format=json"
```

![How it works: destination and dates in, comp-set, signals, value scoring, Saved Rate Memory, ranked value queue out](https://apifyforge.com/readme-assets/ryanclinton-booking-scraper/intelligence-layers.png)

### How Booking Scraper works

**Mental model:** Booking pages to substrate, substrate to comp-sets, comp-sets and rate history to signals, signals to a value score, score to a routed decision, all wrapped in a trust layer.

#### 1. Collect the public substrate

Booking Scraper collects public Booking.com search and hotel pages over residential proxies for your dates, and handles Booking's automated-access limits from shared IPs. It parses each hotel into the faithful substrate, validates that every `url` resolves to its id, and drops any record with an unresolvable link rather than emitting a broken row.

#### 2. Build comp-sets and value

For each destination it groups comparable hotels (same dates, area, star-band), computes the comp median and your rate's position, and derives the auditable `rateValueScore` with components and penalties.

#### 3. Detect signals against rate history

With Saved Rate Memory active, Booking Scraper loads the prior snapshots for each hotel and stay-date and detects shifts: rate drops, underpriced-vs-comp, scarcity, demand surges, and soft-market trajectories. Thin or cold-start data surfaces as honest-null.

#### 4. Score value and route a decision

Each record gets an `attentionPriority`, a `whyNow`, and a verb-fenced `recommendedAction`. The output pack reshapes what escalates. The rate snapshots are then persisted for the next run.

### Tips for best results

1. **Schedule a daily watchlist.** Saved Rate Memory only compounds if you run it. A daily cadence builds the rate trajectory and the outcome history.
2. **Pick rankBy to match the job.** Use `rateDrop` for cut-hunting, `value` for best-value, `demand` for scarcity reads, `softMarket` for buyer's-market trajectory.
3. **Set an output pack.** `revenue-manager` weights comp-shop and rate moves; `traveller` weights value and drops.
4. **Read confidence before trusting a value score.** A low grade means thin data (often no dates or a small comp-set); pass dates and widen the destination to lift it.
5. **Route the Rate Feed.** Pipe the Rate Feed into the actors below to push only critical-severity events into a sheet, CRM, or alert.

### Combine with other Apify actors

| Actor | How to combine |
|-------|---------------|
| [Website Change Monitor](https://apify.com/ryanclinton/website-change-monitor) | Track hotel websites alongside the Booking value queue. |
| [Website Contact Scraper](https://apify.com/ryanclinton/website-contact-scraper) | Pull contact details for hotels surfaced in the queue. |
| [Trustpilot Review Analyzer](https://apify.com/ryanclinton/trustpilot-review-analyzer) | Add off-platform sentiment for a flagged property. |
| [Company Deep Research](https://apify.com/ryanclinton/company-deep-research) | Research the operator behind a hotel group. |
| [HubSpot Lead Pusher](https://apify.com/ryanclinton/hubspot-lead-pusher) | Push attention-flagged hotels into your CRM. |
| [Google Maps Lead Enricher](https://apify.com/ryanclinton/google-maps-lead-enricher) | Enrich a destination's hospitality leads from Maps. |

### What this does NOT do

- **Not a booking or checkout tool.** Booking Scraper reads public search and hotel pages only. It does not book, reserve, or touch the payment flow, and it accesses no booking-flow, confirmation, or "my booking" pages.
- **No member-only or login rates.** It reads public rates only. No login, no CAPTCHA bypass, no member-only or loyalty-gated pricing.
- **It does not predict prices or tell you when to book.** `historicalOutcomeProfile` is descriptive cohort history ("similar past stays dropped a median 9% in the final two weeks"), never a forecast and never a "book now" prompt about a specific hotel.
- **No reviewer personal data.** Review scores and counts only, never reviewer personal details.
- **Descriptive, not advisory.** It describes rate and demand position. It is not investment or pricing advice; the per-record action is prioritisation only (Review, Compare, Re-check), never a transaction instruction.

### Why use Booking Scraper instead of a spreadsheet or an enterprise dashboard?

![Same data, different output: comp-set position, saved rate history, watchlist deltas, value scoring and demand signals vs a generic Booking scraper](https://apifyforge.com/readme-assets/ryanclinton-booking-scraper/comparison.png)

Rate-shopping a comp-set by hand means scraping competitors per date, dumping to Excel, comparing rates by hand, and repeating daily. It is slow, it goes stale, and the comp logic lives in one analyst's head. Enterprise hospitality dashboards solve the analysis but charge enterprise prices, lock the data behind their UI, and are built for human-driven browsing rather than automation.

The real competitor isn't another scraper. It's the spreadsheet. Booking Scraper is built for automation-first workflows: it returns finished, structured decisions with accumulated rate history, on the Booking data you already use. It brings the rate intelligence those tools charge enterprise prices for to a single Apify actor.

#### Booking Scraper vs voyager/booking-scraper

Same data source, same input, same fields (set `outputProfile: "compat"` for exact parity). The difference is the output contract: `voyager/booking-scraper` and its siblings return rows and split the job across three actors, so you assemble the comp-set logic, value scoring, and rate history yourself. Booking Scraper returns the decision (value queue, comp-set position, rate signals, Saved Rate Memory) from one actor instead of the suite.

#### Booking Scraper vs OTA Insight, Lighthouse, and AirDNA

If you are looking for a lightweight, automation-first alternative to enterprise hotel rate-shopping software, Booking Scraper covers the rate-intelligence job on the public Booking data you already use, as structured JSON or CSV you can automate against, at Apify pricing rather than enterprise pricing. It is not a full replacement for those platforms' hospitality suites and their licensed datasets; it ships the comp-set position, value scoring, rate signals, and accumulated rate history as output that drops into your own pipeline.

**Key difference: Booking Scraper ships the decision layer and the accumulated rate history that raw scrapers and closed dashboards do not put in your pipeline.**

| Feature | Booking Scraper | Raw Booking scrapers | Enterprise hospitality dashboards |
|---------|-----------------|----------------------|-----------------------------------|
| Data source | Public Booking.com pages | Public Booking.com pages | Licensed and modelled datasets |
| Comp-set rate position | Yes, per hotel | No | Yes, in dashboard |
| Value queue and routing | Yes | No | Not a core feature |
| Rate history | Saved Rate Memory, compounds every run | Not a core feature | Internal to the product |
| Rate-drop and demand signals | Yes, typed and evidenced | No | Varies by plan |
| Output format | JSON, CSV, Excel, API | Raw rows | Dashboard, varies by plan |
| Automation and scheduling | Native on Apify | Varies | Limited, UI-first |
| Best for | Automated rate-shopping and value-finding | Bulk row collection | Human-driven enterprise analysis |

*Features based on publicly available information as of June 2026 and may change.*

### Responsible use

- Booking Scraper collects publicly available rate, availability, and rating data from Booking.com. It does not bypass authentication or CAPTCHAs, access member-only rates, or touch the booking or payment flow, and it performs no in-platform actions.
- Users are responsible for ensuring their use complies with applicable laws and platform terms, including data protection regulations in their jurisdiction.
- Rate history is descriptive and timestamped; it is not a forecast or booking advice. Do not present it as a prediction or use it as the sole basis for a transaction decision.
- For guidance on web scraping legality, see [Apify's guide](https://blog.apify.com/is-web-scraping-legal/).

### Limitations

- **Public data only.** No login, no member-only rates, no booking-flow or payment-page data.
- **Rates are date-dependent.** Booking only returns complete per-date pricing with `checkIn` and `checkOut`; a dateless run is thin and confidence is penalised.
- **Rate history needs runs.** `rateVelocity`, trajectory, and `historicalOutcomeProfile` require accumulated runs; they return honest-null until Saved Rate Memory matures.
- **Comp-set quality varies.** A destination with too few comparable hotels returns a null cohort with `insufficient-cohort`; comp-based signals weaken when the comp-set is thin.
- **Destination sample caps at 240.** `maxProperties` caps the sample; `coverageGrade` reports whether the run was full, partial, or thin.
- **Rates are a point-in-time snapshot.** Rates change constantly; every stored rate is timestamped and date-keyed, but a snapshot can go stale between runs.
- **Renaming a watchlist resets memory.** State is keyed on `watchlistName`; a new name starts a fresh memory clock.

### Integrations

- [Zapier](https://apify.com/integrations/zapier) - schedule a daily watchlist run so the rate memory compounds, and route the Rate Feed onward.
- [Make](https://apify.com/integrations/make) - branch on event severity to fire alerts only for critical rate moves.
- [Google Sheets](https://apify.com/integrations/google-sheets) - append the daily value queue or Rate Shop Matrix to a tracking sheet.
- [Apify API](https://docs.apify.com/api/v2) - run Booking Scraper from any HTTP client and read the dataset.
- [Webhooks](https://docs.apify.com/platform/integrations/webhooks) - push run completion into your own pipeline.
- [LangChain / LlamaIndex](https://docs.apify.com/platform/integrations) - feed the Rate Feed and rate cards to an AI agent.

### Common hotel rate-intelligence questions

#### How do I find underpriced hotels for my dates?

Run `rates` mode with `rankBy: "value"` and your `checkIn` / `checkOut`. Each hotel returns `rateValueScore`, its `compSet` position, and a `propertyProfile` of best-value, overpriced, and so on.

#### How do I track hotel rate drops?

Run `rates` with `rankBy: "rateDrop"`, or a watchlist with `alerts.rateDropMinPct`. The Rate Drops view returns hotels with rate\_drop and sustained\_rate\_drop signals by depth.

#### How do I rate-shop my competitor set?

Run any mode with a stable `watchlistName` and a competitor hotel set. The Competitor Movers view shows which hotels changed rate since the last run, by change % x days.

#### How do I find the cheapest dates to stay?

Run `date_scan` with a `dateScan` range. You get `bestDates` plus a `rateCalendar` with a seasonality index, cheapest and priciest week, and month medians.

#### How do I benchmark my own hotel?

Run `benchmark` mode with `myHotelUrl` and the destination. You get your property ranked within its market on rate, value, occupancy pressure, pricing discipline, and comp-set drift.

#### How do I send rate alerts to Slack or a CRM?

Set `alerts` and route the Rate Feed through Zapier, Make, or a webhook, branching on event severity so only critical rate moves fire.

### FAQ

**What is the difference between a Booking scraper and a Booking rate-intelligence tool?** A scraper returns raw rows. Booking Scraper runs as a rate-intelligence engine: it ranks hotels by value for your dates, detects which rates moved, and keeps the rate history, so you get a decision rather than a dataset.

**How do I rate-shop hotels for my dates?** Run `rates` mode with a destination, `checkIn`, `checkOut`, and `rankBy: "value"`. You get a ranked value queue with comp-set position and a recommended action in about 60 seconds.

**Can I use Booking Scraper to find underpriced hotels?** Yes. Set `rankBy: "value"` or `rateValueScore`; each hotel carries its position vs comparable properties and a best-value or overpriced archetype.

**Does this actor tell me when to book?** No. It does not predict rates or prompt a booking. `historicalOutcomeProfile` is descriptive history of how rates for similar stays moved toward the date, with a sample size, never a forecast and never a "book now" instruction.

**Does it keep the rate history?** Yes. Saved Rate Memory banks a timestamped public rate, availability, and rating snapshot on every property and date a run touches, keyed by hotel and stay-date. A fresh hotel returns `firstSightFallback` rather than inventing a past.

**Can I migrate from my existing Booking scraper without changing my code?** Yes. Pass the same destination, hotel URLs, and dates, and set `outputProfile: "compat"` for the exact `voyager/booking-scraper` field set with validated URLs. The signal layer is additive on the default profile.

**How do I monitor a comp-set over time?** Run any mode with a stable `watchlistName` and schedule a daily run. Each run returns what changed (`changeFlags`, `rateChange`) and a Competitor Movers rollup of who moved their rates.

**Can I scan a date range for the cheapest dates?** Yes. Use `date_scan` with a `dateScan` range; you get `bestDates` and a seasonality `rateCalendar`. The worst-case fetch count is logged before the scan and capped by `limits.maxDateScanFetches`.

**Does it read member-only or login rates?** No. It reads public rates only. No login, no CAPTCHA bypass, no booking-flow or payment-page data.

**How is Booking Scraper a practical alternative to an enterprise hospitality dashboard for rate-shopping?** It brings the rate intelligence those tools charge enterprise prices for to the Booking data you already use, returning structured comp-set position and rate signals per query in JSON or CSV for automation-first workflows, with rate history that compounds. It uses public data and descriptive history, not licensed datasets.

**What happens on a destination with too few comparable hotels?** The cohort returns null with `insufficient-cohort`, and comp-based signals are fenced as low confidence rather than asserted on a thin comp-set.

**Is it legal to scrape Booking.com data?** Booking Scraper accesses only public content and performs no in-platform actions or booking-flow scraping. Whether your specific use is permitted depends on your jurisdiction and intended use, including data protection rules; consult legal counsel for your situation. See [Apify's guide on scraping legality](https://blog.apify.com/is-web-scraping-legal/).

### Help us improve

If you encounter issues, you can help us debug faster by enabling run sharing in your Apify account:

1. Go to [Account Settings > Privacy](https://console.apify.com/account/privacy)
2. Enable **Share runs with public Actor creators**

This lets us see your run details when something goes wrong, so we can fix issues faster. Your data is only visible to the actor developer, not publicly.

### Support

Found a bug or have a feature request? Open an issue in the Issues tab on this actor's page. For custom solutions or enterprise integrations, reach out through the Apify platform.

# Actor input Schema

## `mode` (type: `string`):

Entry point. 'rates' (default) ranks a destination's hotels by value for your dates. 'properties' analyses specific hotel URLs. 'market' returns a destination's rate/demand trajectory + indices. 'benchmark' ranks YOUR hotel within its market. 'watchlist' tracks a comp-set and returns what changed since last run. 'date\_scan' scans a date range for the cheapest/best-value dates + a rate calendar. Leave fields empty to use the London demo.

## `destination` (type: `string`):

Rates / market / watchlist / date\_scan: a city or area, e.g. 'London'. The actor ranks hotels by where they sit vs comparable properties and how the market is moving.

## `checkIn` (type: `string`):

Stay start date. Booking only returns complete per-date rates with dates - leave empty and the actor uses a demo window, but real value needs your dates (confidence is penalised without them).

## `checkOut` (type: `string`):

Stay end date.

## `propertyUrls` (type: `array`):

Properties mode: Booking /hotel/<country>/<slug>.html URLs to analyse. Each result carries its rate position vs comparable properties + rate history.

## `myHotelUrl` (type: `string`):

Benchmark mode: your own property's Booking URL. The actor ranks it within its market on rate, value, occupancy pressure, pricing discipline, and comp-set drift.

## `adults` (type: `integer`):

Number of guests used to size the search and the rate.

## `rooms` (type: `integer`):

Number of rooms used to size the search.

## `rankBy` (type: `string`):

How to order the value queue. 'value' (default) and 'rateValueScore' are the wedge no other Booking actor ships. 'rateDrop' surfaces the biggest cuts. 'demand' surfaces tightest-availability hotels. 'softMarket' sorts by buyer's-market trajectory. 'rate' is cheapest-first.

## `intent` (type: `string`):

Optional shortcut. Picks mode + rankBy + output pack for a common job, so you do not have to set them by hand. Overridden by any field you set explicitly.

## `intentEnabled` (type: `boolean`):

Off by default so the mode/rankBy you pick above are used as-is. Turn on to let the intent preset fill mode + rankBy + output pack.

## `outputPack` (type: `string`):

Reshapes which signals escalate and how the queue is curated. 'traveller' (default) weights value + drops; 'revenue-manager' weights comp-shop + rate moves; 'investor' weights soft markets; 'analyst' weights demand + discovery; 'raw' applies no persona lens.

## `outputProfile` (type: `string`):

'signals' (default) = full envelope: rate value score + comp position + signals + attention + rate history + delta. 'compat' = exact voyager field set with validated URLs/IDs, no signal fields (migration parity). 'minimal' = name + URL + rate + value score only.

## `watchlistName` (type: `string`):

Composable on any mode. A stable name for this comp-set / market. Rate, availability, and rating history persist in a named store keyed on this name across runs, so you get a 'what changed' delta + a Competitor Movers feed. The retention moat for revenue managers.

## `watchlistMemory` (type: `string`):

'shared' (default) lets your queries strengthen the cross-run rate-history graph (public aggregates only, no per-customer attribution). 'private' keeps this comp-set out of the shared graph.

## `marketId` (type: `string`):

Optional id for a scheduled market subscription, e.g. 'london\_4star'. Accumulates days-tracked + observations across scheduled runs.

## `deltaWindowDays` (type: `integer`):

The comparison window for delta intelligence (what changed since the prior run) and the new-property window.

## `alerts` (type: `object`):

Emit only actionable items + rate cards. { minValueScore (only surface records at/above this score), onlyNewSinceLastRun (watchlist: only changed records), rateDropMinPct (only drops at/above this depth), scarcityThreshold (rooms-left at/below this = scarcity), alertWhenValueImproves }.

## `filters` (type: `object`):

Property-attribute filters ONLY. { starBand ('1-2'|'3'|'4'|'5'), propertyType, maxRate, minRating (0-10 review score), breakfastIncluded }. No demographic or desirability filters.

## `limits` (type: `object`):

Result + fetch caps. { maxProperties (per destination, <=240), maxDetails, maxDateScanFetches (caps the date\_scan fetch budget) }.

## `rateMemory` (type: `object`):

The moat. { enabled (default true - accrues a public rate/availability/rating snapshot on every property+date this run touches), retentionDays (default 365), includeInCommunityBenchmarks (opt-in to public aggregate benchmarks) }.

## `dateScan` (type: `object`):

Date-scan controls. { startDate (YYYY-MM-DD), nights (stay length per check-in), daysToScan (how many check-in dates), weekdaysOnly }. The worst-case fetch count is logged before the scan and capped by limits.maxDateScanFetches.

## `maxRuntimeSeconds` (type: `integer`):

Soft runtime budget. The actor auto-clamps against the Apify timeout and emits partial output before a hard kill.

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

Apify proxy. Defaults to RESIDENTIAL. Leave as default unless you have a reason to change it.

## Actor input object example

```json
{
  "mode": "rates",
  "destination": "London",
  "checkIn": "",
  "checkOut": "",
  "propertyUrls": [],
  "myHotelUrl": "",
  "adults": 2,
  "rooms": 1,
  "rankBy": "value",
  "intent": "find_value",
  "intentEnabled": false,
  "outputPack": "traveller",
  "outputProfile": "signals",
  "watchlistName": "",
  "watchlistMemory": "shared",
  "marketId": "",
  "deltaWindowDays": 7,
  "alerts": {},
  "filters": {},
  "limits": {
    "maxProperties": 60,
    "maxDetails": 30,
    "maxDateScanFetches": 60
  },
  "rateMemory": {
    "enabled": true,
    "retentionDays": 365,
    "includeInCommunityBenchmarks": true
  },
  "dateScan": {
    "nights": 2,
    "daysToScan": 14,
    "weekdaysOnly": false
  },
  "maxRuntimeSeconds": 3600,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "mode": "rates",
    "destination": "London",
    "checkIn": "",
    "checkOut": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("ryanclinton/booking-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 = {
    "mode": "rates",
    "destination": "London",
    "checkIn": "",
    "checkOut": "",
}

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

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

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

```

## CLI example

```bash
echo '{
  "mode": "rates",
  "destination": "London",
  "checkIn": "",
  "checkOut": ""
}' |
apify call ryanclinton/booking-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=ryanclinton/booking-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Booking Scraper — Rate Intelligence, Comp-Set & Price Drops",
        "description": "Booking.com rate-intelligence engine. Returns a ranked value queue — which hotels are underpriced vs comparable properties, whose rates dropped, where demand is softening — with Saved Rate Memory, comp-set position, and watchlist deltas. Drop-in replacement for voyager/booking-scraper.",
        "version": "1.0",
        "x-build-id": "Gzn472oFM0FjyCaoz"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/ryanclinton~booking-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-ryanclinton-booking-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/ryanclinton~booking-scraper/runs": {
            "post": {
                "operationId": "runs-sync-ryanclinton-booking-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/ryanclinton~booking-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-ryanclinton-booking-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "mode": {
                        "title": "Mode",
                        "enum": [
                            "rates",
                            "properties",
                            "market",
                            "benchmark",
                            "watchlist",
                            "date_scan"
                        ],
                        "type": "string",
                        "description": "Entry point. 'rates' (default) ranks a destination's hotels by value for your dates. 'properties' analyses specific hotel URLs. 'market' returns a destination's rate/demand trajectory + indices. 'benchmark' ranks YOUR hotel within its market. 'watchlist' tracks a comp-set and returns what changed since last run. 'date_scan' scans a date range for the cheapest/best-value dates + a rate calendar. Leave fields empty to use the London demo."
                    },
                    "destination": {
                        "title": "Destination (city / area)",
                        "type": "string",
                        "description": "Rates / market / watchlist / date_scan: a city or area, e.g. 'London'. The actor ranks hotels by where they sit vs comparable properties and how the market is moving.",
                        "default": "London"
                    },
                    "checkIn": {
                        "title": "Check-in date (YYYY-MM-DD)",
                        "type": "string",
                        "description": "Stay start date. Booking only returns complete per-date rates with dates - leave empty and the actor uses a demo window, but real value needs your dates (confidence is penalised without them).",
                        "default": ""
                    },
                    "checkOut": {
                        "title": "Check-out date (YYYY-MM-DD)",
                        "type": "string",
                        "description": "Stay end date.",
                        "default": ""
                    },
                    "propertyUrls": {
                        "title": "Hotel URLs (properties / date_scan)",
                        "type": "array",
                        "description": "Properties mode: Booking /hotel/<country>/<slug>.html URLs to analyse. Each result carries its rate position vs comparable properties + rate history.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "myHotelUrl": {
                        "title": "My hotel URL (benchmark mode)",
                        "type": "string",
                        "description": "Benchmark mode: your own property's Booking URL. The actor ranks it within its market on rate, value, occupancy pressure, pricing discipline, and comp-set drift.",
                        "default": ""
                    },
                    "adults": {
                        "title": "Guests (adults)",
                        "minimum": 1,
                        "maximum": 16,
                        "type": "integer",
                        "description": "Number of guests used to size the search and the rate.",
                        "default": 2
                    },
                    "rooms": {
                        "title": "Rooms",
                        "minimum": 1,
                        "maximum": 8,
                        "type": "integer",
                        "description": "Number of rooms used to size the search.",
                        "default": 1
                    },
                    "rankBy": {
                        "title": "Rank by",
                        "enum": [
                            "value",
                            "rateValueScore",
                            "rateDrop",
                            "demand",
                            "softMarket",
                            "rating",
                            "recency",
                            "rate"
                        ],
                        "type": "string",
                        "description": "How to order the value queue. 'value' (default) and 'rateValueScore' are the wedge no other Booking actor ships. 'rateDrop' surfaces the biggest cuts. 'demand' surfaces tightest-availability hotels. 'softMarket' sorts by buyer's-market trajectory. 'rate' is cheapest-first.",
                        "default": "value"
                    },
                    "intent": {
                        "title": "Intent (auto-presets)",
                        "enum": [
                            "find_value",
                            "monitor_rates",
                            "analyze_property",
                            "comp_shop",
                            "market_trends"
                        ],
                        "type": "string",
                        "description": "Optional shortcut. Picks mode + rankBy + output pack for a common job, so you do not have to set them by hand. Overridden by any field you set explicitly.",
                        "default": "find_value"
                    },
                    "intentEnabled": {
                        "title": "Use the intent preset",
                        "type": "boolean",
                        "description": "Off by default so the mode/rankBy you pick above are used as-is. Turn on to let the intent preset fill mode + rankBy + output pack.",
                        "default": false
                    },
                    "outputPack": {
                        "title": "Output pack (persona)",
                        "enum": [
                            "traveller",
                            "revenue-manager",
                            "investor",
                            "analyst",
                            "raw"
                        ],
                        "type": "string",
                        "description": "Reshapes which signals escalate and how the queue is curated. 'traveller' (default) weights value + drops; 'revenue-manager' weights comp-shop + rate moves; 'investor' weights soft markets; 'analyst' weights demand + discovery; 'raw' applies no persona lens.",
                        "default": "traveller"
                    },
                    "outputProfile": {
                        "title": "Output profile",
                        "enum": [
                            "signals",
                            "compat",
                            "minimal"
                        ],
                        "type": "string",
                        "description": "'signals' (default) = full envelope: rate value score + comp position + signals + attention + rate history + delta. 'compat' = exact voyager field set with validated URLs/IDs, no signal fields (migration parity). 'minimal' = name + URL + rate + value score only.",
                        "default": "signals"
                    },
                    "watchlistName": {
                        "title": "Watchlist name",
                        "type": "string",
                        "description": "Composable on any mode. A stable name for this comp-set / market. Rate, availability, and rating history persist in a named store keyed on this name across runs, so you get a 'what changed' delta + a Competitor Movers feed. The retention moat for revenue managers.",
                        "default": ""
                    },
                    "watchlistMemory": {
                        "title": "Watchlist memory sharing",
                        "enum": [
                            "shared",
                            "private"
                        ],
                        "type": "string",
                        "description": "'shared' (default) lets your queries strengthen the cross-run rate-history graph (public aggregates only, no per-customer attribution). 'private' keeps this comp-set out of the shared graph.",
                        "default": "shared"
                    },
                    "marketId": {
                        "title": "Market subscription id (scheduled market mode)",
                        "type": "string",
                        "description": "Optional id for a scheduled market subscription, e.g. 'london_4star'. Accumulates days-tracked + observations across scheduled runs.",
                        "default": ""
                    },
                    "deltaWindowDays": {
                        "title": "Delta window (days)",
                        "minimum": 1,
                        "maximum": 90,
                        "type": "integer",
                        "description": "The comparison window for delta intelligence (what changed since the prior run) and the new-property window.",
                        "default": 7
                    },
                    "alerts": {
                        "title": "Alerts",
                        "type": "object",
                        "description": "Emit only actionable items + rate cards. { minValueScore (only surface records at/above this score), onlyNewSinceLastRun (watchlist: only changed records), rateDropMinPct (only drops at/above this depth), scarcityThreshold (rooms-left at/below this = scarcity), alertWhenValueImproves }.",
                        "default": {}
                    },
                    "filters": {
                        "title": "Filters (property-attribute only)",
                        "type": "object",
                        "description": "Property-attribute filters ONLY. { starBand ('1-2'|'3'|'4'|'5'), propertyType, maxRate, minRating (0-10 review score), breakfastIncluded }. No demographic or desirability filters.",
                        "default": {}
                    },
                    "limits": {
                        "title": "Limits",
                        "type": "object",
                        "description": "Result + fetch caps. { maxProperties (per destination, <=240), maxDetails, maxDateScanFetches (caps the date_scan fetch budget) }.",
                        "default": {
                            "maxProperties": 60,
                            "maxDetails": 30,
                            "maxDateScanFetches": 60
                        }
                    },
                    "rateMemory": {
                        "title": "Saved Rate Memory",
                        "type": "object",
                        "description": "The moat. { enabled (default true - accrues a public rate/availability/rating snapshot on every property+date this run touches), retentionDays (default 365), includeInCommunityBenchmarks (opt-in to public aggregate benchmarks) }.",
                        "default": {
                            "enabled": true,
                            "retentionDays": 365,
                            "includeInCommunityBenchmarks": true
                        }
                    },
                    "dateScan": {
                        "title": "Date scan range (date_scan mode)",
                        "type": "object",
                        "description": "Date-scan controls. { startDate (YYYY-MM-DD), nights (stay length per check-in), daysToScan (how many check-in dates), weekdaysOnly }. The worst-case fetch count is logged before the scan and capped by limits.maxDateScanFetches.",
                        "default": {
                            "nights": 2,
                            "daysToScan": 14,
                            "weekdaysOnly": false
                        }
                    },
                    "maxRuntimeSeconds": {
                        "title": "Max runtime (seconds)",
                        "minimum": 60,
                        "maximum": 7200,
                        "type": "integer",
                        "description": "Soft runtime budget. The actor auto-clamps against the Apify timeout and emits partial output before a hard kill.",
                        "default": 3600
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Apify proxy. Defaults to RESIDENTIAL. Leave as default unless you have a reason to change it.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
