# Expedia Room Rates Scraper (`boncross/expedia-room-rates`) Actor

Scrape every room Expedia and Hotels.com are selling for a hotel and your dates. Just add property IDs or hotel links and get room name, size, nightly price, stay total with taxes, board, cancellation terms and payment policy. $3.50 per 1,000 priced hotel-stays.

- **URL**: https://apify.com/boncross/expedia-room-rates.md
- **Developed by:** [BonCross API](https://apify.com/boncross) (community)
- **Categories:** Travel
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 hotel-priceds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Expedia Room Rates Scraper

### What is Expedia Room Rates Scraper?

A hotel on Expedia doesn't have one price. It has a grid: each room, sold several ways, refundable or not, with breakfast or without. Expedia Room Rates Scraper gets you that whole grid for a hotel and your dates, one row per rate, from Expedia or Hotels.com. Paste property IDs or hotel links, set the dates, and you're done.

Four things you won't get from a search-level price:

- **All the rates, not the cheapest one.** Individual hotels returned 13 to 58 rows each in the measured runs, and 40 hotels over two stays returned 1,635.
- **Refundable against non-refundable, for the same room.** Each row says whether the rate can be cancelled and until when, in the site's own words, next to its board and payment terms.
- **A price calendar on top.** Switch it on and you get a nightly price for each date the hotel is bookable, around 217 dates or roughly eight months ahead.
- **Change tracking that saves you money.** A hotel and stay whose cheapest price hasn't moved since your last run is skipped, and costs $0.0005.

It's priced per hotel and stay, not per row: $3.50 per 1,000 priced hotel-stays on the Free plan and $2.60 on Business, however many rates each one has. Proxy usage and platform usage are included.

**BonCross Verified** means we tested this actor against the live site before release and kept the record:

- 36 of 36 live checks on its inputs and filters passed on 7 October 2026
- 7 hotels run the same day on 3 stays each: 248 rates, 4 sold-out answers, 1 error row
- A stay the site does not answer gets an error row saying so

### What data is in a rate row?

| | |
|---|---|
| 🏨 Hotel name and property ID | Site (Expedia or Hotels.com) |
| 🛏 Room name | Bed setup |
| 📐 Room size | 👥 Sleeps (max occupancy) |
| ⭐ Guest rating for that room type | Room and rate IDs |
| 💵 Price per night | 💰 Stay total with taxes and fees |
| Price as displayed | Price before discount |
| 💱 Currency | Whether tax is in the nightly rate, and the pre-tax nightly price |
| 🍳 Board | Whether a meal is included |
| Cancellation terms and deadline | Refundable flag |
| 💳 Payment terms | Sold-out flag |
| 📅 Check-in, check-out and nights | Adults, child ages and rooms priced |
| Price calendar dates (optional) | Market the prices came from |
| 🔗 Link to the booking page | Timestamp of the run |

### Who uses a rate grid?

Revenue managers tracking a competitor set across a season, to see which rooms move first. Analysts putting a value on flexibility by comparing the refundable and non-refundable price of one room. Hotels checking that their own rates and board descriptions are listed as intended. Teams running a rate-parity check of one site's grid against another's, or building a price history from a daily run with change tracking on. The calendar answers a different question: how far ahead a hotel starts discounting.

### How to scrape Expedia room rates

1. [Sign up for a free Apify account](https://console.apify.com/sign-up).
2. Open [Expedia Room Rates Scraper](https://apify.com/boncross/expedia-room-rates).
3. Put property IDs or hotel page links into Hotels. If you have a long list, load it through Start URLs from a file or a Google Sheet.
4. Choose Expedia or Hotels.com. A link you paste already names its own site.
5. Set check-in and check-out, or leave them empty and set days ahead.
6. Click Start. One hotel takes about 3 seconds. Download the rates as Excel, CSV or JSON.

### ⬇️ Input

A hotel is a property ID or a hotel page link, in any mix. The link `https://www.expedia.com/Santorini-Hotels-Ira-Hotel-Spa.h6116875.Hotel-Information` and the bare number `6116875` mean the same thing. Don't have the IDs? [Expedia Hotel Search Scraper](https://apify.com/boncross/expedia-hotel-search) returns them for a whole destination.

#### Two hotels, one weekend

```json
{
  "hotels": ["12570", "https://www.expedia.com/Santorini-Hotels-Ira-Hotel-Spa.h6116875.Hotel-Information"],
  "checkIn": "2026-11-13",
  "checkOut": "2026-11-15",
  "adults": 2,
  "rooms": 1
}
```

#### Only refundable rates, the three cheapest per hotel, with a Hotels.com link in the list

```json
{
  "hotels": ["12570", "https://www.hotels.com/ho3388/"],
  "checkIn": "2026-11-13",
  "checkOut": "2026-11-15",
  "freeCancellationOnly": true,
  "maxRatePlansPerStay": 3
}
```

#### One hotel across three stays, with a row when a stay is sold out

```json
{
  "hotels": ["375613"],
  "checkIn": "2026-10-24",
  "checkOut": "2026-10-25",
  "stays": ["2026-12-31_2027-01-02", "2027-02-10_2027-02-13"],
  "maxRatePlansPerStay": 25,
  "includeUnavailable": true
}
```

#### The rate grid plus thirty days of calendar prices

```json
{
  "hotels": ["12570"],
  "checkIn": "2026-11-13",
  "checkOut": "2026-11-15",
  "priceCalendar": true,
  "calendarDaysMax": 30
}
```

#### A daily watch that returns only what moved

```json
{
  "hotels": ["12570", "375613"],
  "checkInDaysAhead": 30,
  "nights": 2,
  "priceStoreName": "my-comp-set",
  "onlyNewOrChanged": true
}
```

**Three limits, three different jobs.** "Maximum rates per hotel and stay" keeps only the cheapest N rates for each hotel and date range. "Maximum hotel-stays for the whole run" stops after that many hotel-stays, each with all its rates. "Maximum rows for the whole run" stops once that many rows exist, cutting the last hotel-stay to fit and keeping its cheapest rates. Price-calendar rows count towards it. 0 means no limit on each.

**Filters.** "Refundable rates only" keeps rates the site states can be cancelled. "Rates including a meal only" keeps rates with breakfast or another meal. "Maximum price per night" drops rates above a nightly price in the market's currency, and rates with no price.

**Guests and rooms.** Adults (1 to 14, default 2) and one age per child set the party. "Rooms" prices a booking of several rooms: the nightly rate stays per room and the stay total covers them all, which is how the site quotes it. Asking for more rooms can return fewer rows, because a room with one unit left can't be booked twice. That's the site telling you about availability, not rows going missing.

**Market decides the money.** Expedia runs 40 country sites and each quotes its own currency. Pick Japan and you get JPY, pick the United States and you get USD, for the same hotel on the same dates. Nothing is converted afterwards: these are the prices that market shows a traveller. Leave Market on Auto and the first pasted link's own site sets it for the run. An `expedia.se` link is quoted in SEK, and a list of bare property IDs uses the US site in USD. "Currency" defaults to USD wherever the market offers it. Clear it to take the market's own. Each row reports the currency its price is really in.

**A nightly price is only comparable within one market.** In 18 of the 40 markets the nightly rate already includes tax, and the stay total is exactly the nightly rate times the nights. In the other 22 tax is added on top. `priceTotal` is what you'd pay either way. Compare on that.

**Hotels.com** is read on the United States market only.

#### For developers

- `startUrls` takes the same links as `hotels`, and the two are combined. The party is `adults` and `childrenAges`. The limits are `maxRatePlansPerStay`, `maxItems` (hotel-stays) and `maxRows`. The filters are `freeCancellationOnly`, `mealIncludedOnly` and `maxPricePerNight`.
- `stays` takes `CHECKIN_CHECKOUT` lines, and every hotel is priced for every stay. With no `checkIn`, the window is `checkInDaysAhead` (default 30) and `nights` (default 1), counted from the day the run starts.
- `priceCalendar` adds one row per bookable date on top of the rate grid. `calendarDaysMax` keeps only the first N dates per hotel.
- `priceStoreName` names the store that remembers each hotel-stay's cheapest price. With `onlyNewOrChanged` on, a hotel-stay whose cheapest price hasn't moved is skipped and billed as `hotel-checked` only.
- `includeUnavailable` writes a single row with `isSoldOut: true` for a stay with nothing for sale.
- `language: "site-default"` labels rooms and rates in the market's own language. Refundability, meals, room size, capacity, beds and the room's rating are published only in English wording. In this mode the grid is read once more in English and those values are copied across by rate. A rate missing from the English copy (2 of 40 on the markets measured) keeps them empty, with no guessing. Where the regional site leaves out a rate's cancellation deadline, the English wording of it is used.
- `maxConcurrency` (default 4, up to 8) is how many hotel-stays are fetched at once. `delayMs` (default 0) pauses after each request, per parallel lane, and values above 2000 are treated as 2000.
- If the platform moves or restarts a run part-way, it carries on where it stopped. Stays already in the dataset aren't fetched, delivered or billed again. Restarting an 80-stay run part-way gave the same 1,635 rows as an uninterrupted run.

### ⬆️ Output

One row per rate. A room appears once for each way it's sold. This is a refundable rate at the Hilton Chicago, from a run on 7 October 2026:

```json
{
  "id": "12570-2026-11-13-403873-266071239",
  "brand": "expedia",
  "market": "us",
  "hotelId": 12570,
  "hotelName": "Hilton Chicago",
  "url": "https://www.expedia.com/en/h12570.Hotel-Information?chkin=2026-11-13&chkout=2026-11-15",
  "checkIn": "2026-11-13",
  "checkOut": "2026-11-15",
  "nights": 2,
  "roomId": "403873",
  "ratePlanId": "266071239",
  "roomName": "Room, 1 King Bed",
  "roomRating": 8.4,
  "roomRatingScale": 10,
  "roomSizeSqm": 24,
  "roomSizeText": "260 sq ft",
  "maxOccupancy": 2,
  "bedConfiguration": "1 King Bed",
  "priceTotal": 817.16,
  "pricePerNight": 319,
  "priceText": "$319 nightly",
  "priceTotalText": "$817",
  "priceListedPerNight": null,
  "priceListedTotal": null,
  "currency": "USD",
  "isTaxIncludedInNightly": false,
  "pricesIncludeTax": false,
  "pricePerNightExcludingTax": 319,
  "paymentType": "PAY_NOW",
  "paymentText": "Pay the total now",
  "isRefundable": true,
  "cancellation": "Fully refundable before Tue, Nov 10",
  "board": "No extras",
  "isMealIncluded": false,
  "adults": 2,
  "childrenAges": [],
  "rooms": 1,
  "isSoldOut": false,
  "scrapedAt": "2026-10-07T20:27:07.856Z"
}
```

#### Reading the prices

`pricePerNight` and `priceTotal` aren't multiples of each other. The nightly figure is the one the site displays, and the total is what you'd pay with taxes and fees. Two nights at $319 comes to $817.16 here, not $638, because the US adds tax and fees on top. The same room's non-refundable rate was $271 a night and $703.44 for the stay in a run a minute earlier.

`priceTotal` always includes taxes and fees. `pricesIncludeTax` says whether `pricePerNight` does too. It's `true` in markets such as the UK, Germany, France and Australia and `false` in markets such as the US, Japan and Canada. Where it's `false`, the nightly rate is also in `pricePerNightExcludingTax`. `isTaxIncludedInNightly` is the older name for the same flag, kept for compatibility, and the two are always equal. On 2 October 2026 both were filled on every rate in the US, Japan, the UK, Germany and France, in English and in the site's own language.

`priceListedPerNight` and `priceListedTotal` are the crossed-out price a discounted rate is reduced from. At most one is filled, because a market's headline price is either nightly or for the stay and the listed figure follows it: the Japanese market fills the nightly one, the US market the total. Both are null on a rate with no discount.

#### Cancellation, sold-out stays and errors

Cancellation terms are stated when a rate is refundable and absent when it isn't. On a non-refundable rate `isRefundable` is `false` and `cancellation` is `null`, because the site says nothing there. It doesn't print "non-refundable".

A hotel and stay with nothing for sale writes no rows unless you turn on "Include sold-out stays", which gives you a single row with `isSoldOut: true`. A hotel the site never answered is written as a row with an `error`, and is never charged.

`childrenAges` echoes the ages you asked for and is an empty list when you asked for none.

#### Price-calendar rows

Calendar rows are marked `isCalendarDay: true`. Each has one date, its nightly price and whether it's available, with the same `hotelId`, `market` and link:

```json
{
  "id": "12570-cal-2026-10-07",
  "brand": "expedia",
  "market": "us",
  "hotelId": 12570,
  "date": "2026-10-07",
  "pricePerNight": 388,
  "priceText": "$388",
  "currency": "USD",
  "isAvailable": true,
  "pricesIncludeTax": null,
  "isCalendarDay": true,
  "url": "https://www.expedia.com/en/h12570.Hotel-Information?chkin=2026-10-07&chkout=2026-10-07",
  "scrapedAt": "2026-10-07T20:26:31.054Z"
}
```

`pricesIncludeTax` is null on calendar rows, because the calendar doesn't say.

### How fast is it?

One request covers one hotel and one date range and returns the full set of rooms and rates. Several hotel-stays are fetched at the same time. Measured on Apify on 2 October 2026, on Tokyo hotels:

| Run | Rows | Run time |
|---|---|---|
| 1 hotel, 1 stay, 8 cheapest rates | 8 | 3 s (10 s once, on a slow connection) |
| 6 hotels × 2 stays, every rate | 478 to 497 | 8 to 9 s |
| 10 hotels × 2 stays, every rate (18 priced, 2 sold out) | 501 | 9 s |
| 40 hotels × 2 stays, every rate | 1,635 | 25 s |

That's about 190 hotel-stays a minute on a larger run, and around 11,000 fit in the default one-hour run limit. There's no cap on rooms or rates. The limits you set are the only ones.

### How much does it cost to price a hotel?

| Event | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| `actor-start`, once per run | $0.002 | $0.002 | $0.002 | $0.002 |
| `hotel-checked`, per hotel and date range the site answered | $0.0005 | $0.0005 | $0.0005 | $0.0005 |
| `hotel-priced`, per hotel and date range that came back with rates | $0.003 | $0.0027 | $0.0024 | $0.0021 |
| `calendar-day`, per price-calendar date, only with **Include a price calendar** on | $0.0005 | $0.00045 | $0.0004 | $0.00035 |

Enterprise plans pay the Business price.

**$3.50 per 1,000 hotel-stays** on the Free plan, $2.60 on Business, with all rooms and rates in each. Proxy usage and platform usage are part of that price, and there's no proxy to set up.

- 100 hotel-stays, all priced: $0.002 + 100 × $0.0005 + 100 × $0.003 = **$0.352** ($0.262 on Business), for roughly 3,800 rows.
- 1,000 hotel-stays, 900 priced and 100 sold out: $0.002 + 1,000 × $0.0005 + 900 × $0.003 = **$3.202** ($2.392 on Business).
- Ten hotels for one stay, with the price calendar on (around 217 dates each): $0.002 + 10 × ($0.0005 + $0.003) + 2,170 × $0.0005 = **$1.122** ($0.7875 on Business).

Apify's Free plan includes $5 of credits a month. In runs of ten hotels that's about 1,350 priced hotel-stays a month for nothing.

A sold-out stay, and a stay skipped because its price hasn't changed, costs only the $0.0005 checking fee. It's a real answer that took real work, but it returned no rates. The same goes for a stay whose rates your filters all remove: it writes one row with an `error` saying how many rates were found, and pays the checking fee. A hotel the site never answered costs nothing at all.

### Limitations

- Nightly prices aren't comparable between markets. Compare on the stay total.
- Star ratings aren't returned. The site doesn't publish a star class on this record.
- Cancellation deadlines are text, not dates. They read as the site writes them ("Fully refundable before Tue, Nov 10"), which is what a guest is shown.
- Prices are what the site shows an anonymous visitor. Member-only and logged-in rates aren't included.
- Board is described in the site's own words, which vary by property ("No extras", "Breakfast included"). `isMealIncluded` turns that into a flag.
- Pay-at-property rates are unconfirmed. `paymentType` is often null, and no pay-at-property rate has been seen in testing.
- Hotels.com is available on the United States market only, where it answered 12 of 12 hotels in testing. Hotels.com Japan isn't supported: a run asking for it returns one error row saying so and costs nothing. Expedia Japan (expedia.co.jp) is fully supported, with the same property IDs.
- A Hotels.com stay the site doesn't answer returns an error row, uncharged, that says Hotels.com didn't answer on this run. Run it again later.

### FAQ

#### How do I compare the refundable and non-refundable price of the same room?

Group the rows by `roomId`. Each rate for that room is its own row with its own `ratePlanId`, `isRefundable`, `cancellation` and prices. If refundable rates are all you want, switch on "Refundable rates only".

#### Why is the cancellation column empty on some rates?

Those rates can't be cancelled. Expedia states the terms on a refundable rate and says nothing on the others, and the row mirrors that with `isRefundable: false` and a null `cancellation`.

#### Can I read Expedia and Hotels.com in one run?

Site sets which one bare property IDs are read from, and a pasted link overrides it. A list mixing Expedia and Hotels.com links is read correctly, each hotel from its own site, and `brand` on each row says which.

#### How do I get only what changed since yesterday?

Give "Price memory store" a name and turn on "Only changed prices". A hotel and stay whose cheapest price hasn't moved is skipped, and you pay the $0.0005 checking fee for it.

#### Which currency do the prices come back in?

The one the market quotes in: Japan JPY, the United States USD. A row is never labelled with money it isn't in. To compare one hotel across currencies, run it once per market. The property IDs are the same on each.

#### What does a sold-out hotel look like?

Nothing, by default: a sold-out stay writes no rows. That's an answer, not a failure. Turn on "Include sold-out stays" and you get one row per sold-out stay with `isSoldOut: true`, which lets a schedule see that the stay was checked.

#### Do I need proxies or an account?

No to both. There's no login, no cookie of yours is used, and proxy usage is included in the price.

#### Is it legal to scrape Expedia and Hotels.com?

The actor reads only pages Expedia and Hotels.com serve to a logged-out visitor, with no account access and no private data. Public data scraping is generally lawful in the UK, EU and US. How you use the rates, and whether that fits the site's own terms, is yours to check.

### Automating it

For a rate monitor, schedule the run in Apify with the dates left empty and days ahead set, and the window moves with the schedule. Add a price memory store and each run reports only the hotels whose price moved, which a webhook can pass to Slack or a Google Sheet.

From your own code, one request starts a run. Your API token is under Integrations in Apify Console.

```bash
curl -X POST "https://api.apify.com/v2/acts/boncross~expedia-room-rates/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"hotels":["12570"],"checkIn":"2026-11-13","checkOut":"2026-11-15"}'
```

Agents reach it through the Apify MCP server at `mcp.apify.com`, under the name `boncross/expedia-room-rates`, and get the rate grid back as structured rows.

### More from BonCross

- [Expedia Hotel Details Scraper](https://apify.com/boncross/expedia-hotel-details): The full property record from Expedia and Hotels.com.
- [Expedia Hotel Search Scraper](https://apify.com/boncross/expedia-hotel-search): Every hotel Expedia and Hotels.com list for a destination and your dates.
- [Expedia Reviews Scraper](https://apify.com/boncross/expedia-reviews): Expedia guest reviews for any hotel, including hotels given as Hotels.com links.
- [Google Hotels Prices Scraper](https://apify.com/boncross/google-hotels-prices): Google Hotels price comparisons for any hotel and stay.
- [Google Hotels Search Scraper](https://apify.com/boncross/google-hotels-search): Google Hotels prices for a whole city or map area.
- [Hilton Hotel Details Scraper](https://apify.com/boncross/hilton-hotel-details): Everything a Hilton property publishes about itself: address, coordinates, phone,…

### Your feedback

If a rate on the Expedia page isn't in your rows, or a refundable flag looks wrong, open an issue on the Issues tab in Apify Console and include the hotel and dates. We read each one and reply there.

# Changelog

This Actor's version history is a separate document: https://apify.com/boncross/expedia-room-rates/changelog.md

# Actor input Schema

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

Property IDs or hotel page links. A link looks like https://www.expedia.com/Santorini-Hotels-Ira-Hotel-Spa.h6116875.Hotel-Information: paste the whole link or just the number after the h.

## `startUrls` (type: `array`):

Hotel page links, pasted or bulk-loaded from a file or Google Sheet. Use this instead of the list above when you have many.

## `site` (type: `string`):

Which site to read. Links you paste already name their own site, so this only applies to bare property IDs. Hotels.com is read on the United States site only.

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

Stop after this many hotel-stays, across every hotel and date. A hotel-stay is one hotel for one date range, with all its rates. 0 means no limit.

## `maxRows` (type: `integer`):

Stop after this many rows. The last hotel-stay is cut to fit, keeping its cheapest rates. Price-calendar rows count too. 0 means no limit.

## `maxRatePlansPerStay` (type: `integer`):

Keep only the cheapest N rates for each hotel and stay. A large hotel can offer 60 or more. 0 means keep all of them.

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

Check-in date as YYYY-MM-DD, for example 2026-11-10.

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

Check-out date as YYYY-MM-DD, for example 2026-11-12.

## `checkInDaysAhead` (type: `integer`):

Used only when no check-in date is given. The stay starts this many days from the day the run starts, which keeps a scheduled run pointed at a moving window.

## `nights` (type: `integer`):

Length of the stay when the dates are computed from "days ahead" rather than given.

## `stays` (type: `array`):

More date ranges to price, one per line as CHECKIN_CHECKOUT, for example 2026-11-10_2026-11-12. Each one is fetched for every hotel.

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

Number of adults in the room.

## `childrenAges` (type: `array`):

One age per child, in years. Leave empty for an adults-only stay.

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

How many rooms to price, each with the same guests. The nightly rate stays per room and the stay total covers them all, which is how the site quotes a multi-room booking.

## `freeCancellationOnly` (type: `boolean`):

Keep only rates the site states can be cancelled.

## `mealIncludedOnly` (type: `boolean`):

Keep only rates that include breakfast or another meal.

## `maxPricePerNight` (type: `number`):

Drop rates above this nightly price, in the currency you chose. 0 means no limit.

## `includeUnavailable` (type: `boolean`):

Write a row for a hotel and stay with nothing for sale, so a schedule can see that it was checked.

## `priceCalendar` (type: `boolean`):

Add one row per date with the nightly price for every date the hotel is bookable (around 217 dates, roughly eight months ahead) on top of the rate grid for your own dates.

## `calendarDaysMax` (type: `integer`):

Keep only the first N calendar dates for each hotel. 0 means keep all of them.

## `market` (type: `string`):

Which country's site to read, which is what decides the currency: each one quotes its own money and will not quote another's. Auto follows each pasted link's own site, so an expedia.se link is quoted in SEK, and a bare property ID uses the US site, in USD. Some markets quote a nightly rate that already includes tax and others add it on top, so a nightly price is only comparable within one market: compare on the stay total.

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

Three-letter currency code, default USD. Only currencies the chosen region offers are accepted: 11 regions offer a choice, the rest quote one currency only. Anything else is ignored and the region's own currency is used, which the rows report. Clear it for the region's own currency.

## `language` (type: `string`):

Language of the room names, board and cancellation wording. Prices are unaffected; they always follow the market. With the market's own language the room size, occupancy and bed columns can come back empty, so English is recommended.

## `priceStoreName` (type: `string`):

Name of a storage area to remember the cheapest price for each hotel and stay. Leave empty to remember nothing.

## `onlyNewOrChanged` (type: `boolean`):

Skip a hotel and stay whose cheapest price is the same as last run. Needs a price memory store.

## `delayMs` (type: `integer`):

Pause after each request, per parallel lane. 0 runs at full speed; raise it only to make a large run gentler. Values above 2000 are treated as 2000.

## `maxConcurrency` (type: `integer`):

How many hotel-stays are fetched at once. Higher is faster; the default suits almost every run.

## Actor input object example

```json
{
  "hotels": [
    "12570",
    "https://www.hotels.com/ho3388/"
  ],
  "site": "expedia",
  "maxItems": 0,
  "maxRows": 0,
  "maxRatePlansPerStay": 0,
  "checkIn": "2026-11-10",
  "checkOut": "2026-11-12",
  "checkInDaysAhead": 30,
  "nights": 1,
  "stays": [
    "2026-11-10_2026-11-12",
    "2026-12-24_2026-12-27"
  ],
  "adults": 2,
  "childrenAges": [
    "7",
    "3"
  ],
  "rooms": 1,
  "freeCancellationOnly": false,
  "mealIncludedOnly": false,
  "maxPricePerNight": 0,
  "includeUnavailable": false,
  "priceCalendar": false,
  "calendarDaysMax": 0,
  "market": "auto",
  "currency": "USD",
  "language": "english",
  "onlyNewOrChanged": false,
  "delayMs": 0,
  "maxConcurrency": 4
}
```

# Actor output Schema

## `dataset` (type: `string`):

Expedia room rates: every row the run returned.

## `stats` (type: `string`):

Counts for the run: what was resolved, fetched, filtered and returned.

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "hotels": [
        "12570"
    ],
    "rooms": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("boncross/expedia-room-rates").call(input);

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

# Prepare the Actor input
run_input = {
    "hotels": ["12570"],
    "rooms": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("boncross/expedia-room-rates").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "hotels": [
    "12570"
  ],
  "rooms": 1
}' |
apify call boncross/expedia-room-rates --silent --output-dataset

```

## MCP server setup

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

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

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/fYcW9wKxjnZSlRCfe/builds/83OKrqKWTXMJ4fLh7/openapi.json
