# Expedia Hotels Scraper & Price Tracker (`myth84/expedia-hotels-scraper`) Actor

Expedia hotels scraper and Expedia price tracker: search results for any destination and dates — nightly and total stay price, guest rating, reviews, class, location, photos. Schedule it for hotel price tracking: price drops and rises flagged between runs. One flat row per hotel, no personal data.

- **URL**: https://apify.com/myth84/expedia-hotels-scraper.md
- **Developed by:** [Flatrow Data Studio](https://apify.com/myth84) (community)
- **Categories:** Travel, Automation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.29 / 1,000 hotels

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 Hotels Scraper & Price Tracker – hotel prices and ratings, no personal data

Expedia hotels scraper and Expedia price tracker for hotel price tracking and comparison: get Expedia hotel prices per night and for the whole stay, guest ratings and review counts for any destination and dates, as a clean table or through an API — no login. Use it as an Expedia hotel price monitor: schedule the same search to track hotel prices over time, and with price monitoring on get hotel price drop alerts (and rises) since your previous run, or compare hotels, dates and destinations side by side.

**No login, no cookies, no personal data:** nothing to sign in to, no cookies to paste, nothing about guests or reviewers in the output.

- **What you get:** one flat row per Expedia property for any destination and dates: total price of the stay with taxes and fees, price per night, strike-through price, guest rating on 10, review count, property type, star class where Expedia shows it, neighbourhood, coordinates, photos and link; a price-monitoring mode that returns only what changed since your previous run. No personal data.
- **For whom:** hoteliers and revenue managers (rate shopping), travel data and BI teams, deal finders and price-alert tools, AI agents through MCP.
- **How much:** from $2.00 per 1,000 properties on the Free plan, lower on paid plans; Apify's free monthly credit of $5 covers about 2,499 properties. A fixed price per property saved and nothing else (compute and proxy traffic included, see the Pricing tab); unchanged prices are never charged with `onlyChanges`; `maxResults` caps every run.

**Sample output**: one real row from a Lisbon search, key columns only (the full row is under *Output example*):

```json
{
  "platformListingId": "7369640",
  "title": "Meliá Lisboa Aeroporto",
  "city": "Lisbon",
  "region": "Olivais",
  "checkIn": "2026-11-20",
  "checkOut": "2026-11-23",
  "currency": "USD",
  "pricePerNight": 174,
  "priceTotal": 582,
  "priceTotalAllIn": 582,
  "rating": 9.4,
  "reviewCount": 3084
}
```

Scrape Expedia search results for any destination and dates and get **one flat row per property**: hotels, aparthotels, guest houses, hostels and rentals listed by Expedia, with the total price of the stay (taxes and fees included, as Expedia displays it) and the price per night, the strike-through price of deals, the guest rating on 10 and the number of reviews, the property type, the star class when the Expedia site shows it (expedia.fr), the neighbourhood, the coordinates, four photos and the link to the property page for those dates. Search **up to 50 destinations in one run** with `locations`. This Expedia scraper reads the same search API as the Expedia website, without logging in, 50 or 100 properties per request, removes duplicates and stops exactly at the number of properties you ask for. **Track and compare hotel prices**: schedule the same search (relative dates keep it valid) to follow every hotel's price over time, and compare hotels, dates and destinations on the same basis: same stay, same adults, same currency.

**No personal data, by design.** Nothing about guests or reviewers is collected: no names, no review texts, no profile photos, no ids of persons. The output only contains property-level facts (business names), the average rating and the number of reviews. The dataset is safe to store, share and feed to AI agents.

### What can you do with Expedia data?

- **Track hotel prices** for a destination and dates: rate shopping for hoteliers and revenue managers, deal finders, seasonal price studies, price alerts with a scheduled run.
- **Build accommodation datasets** for a city with coordinates ready for mapping, neighbourhoods, ratings and review counts for segmentation.
- **Compare platforms**: the same stay on Expedia, Booking.com and Airbnb with the same columns (this travel studio shares one output schema), so nightly and total prices line up in one spreadsheet.
- **Feed AI agents, spreadsheets and BI tools** with a stable, documented schema: every row has every column, prices are numbers, links open the property with your dates.

### What data does Expedia Scraper extract?

Every row has every column: a value Expedia does not show in search results is `null` (or `[]` for lists), so CSV and Excel exports keep the same columns from run to run.

| Group | Columns |
|---|---|
| Identity | `schemaVersion`, `platform`, `platformListingId`, `url`, `title`, `propertyType`, `roomType` |
| Location | `city`, `region`, `country`, `countryCode`, `latitude`, `longitude` |
| Stay | `checkIn`, `checkOut`, `nights`, `guests`, `isAvailable` |
| Prices | `currency`, `pricePerNight`, `priceTotal`, `priceBeforeDiscount`, `taxesAndFees`, `taxesIncluded`, `priceTotalAllIn`, `cleaningFee`, `serviceFee` |
| Quality | `rating`, `ratingMax`, `reviewCount`, `starRating`, `badges`, `isSuperhost`, `isNew`, `listedBy`, `cancellationPolicy`, `instantBook` |
| Size | `bedrooms`, `beds`, `bathrooms`, `maxGuests`, `amenities` |
| Photos | `imageUrls`, `imageCount` |
| Search context | `searchLocation`, `searchRank`, `searchPage`, `viewCountryCode`, `scrapedAt` |
| Price monitoring (`monitorPrices` runs only, otherwise `null`) | `changeType`, `previousPrice`, `priceDelta`, `priceDeltaPercent` |

Columns that Expedia never shows on search result cards stay empty for this Actor: `taxesAndFees`, `cleaningFee` and `serviceFee` (Expedia does not itemise them; `taxesIncluded` says card by card whether `priceTotal` includes them), `bedrooms`, `beds`, `bathrooms`, `maxGuests`, `instantBook`, `isNew`, `isSuperhost`, `listedBy` (always `null`) and `amenities` (always `[]`). `city` and `country` come from the destination you typed (search cards carry no address); `region` is the neighbourhood of the card; `latitude` / `longitude` come from the map markers Expedia returns with each page. `rating` is on a 10-point scale (`ratingMax` is `10`).

- **`priceTotal`** is the total of the stay as Expedia displays it, after discounts: **taxes and fees included** on every card of our captures. `taxesIncluded` is `true` when the card says so ("Total with taxes and fees", "taxes et frais compris": every card of our captures), and `priceTotalAllIn` then repeats `priceTotal`: it is the column to compare across sites, dates and platforms, filled with the same rule by every travel scraper of the studio. A card without that line leaves both `null` (Expedia does not itemise the taxes, so they are never estimated).
- **`pricePerNight`** is the nightly price of the card and its meaning follows the Expedia site: on **expedia.com (USD)** it is the nightly rate **before taxes and fees** ("$174 nightly" next to "$582 total" for 3 nights, so `pricePerNight × nights` is lower than `priceTotal`); on **expedia.fr (EUR)** it is the average night **with taxes and fees** ("173 € par nuit" for 518 € over 3 nights). When a card shows no nightly price, it is `priceTotal` divided by the nights.
- **`starRating`** is the property class shown on the card, 1 to 5: hotel stars, or Expedia's circles for other accommodation. Expedia shows it on **expedia.fr** (every card of our captures has it) but **not on expedia.com**, whose search cards carry no class at all, even for the same hotels: with `USD`, `starRating` is `null`. Use `EUR` (expedia.fr) when you need the class.
- **`propertyType`** is the type the property name states (`Hostel`, `Guest house`, `Apartment`, `Aparthotel`, `Bed and breakfast`, `Motel`, `Boat`…, the labels of our Booking.com scraper), otherwise `Hotel`; `null` only for a property Expedia rates on its non-hotel scale whose name says nothing. `roomType` is `hotel_room` for hotel-like types and `unknown` for hostels, apartments and boats (the card does not tell a room from a whole place).

### How to scrape Expedia hotels

1. **Enter a destination** as you would type it on Expedia ("Lisbon, Portugal", "Paris, France", "New York, New York, United States of America"). Add the country: the text before the first comma becomes the `city` column and the text after the last comma the `country` column. Put **a list of destinations** in `locations` to compare several cities in one run. Or **paste Expedia search URLs** into `startUrls` (see *Search from Expedia URLs* below): each URL carries its own destination, dates and travellers.
2. **Choose the stay**: fixed dates (`checkIn` / `checkOut`) for a precise quote, or relative dates (check-in in *N* days for *M* nights, the default) for schedules and recurring price checks that must never expire. Set the number of adults in the room: prices depend on it.
3. **Pick the currency**: `USD` reads expedia.com (English wording), `EUR` reads expedia.fr (French wording, type the destination in French: "Lisbonne, Portugal"). Set the maximum number of properties and, if needed, the sort order and the page size.
4. **Run** and open the **Output** tab: the *Overview*, *Prices* and *Location* views show the main columns; export everything as JSON, CSV, Excel or through the API. To track prices, tick `monitorPrices` and schedule the run (see *Price monitoring* below).

### Input

Field names and defaults are those of the input form. Give a list of `locations` (one or more destinations) or Expedia search URLs (`startUrls`); `location` (a single destination) is still accepted. `checkIn` and `checkOut` go together, otherwise `checkInDaysFromNow` and `nights` apply.

The search of our validation run, written with `locations`: 60 properties in Lisbon for a 3-night stay starting in 30 days, 2 adults, prices in USD on expedia.com, Expedia's recommended order (every other field keeps its default):

```json
{
  "locations": ["Lisbon, Portugal"],
  "checkInDaysFromNow": 30,
  "nights": 3,
  "adults": 2,
  "currency": "USD",
  "sortBy": "RECOMMENDED",
  "maxResults": 60
}
```

Every field, with its type and default:

| Field | Type | Default | Description |
|---|---|---|---|
| `locations` | string\[] | `[]` | One or more destinations as typed on Expedia, with the country, one per line, searched one after the other with the same dates, adults, currency and sort (up to 50, with `location`), together with the search URLs. When set, `maxResults` applies to each destination and each search URL. Prefilled with `["Lisbon, Portugal"]` in the form (clear it to search URLs only); with no `locations`, `location` or `startUrls` at all, the Actor searches Lisbon. |
| `location` | string | — | Single destination (kept for compatibility; prefer `locations`), as typed on Expedia with the country, searched before the destinations of `locations`. Ignored when `startUrls` is filled. |
| `startUrls` | string\[] | `[]` | Expedia hotel search URLs copied from your browser (`https://www.expedia.com/Hotel-Search?destination=…&startDate=…&endDate=…&adults=2`), one search per URL. The URL's destination, dates, adults, sort and site replace the form fields; the form fields fill in what the URL leaves out. |
| `checkIn` | string | — | Check-in date, YYYY-MM-DD. Leave both dates empty to use relative dates. |
| `checkOut` | string | — | Check-out date, YYYY-MM-DD, after check-in. Required when `checkIn` is set. |
| `checkInDaysFromNow` | integer | `30` | Without fixed dates: check-in this many days from today (UTC). |
| `nights` | integer | `3` | Without fixed dates: length of the stay (1 to 28). |
| `adults` | integer | `2` | Number of adults in one room (1 to 14). |
| `maxResults` | integer | `100` | Stop after this many unique properties (1,000 at most): for the whole run, or for each destination and each search URL when `locations` is set; with `monitorPrices`, the number of properties compared. You are never charged for more. Prefilled with `20` in the form (a quick first run). |
| `sortBy` | string | `"RECOMMENDED"` | `RECOMMENDED` (Expedia's default) or `PRICE_LOW_TO_HIGH`, both validated; `REVIEW`, `PRICE_HIGH_TO_LOW`, `PROPERTY_CLASS`, `DISTANCE` are the other orders of the Expedia sort menu, passed to the API but not yet verified. |
| `resultsPerPage` | string | `"50"` | Properties per API request: `"50"` (Expedia's page size) or `"100"` (fewer requests), both validated. |
| `currency` | string | `"USD"` | `USD` (expedia.com, English texts) or `EUR` (expedia.fr, French texts). The currency selects the Expedia site; other currencies need `pointOfSale`. |
| `pointOfSale` | object | — | Advanced: another Expedia site, e.g. `{"domain":"www.expedia.co.uk","siteId":3,"tpid":3,"locale":"en_GB","currency":"GBP"}`; `siteId` and `tpid` are in the source of any page of that site. Overrides `currency`. Not verified beyond expedia.com and expedia.fr. |
| `monitorPrices` | boolean | `false` | Price monitoring: compare every property with your previous run of the same search and fill `changeType`, `previousPrice`, `priceDelta` and `priceDeltaPercent` (see *Price monitoring*). `maxResults` is then the number of properties compared. |
| `monitorStoreName` | string | `"expedia-price-monitor"` | Key-value store of your account that keeps the previous prices, one record per search. Letters, digits and dashes. |
| `onlyChanges` | boolean | `false` | With `monitorPrices`: save and charge only the new properties and the price changes; a run without any change succeeds with an empty dataset. |
| `proxyConfiguration` | object | `{"useApifyProxy":true,"apifyProxyGroups":["RESIDENTIAL"],"apifyProxyCountry":"US"}` | The default proxy configuration (Apify proxies, `RESIDENTIAL` group, United States) is the only one validated for Expedia and its traffic is included in the price: keep it. Your own proxy URLs of the same kind are accepted. |
| `maxRequests` | integer | `100` | Safety cap on API requests per run, retries included. |
| `delayMs` | integer | `1000` | Pause between two page requests of the same search, in milliseconds. |
| `clientInfo` | string | `"shopping-pwa,7287debfc51fab933e63d3f59245f3c1316560e2,us-west-2"` | Value of the `client-info` header Expedia requires on its API. Replace it with the current value from your browser (Network tab, request to `/graphql`) if a run fails with *client-info header* in the error. |
| `debugStoreHtml` | boolean | `false` | Debugging only: store every API response (JSON, refused attempts included) in the key-value store. |

**Several destinations in one run.** List them in `locations` (with or without `location`): each destination is searched on its own with the same dates, adults, currency and sort, and `maxResults` applies to each of them. This input returns up to 50 properties for each of the three cities, 150 at most:

```json
{
  "locations": ["Paris, France", "Rome, Italy", "Barcelona, Spain"],
  "checkInDaysFromNow": 30,
  "nights": 3,
  "adults": 2,
  "currency": "USD",
  "maxResults": 50
}
```

The `searchLocation` column tells which destination found each property (and `city` / `country` follow it). A property found by two destinations for the same stay (a city and one of its districts) is saved and charged once, under the first destination of the list. Without `locations`, `maxResults` keeps capping the whole run.

### Search from Expedia URLs

Run a search on expedia.com or expedia.fr in your browser, copy the address of the results page and paste it into `startUrls`; add as many URLs as you like, one per line. Each URL becomes its own search in the run, so one run can cover several destinations or several stays, with every row carrying the stay it was priced for:

```json
{
  "startUrls": [
    "https://www.expedia.com/Hotel-Search?destination=Lisbon%2C%20Portugal&startDate=2026-11-20&endDate=2026-11-23&adults=2&rooms=1&sort=RECOMMENDED",
    "https://www.expedia.fr/Hotel-Search?destination=Paris%2C%20France&startDate=2026-12-01&endDate=2026-12-03&adults=3"
  ],
  "maxResults": 100
}
```

- **Read from the URL**: the destination (`destination`, with Expedia's `regionId` when the URL has one), the stay (`startDate` / `endDate`; the `d1` / `d2` and `chkin` / `chkout` spellings of older links too), the adults (`adults`, or the older `rm1=a2`), the sort order (`sort`) and the site: a URL on expedia.com is priced in USD with English texts, a URL on expedia.fr in EUR with French texts, whatever the `currency` field says. A URL on another Expedia site works only with the advanced `pointOfSale` input for that site.
- **Filled in from the form**: a URL without dates uses `checkIn` / `checkOut` or the relative dates, a URL without adults uses `adults`, a URL without a sort uses `sortBy`. `location` is ignored when `startUrls` is filled (the destinations of `locations` are searched too, before the URLs). `maxResults` caps the whole run, across all URLs, or each URL when `locations` is set.
- **Not supported**: children, several rooms, an unknown sort value, a property page or any page other than a hotel search. Such a URL makes the run fail at once with the URL number and the reason, so remove the parameter and run again. Filters of the Expedia page (stars, price range, guest rating, property type, amenities, neighbourhood, map area) are **ignored**: the search returns the unfiltered results of the destination, and the start of the run log lists the parameters that were left out.
- **Deduplication** stays per stay: the same hotel searched for two different stays (two URLs) gives two rows, one per stay; two URLs for the same stay give one row per hotel.

### Price monitoring

Use the Actor as an **Expedia price tracker**: tick `monitorPrices`, then **schedule the run** (daily is typical). The scraper keeps the last price of every property it compared in a key-value store of your account named `monitorStoreName` (`expedia-price-monitor` by default), with one record per search (same destination or search URL, stay, adults, sort, currency and Expedia site). The first run of a search is the reference: every property comes back with `changeType` = `"new"` (and `RUN_STATS.monitorBaseline` is true). From the second run on, every property is compared with the recorded one: `price_changed` rows carry `previousPrice`, `priceDelta` and `priceDeltaPercent`, the others are `unchanged`. With `onlyChanges` the dataset holds **only the new properties and the price changes** (hotel price drop alerts and rises), and **only those rows are charged**; a run where nothing changed succeeds with an empty dataset. In both cases `maxResults` is the number of properties compared by the run.

**The compared price is `priceTotal`**, the total of the stay with taxes and fees, whenever Expedia shows one; for a property whose card shows only a nightly price, `pricePerNight` is compared instead. A total is never compared with a nightly price: when a property switches from one to the other, it is reported `unchanged` and the new price becomes the reference.

A scheduled input that watches the 100 cheapest hotels of Paris for a 2-night stay two weeks ahead:

```json
{
  "location": "Paris, France",
  "checkInDaysFromNow": 14,
  "nights": 2,
  "adults": 2,
  "currency": "USD",
  "sortBy": "PRICE_LOW_TO_HIGH",
  "maxResults": 100,
  "monitorPrices": true,
  "onlyChanges": true
}
```

A `price_changed` row, as the Actor produces it from the row of the output example when the previous run had recorded a total of $640 (the other columns are the same as below):

```json
{
  "platformListingId": "7369640",
  "title": "Meliá Lisboa Aeroporto",
  "checkIn": "2026-11-20",
  "checkOut": "2026-11-23",
  "currency": "USD",
  "priceTotal": 582,
  "changeType": "price_changed",
  "previousPrice": 640,
  "priceDelta": -58,
  "priceDeltaPercent": -9.1
}
```

What to know before relying on it:

- **Fixed dates compare one stay; relative dates compare a lead time.** With `checkIn` / `checkOut` (or a search URL with its own dates), the record follows the price of that stay until it passes. With relative dates (the default), the record follows the price of the stay *N days ahead for M nights*: each run searches new dates, so a change mixes the hotel's pricing and the calendar (weekday, season). Both are useful; just know which one you track. Changing `checkInDaysFromNow` or `nights` starts a new reference.
- **The record is written only after a clean run.** A refused or failed search, a charge limit reached in the middle of a run or an interrupted run never overwrites the reference, so a bad day cannot erase your prices; the log says when a record was kept unchanged. A store that cannot be read stops the run before its first request.
- **Same currency only.** A price is compared only with a previous price of the same kind in the same currency; otherwise the property is reported `unchanged` and the new price becomes the reference.
- **Rankings move.** Expedia's recommended order varies between sessions, so the set of compared properties (the first `maxResults` of the run) drifts a little from run to run; a property that drops out of the results and comes back later is not reported as new (its last price is kept for 90 days). Sort by `PRICE_LOW_TO_HIGH` for a steadier set.
- **One record per search.** Runs sharing a `monitorStoreName` share the records; changing the destination, stay, adults, sort, currency or site of a search starts a new reference for it. Each destination of `locations` and each search URL has its own record; keep the same list, in the same order, from run to run, since a property found by two destinations is compared under the first one. Delete the key-value store in Apify Console to start over.

### Output example

One real row, produced by the Actor from a Lisbon search (USD, expedia.com, 20–23 November 2026, 2 adults). All columns are present, in this order, for every property:

```json
{
  "schemaVersion": "travel-listing/1.5",
  "platform": "expedia",
  "platformListingId": "7369640",
  "url": "https://www.expedia.com/Lisbon-District-Hotels-Melia-Lisboa-Aeroporto.h7369640.Hotel-Information?chkin=2026-11-20&chkout=2026-11-23&x_pwa=1&rfrr=HSR&pwa_ts=1792448088809&referrerUrl=aHR0cHM6Ly93d3cuZXhwZWRpYS5jb20vSG90ZWwtU2VhcmNo&useRewards=false&rm1=a2&regionId=2080&destination=Lisbon%2C+Lisbon+District%2C+Portugal&destType=MARKET&latLong=38.7123%2C-9.13833&sort=RECOMMENDED&top_dp=582&top_cur=USD&userIntent=&selectedRoomType=341392571&selectedRatePlan=CA%7C2253502223%7CQUJWY21WUW9MMEpMZ1FBV0FBQUFBZ0FBQUFDR1ViY1AtTm02bk1BRklyY1U5blk9%7CNRF%7CTV2&categorySearch=any_option",
  "title": "Meliá Lisboa Aeroporto",
  "propertyType": "Hotel",
  "roomType": "hotel_room",
  "city": "Lisbon",
  "region": "Olivais",
  "country": "Portugal",
  "countryCode": "PT",
  "latitude": 38.770382,
  "longitude": -9.125218,
  "checkIn": "2026-11-20",
  "checkOut": "2026-11-23",
  "nights": 3,
  "guests": 2,
  "currency": "USD",
  "pricePerNight": 174,
  "priceTotal": 582,
  "priceBeforeDiscount": null,
  "cleaningFee": null,
  "serviceFee": null,
  "taxesAndFees": null,
  "taxesIncluded": true,
  "priceTotalAllIn": 582,
  "rating": 9.4,
  "ratingMax": 10,
  "reviewCount": 3084,
  "starRating": null,
  "bedrooms": null,
  "beds": null,
  "bathrooms": null,
  "maxGuests": null,
  "amenities": [],
  "badges": [
    "Exceptional"
  ],
  "isSuperhost": null,
  "listedBy": null,
  "instantBook": null,
  "isNew": null,
  "isAvailable": true,
  "cancellationPolicy": null,
  "imageUrls": [
    "https://images.trvl-media.com/lodging/8000000/7370000/7369700/7369640/5f2dae4f.jpg?impolicy=resizecrop&ra=fit&rw=455&rh=455",
    "https://images.trvl-media.com/lodging/8000000/7370000/7369700/7369640/2ef3eae7.jpg?impolicy=resizecrop&ra=fit&rw=455&rh=455",
    "https://images.trvl-media.com/lodging/8000000/7370000/7369700/7369640/b05af088.jpg?impolicy=resizecrop&ra=fit&rw=455&rh=455",
    "https://images.trvl-media.com/lodging/8000000/7370000/7369700/7369640/9df1e2c9.jpg?impolicy=resizecrop&ra=fit&rw=455&rh=455"
  ],
  "imageCount": 4,
  "searchLocation": "Lisbon, Portugal",
  "searchRank": 1,
  "searchPage": 1,
  "viewCountryCode": "US",
  "scrapedAt": "2026-10-20T08:00:00.000Z",
  "changeType": null,
  "previousPrice": null,
  "priceDelta": null,
  "priceDeltaPercent": null
}
```

A discounted property has `priceBeforeDiscount` set to the strike-through total; a hostel, a guest house or a houseboat has `propertyType` `Hostel`, `Guest house` or `Boat` (from its name); on expedia.fr the wording (`region`, `badges`) is French, `starRating` is filled (4 for this hotel) and `pricePerNight` includes taxes and fees (173 € for 518 € over 3 nights).

The **Output** tab offers four views of the same rows: **Overview** (name, class, neighbourhood, dates, prices, rating, reviews, link, photos), **Prices** (nights, nightly price, total, strike-through price, currency, cancellation, badges), **Location** (city, neighbourhood, country, coordinates, rank) and **Changes** (for price-monitoring runs: change, total, previous total, difference in amount and percent).

### How much does it cost to scrape Expedia?

This Actor uses **pay-per-event pricing: you pay a fixed price per property** saved to your dataset, and nothing else. On the Free plan, properties cost $2.00 per 1,000, so Apify's free monthly credit of $5 covers about 2,499 properties; paid plans pay less per property, and the price of every plan tier is on the **Pricing tab** of this page.

| What you pay for | How it is counted | Price |
|---|---|---|
| `result` event: one property saved to your dataset | once per unique property of the run, capped by `maxResults` (per destination with `locations`); with `onlyChanges`, only the new properties and the price changes | Pricing tab, per plan tier |
| Run start | a symbolic amount, once per run | Pricing tab |
| Compute, proxies, storage and data transfer | included: no platform usage is passed on to you | — |

The cost of a run is known before you start: 1,000 properties cost 1,000 times the `result` price of your tier, whatever the number of pages fetched. One request returns 50 or 100 properties in one to two seconds; about one request in ten is refused by Expedia and retried, so a run of a few hundred properties takes under a minute.

### Limits and behaviour worth knowing

- **One destination and one stay per search.** Every row of a search shares the same `checkIn`, `checkOut`, `guests` and `currency`, which is what makes prices comparable. A run holds one search per destination of the form (`location`, `locations`) and one per URL of `startUrls` (several destinations or stays in one dataset: compare rows by `searchLocation`, `checkIn` and `checkOut`); schedules can also use one task per destination.
- **About 500 properties per destination.** Expedia announces the total in the search results (logged at the start of the run); the scraper stops there, at `maxResults`, or after two pages without a new property. Beyond that, split the city into districts or landmarks.
- **Totals include taxes and fees, nightly prices depend on the site.** `priceTotal` is the total Expedia displays for the stay ("Total with taxes and fees"); `pricePerNight` is the nightly price of the card, before taxes and fees on expedia.com and with them on expedia.fr (or the total divided by the nights when the card shows none); `priceBeforeDiscount` is the strike-through total of a deal. `taxesAndFees` is `null` because Expedia does not itemise them in search results.
- **Star class on expedia.fr only.** expedia.com search cards carry no property class, so `starRating` is `null` with `USD`; with `EUR` (expedia.fr) it is filled for every property that has one.
- **Currency and language follow the Expedia site.** `USD` reads expedia.com in English, `EUR` reads expedia.fr in French (type the destination in French there). Expedia ignores a currency that does not match the site; other sites need the advanced `pointOfSale` object with their `siteId` / `tpid`, which we have not verified.
- **Rankings move and sponsored cards appear.** Expedia's recommended order varies between sessions; sponsored placements and banners are skipped (counted in the run statistics) and properties seen again are removed by id. The `PRICE_LOW_TO_HIGH` order is exact.
- **Search cards show a subset of the property.** Address, amenities, room details, free-cancellation terms beyond the card wording and the full photo gallery are not in search results and are therefore `null`, empty or limited to four photos. Property pages are not covered by this Actor.
- **Blocking and retries.** Expedia refuses about one request in ten; the scraper retries each page up to five times on a new proxy session with a growing pause (1 to 8 seconds), then abandons the page and reports it. A whole run that is refused ends as failed with the reason: keep the default proxy configuration, raise `delayMs` or try again later, and open an issue with your run id if it persists.
- **API changes.** If Expedia changes its API, the run fails at once with an explicit message (schema change, or `client-info` header refused: update the `clientInfo` input from your browser while the Actor is being updated).
- **No empty successes.** A run that finds no property ends as failed with an explicit message (destination not recognised, dates in the past, every request refused), so that your schedules and integrations notice. The one exception is a price-monitoring run with `onlyChanges` that compared properties and found no change: it succeeds with an empty dataset.

### Integrations and API

Start the Actor from Apify Console, schedule it, or call it from the [Apify API](https://docs.apify.com/api/v2) with any language (the **API** tab shows ready-made code for Node.js, Python and curl). Webhooks notify your systems when a run finishes; the dataset can be pulled as JSON, CSV, Excel, XML or RSS, or pushed to Google Sheets, Make, Zapier, n8n, Slack, Airtable, Google Drive and more through the Apify integrations.

For bugs or questions, open an issue in the **Issues** tab of this Actor with your run id and input. Bugs and API changes are fixed as a priority; feature requests (filters, property details, other Expedia sites, other platforms of the travel studio) are welcome.

### Use it from your AI assistant

Add this Actor as a tool to Claude, ChatGPT, Cursor, VS Code or any MCP client with the Apify MCP server URL below (sign in with your Apify account when asked):

`https://mcp.apify.com?tools=myth84/expedia-hotels-scraper`

Then ask in plain words. Copy this prompt and change the details:

```text
Use myth84/expedia-hotels-scraper to compare 20 hotels in Rome, Italy on Expedia for 2 adults, 3 nights starting 30 days from today, prices in USD, cheapest first. Input: {"location": "Rome, Italy", "checkInDaysFromNow": 30, "nights": 3, "adults": 2, "currency": "USD", "sortBy": "PRICE_LOW_TO_HIGH", "maxResults": 20}. Show the name, price per night, total price, guest rating, number of reviews and link of each hotel.
```

### For AI agents (MCP)

Through the [Apify MCP server](https://docs.apify.com/mcp) this Actor is a tool that answers questions such as *"what do hotels in Lisbon cost for two adults from 20 to 23 November?"*, *"list the best-rated hotels in Paris under 200 dollars a night"* or *"compare hotel prices in Rome and Florence next month"*.

**Minimal input** (one or more destinations in `locations`, `maxResults` per destination; every other field keeps its default, raise `maxResults` only when the question needs more rows):

```json
{
  "locations": ["Rome, Italy", "Florence, Italy"],
  "checkInDaysFromNow": 30,
  "nights": 3,
  "adults": 2,
  "currency": "USD",
  "maxResults": 20
}
```

- **Key output fields**: `platformListingId`, `title`, `url`, `priceTotal` (taxes and fees included), `pricePerNight` (before taxes and fees on expedia.com, included on expedia.fr), `priceBeforeDiscount`, `currency`, `rating` (on 10), `reviewCount`, `starRating` (expedia.fr only: use `EUR` for hotel stars), `propertyType`, `region`, `latitude` / `longitude`, `badges`. Every column is always present, in a fixed order; `null` means Expedia did not show the value. The full list is in *What data does Expedia Scraper extract?* above.
- **Use it when** you need current Expedia search results for a destination and a stay: nightly and total prices, guest ratings, review counts, neighbourhoods, coordinates, photos, links. Pass `locations` (one or more destinations with their country, searched one by one, `maxResults` each) or `location`, the dates (`checkIn` / `checkOut`, or `checkInDaysFromNow` + `nights`), `adults`, `currency` (`USD` or `EUR`), optionally `sortBy`, and a small `maxResults` (10–50 is enough for an answer). When the user gives Expedia search URLs, pass them in `startUrls` instead: each URL carries its destination, dates and adults.
- **Track prices** by scheduling the same input with `monitorPrices: true` (and `onlyChanges: true` for changes only): rows carry `changeType`, `previousPrice`, `priceDelta`, `priceDeltaPercent`.
- **Do not use it for** guest reviews, property descriptions and amenities, room availability, booking or anything behind a login: it does not collect personal data and only reads public search results.
- **Cost per 1,000 results**: 1,000 `result` events, $2.00 per 1,000 on the Free plan and less on paid plans (Pricing tab); nothing else is charged.
- **Typical time**: one to two seconds per request of 50 or 100 properties, plus retries: 20 properties in a few seconds, a few hundred in under a minute.

### Alternatives and switching

- **Official API.** Expedia's APIs are made for its travel partners and need an approved partner account; if you have one and need bookings, use it. This Actor reads what any visitor sees in Expedia search results (public prices per night and per stay, guest ratings, review counts) with no account, no keys and no approval.
- **Your own scraper.** Nothing to build or maintain: sessions, retries, pagination, deduplication and Expedia page changes are handled for you. The columns stay the same from run to run, a run that finds nothing fails with an explicit message instead of succeeding empty, and a scheduled test run catches Expedia changes early.
- **Another scraper from the Store.** What you can count on here: `maxResults` is a hard cap (per destination with `locations`), the run stops at that number of properties and you are never charged for more; with `monitorPrices` and `onlyChanges`, a scheduled run returns and charges only the new properties and the price changes; `priceTotalAllIn` gives one total, taxes included, to compare with the other platforms. The input names differ from one Actor to the next; the usual ones map to this Actor as follows:

| Usual input | Here | Note |
|---|---|---|
| `search`, `query`, `destination` | `location`, or `locations` for up to 50 places | Destination with its country, as typed on Expedia |
| `startUrls` | `startUrls` | Expedia search results URLs |
| `maxItems`, `limit` | `maxResults` | Unique properties per run, never charged beyond |
| `checkin`, `checkout` | `checkIn`, `checkOut` | YYYY-MM-DD; or `checkInDaysFromNow` + `nights` for schedules |
| `adults` | `adults` | Adults in the room: prices depend on it |
| `sort` | `sortBy` | `RECOMMENDED`, `PRICE_LOW_TO_HIGH`, `REVIEW`… |
| `currency` | `currency` | `USD` (expedia.com) or `EUR` (expedia.fr) |
| `proxy` | `proxyConfiguration` | Keep the default: proxies are included in the price |
| `monitor`, `trackPrices`, `alerts` | `monitorPrices`, `onlyChanges` | Compares with your previous run of the same search; only changes when asked |

### FAQ

#### Does Expedia Scraper collect personal data?

No. The scraper reads search result cards only and keeps nothing about guests or reviewers: no names, photos, profile ids, contact details or review texts. It outputs property facts (business names and neighbourhoods), the average guest rating and the number of reviews. Every row goes through a privacy filter before it is saved.

#### Is it legal to scrape Expedia?

The Actor only reads search results that Expedia serves to any visitor without an account, and it stores no personal data. Scraping public data is generally lawful, but you are responsible for how you use the results and for complying with Expedia's terms of service and the laws that apply to you (including copyright on property texts and photos). Use the data for analysis, not to republish listings.

#### Do the prices include taxes and fees, and why do they differ from my browser?

`priceTotal` is the total Expedia displays for the stay: taxes and fees included ("Total with taxes and fees") on every card of our captures, and `taxesIncluded` says it card by card. `pricePerNight` follows the site: on expedia.com it is the nightly rate before taxes and fees (so `pricePerNight × nights` is below `priceTotal`: $174 a night, $582 in total for 3 nights), on expedia.fr the average night with taxes and fees. Compare stays with `priceTotalAllIn` (equal to `priceTotal` here), the column every travel scraper of the studio fills the same way. Prices also depend on the stay (dates, adults), the Expedia site (currency) and the moment: Expedia runs time-limited deals and member prices (never used here: no login). Compare rows obtained with the same input.

#### Do I need proxies, and do I pay for them?

No extra setup: the default `proxyConfiguration` (United States) is the only one validated for Expedia, and its traffic is included in the price per property: you pay per property, nothing more. Keep it; other configurations are not expected to work.

#### What do I do if a run fails with "client-info header"?

Expedia ties its API to the build of its website through a `client-info` header. Open any Expedia search in your browser, find a request to `/graphql` in the Network tab, copy its `client-info` request header into the `clientInfo` input, and run again. The Actor is updated with the new value as a priority.

#### Can I search several cities in one run?

Yes. Put up to 50 destinations in `locations`, one per line ("Paris, France", "Rome, Italy", "Barcelona, Spain"…), alongside or instead of `location`. Each destination is a separate search with the same dates, adults, currency and sort, and `maxResults` applies to each destination: 3 cities with `maxResults` 50 give up to 150 properties. Every row says in `searchLocation` which destination found it, and a property found by two destinations for the same stay is saved and charged once. Large lists need more requests: raise `maxRequests` if the log says that some destinations were not searched.

#### Which currencies and languages are supported?

`USD` on expedia.com (English) and `EUR` on expedia.fr (French) are validated. Other Expedia sites (GBP, CAD, AUD…) can be reached with the advanced `pointOfSale` input once you have their `siteId` and `tpid` from the site's page source; they are not verified. A pasted search URL follows its own site: expedia.com in USD, expedia.fr in EUR.

#### What are relative dates?

Leave `checkIn` and `checkOut` empty and the Actor searches a stay starting `checkInDaysFromNow` days from today for `nights` nights, so that a scheduled run or an example task never expires. Give fixed dates when you need a quote for precise dates.

#### How often should I run it, and how do I get only price changes?

Every run fetches live search results. Prices and availability change daily, so schedule the Actor as often as your use case needs (daily is typical for price tracking) and compare runs by `platformListingId`, `checkIn` and `checkOut`, or let the Actor compare them for you: tick `monitorPrices` (and `onlyChanges`) and schedule the run. The first run records every property of the search and returns it as `new`; each later run flags the properties that appeared since and the properties whose price changed, with `previousPrice`, `priceDelta` and `priceDeltaPercent`, and with `onlyChanges` returns and charges only those rows. A run without any change succeeds with an empty dataset. The previous prices live in the key-value store `monitorStoreName` of your account; keep the same destination, stay, adults, sort and currency from run to run. With relative dates you follow the price of a stay at a constant lead time; with fixed dates, the price of one stay.

#### Why is `starRating` empty, and how do I get hotel stars?

Expedia shows the property class (stars, or circles for other accommodation) on expedia.fr search results but not on expedia.com: the API sends no class for expedia.com cards, even for the hotels it rates on expedia.fr. With `currency` `USD`, `starRating` is therefore `null`; set `currency` to `EUR` (expedia.fr, prices in euros) to get it for every property that has one. `propertyType` is filled in both cases (`Hotel`, `Hostel`, `Guest house`, `Apartment`…). Exports and integrations are described under *Integrations and API*.

### More scrapers by Flatrow Data Studio

The travel scrapers of the studio share the same core columns, so stays from several platforms land in one table; compare their prices on `priceTotalAllIn`, the total of the stay with taxes and fees, filled with the same rule by each scraper (`null` when a platform does not show the taxes):

- [Airbnb Listings Scraper & Price Tracker](https://apify.com/myth84/airbnb-listings-scraper): Airbnb prices, ratings, review counts and locations for any place and dates, up to 50 destinations per run, with price monitoring.
- [Airbnb Listing Details & Availability Calendar](https://apify.com/myth84/airbnb-listing-details-scraper): amenities, house rules, six category ratings and a 1–12 month availability calendar for the Airbnb listing URLs you give.
- [Booking.com Hotels Scraper & Price Tracker](https://apify.com/myth84/booking-hotels-scraper): Booking.com hotel prices for your dates with the excluded taxes, review scores and stars, search URLs and price monitoring.

Did this scraper give you the data you needed? A rating on its Store page helps other people find it. For a bug or a missing field, open an issue in the **Issues** tab.

### Legal note

This Actor reads publicly available Expedia search results without logging in and collects no personal data. You are responsible for your use of the data and for complying with Expedia's terms and the laws that apply to you.

Not affiliated with, endorsed or sponsored by Expedia Group. Expedia is a trademark of Expedia, Inc.

# Changelog

This Actor's version history is a separate document: https://apify.com/myth84/expedia-hotels-scraper/changelog.md

# Actor input Schema

## `locations` (type: `array`):

One or more destinations, one per line, as typed in the Expedia search box with their country, e.g. <code>Lisbon, Portugal</code>, <code>Rome, Italy</code>. Each is its own search with the same dates, adults, currency and sort, and <b>maxResults applies to each destination</b> (and to each search URL). Always searched, also with startUrls: clear the list to search URLs only. Up to 50. Default empty; with no destination at all, the Actor searches Lisbon, Portugal.

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

Expedia hotel search URLs from your browser (<code>https://www.expedia.com/Hotel-Search?destination=…</code>), one search each: their destination, dates, adults, sort and site win over the form (expedia.com in USD, expedia.fr in EUR; another Expedia site only with the advanced pointOfSale input). Filters of the Expedia page (stars, price, rating, amenities) are ignored: the run log lists the parameters left out. location is then ignored. Default empty: search by destination.

## `location` (type: `string`):

Single destination (kept for compatibility; prefer <code>locations</code>), as typed in the Expedia search box with its country, e.g. <code>Paris, France</code>: the text before the first comma fills <code>city</code>, the text after the last comma <code>country</code>. Searched before the destinations of <code>locations</code> (up to 50 together); ignored when startUrls is filled. Leave empty when you use locations.

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

Check-in date, YYYY-MM-DD, e.g. <code>2026-12-01</code>, given with checkOut. Leave both empty for a stay relative to today (checkInDaysFromNow and nights), better for schedules: fixed dates expire.

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

Check-out date, YYYY-MM-DD, after checkIn, e.g. <code>2026-12-04</code>. Required when checkIn is set.

## `checkInDaysFromNow` (type: `integer`):

Without fixed dates: check-in this many days after today (UTC), e.g. <code>7</code> for next week. Default 30: a month ahead, a typical booking window, and the stay moves with each scheduled run so it never expires.

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

Without fixed dates: length of the stay in nights, 1 to 28. Default 3: a typical city break.

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

Number of adults in one room, 1 to 14; prices depend on it. Default 2: the most searched occupancy.

## `maxResults` (type: `integer`):

Maximum number of properties saved and charged, 1 to 1,000 (Expedia lists about 500 per destination; one request returns 50 or 100). With <code>locations</code> it applies to each destination; with price monitoring it is the number compared. Default 100: enough to compare a city, about $0.20 on the Free plan. The form prefills 20 for a quick first run (our daily check).

## `sortBy` (type: `string`):

Order of the results: <code>RECOMMENDED</code> (Expedia's default) and <code>PRICE_LOW_TO_HIGH</code> are validated; guest rating, highest price, property class and distance are passed as they are. Default RECOMMENDED: the order visitors see first.

## `resultsPerPage` (type: `string`):

Properties fetched by one request: <code>50</code> (Expedia's page size) or <code>100</code> (fewer requests), both validated. Default 50: the page size of the site.

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

Currency of every price, which picks the Expedia site: <code>USD</code> reads expedia.com (English), <code>EUR</code> reads expedia.fr (French texts: type the destinations in French). Other currencies need pointOfSale. Default USD: expedia.com, the most visited site.

## `pointOfSale` (type: `object`):

Advanced: another Expedia site, overriding currency, as JSON with domain, siteId, tpid, locale and currency, e.g. <code>{"domain":"www.expedia.co.uk","siteId":3,"tpid":3,"locale":"en_GB","currency":"GBP"}</code>; siteId and tpid are in the source of any page of that site. Not verified beyond expedia.com and expedia.fr. Leave empty to follow currency.

## `monitorPrices` (type: `boolean`):

Compare the total price of each property (the price per night when Expedia shows no total) with the one recorded by your previous run of the same search, and fill changeType, previousPrice and priceDelta. maxResults is then the number of properties compared. Default off: a plain search.

## `monitorStoreName` (type: `string`):

Key-value store of your account that keeps the previous prices, one record per search (each destination and each search URL has its own), e.g. <code>expedia-paris-daily</code>. Letters, digits and dashes, up to 63 characters. Default expedia-price-monitor: one store for all your monitoring runs.

## `onlyChanges` (type: `boolean`):

With monitorPrices: save and charge only the new properties and the price changes (price drop alerts); a run without any change succeeds with an empty dataset. Default off: every compared property is saved with its changeType.

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

Proxies of the requests. Default: Apify proxies of the RESIDENTIAL group in the United States, the configuration validated for Expedia, included in the price: keep it. Your own proxy URLs of the same kind are accepted.

## `maxRequests` (type: `integer`):

Safety cap on API requests for the whole run, retries included (about one request in ten is retried). Default 100: the default search needs 2 requests, which leaves room for retries or about 40 destinations of 100 properties.

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

Pause between two page requests of the same search, in milliseconds (retries have their own growing pause); 0 disables it. Default 1000: one second, the pacing of our tests.

## `clientInfo` (type: `string`):

Advanced, keep the default: the <code>client-info</code> header Expedia's API requires. If a run fails with <i>client-info header</i>, copy the current value from any Expedia search in your browser (Network tab, request to /graphql). Default <code>shopping-pwa,7287debfc51fab933e63d3f59245f3c1316560e2,us-west-2</code>: the value observed at build time.

## `debugStoreHtml` (type: `boolean`):

Debugging only: save every API response (JSON, refused attempts included) in the run's key-value store. Default off: it uses storage.

## Actor input object example

```json
{
  "locations": [
    "Lisbon, Portugal"
  ],
  "startUrls": [],
  "checkInDaysFromNow": 30,
  "nights": 3,
  "adults": 2,
  "maxResults": 20,
  "sortBy": "RECOMMENDED",
  "resultsPerPage": "50",
  "currency": "USD",
  "monitorPrices": false,
  "monitorStoreName": "expedia-price-monitor",
  "onlyChanges": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  },
  "maxRequests": 100,
  "delayMs": 1000,
  "clientInfo": "shopping-pwa,7287debfc51fab933e63d3f59245f3c1316560e2,us-west-2",
  "debugStoreHtml": false
}
```

# Actor output Schema

## `listings` (type: `string`):

All extracted properties as dataset items, one flat row per property. Append ?format=csv or ?format=xlsx for spreadsheets. The Overview view is selected by default.

## `runStats` (type: `string`):

Requests and retries made, refused attempts, bytes transferred, pages, duplicates, properties seen and pushed, and the estimated platform cost of the run (residential traffic included).

# 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 = {
    "locations": [
        "Lisbon, Portugal"
    ],
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("myth84/expedia-hotels-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 = {
    "locations": ["Lisbon, Portugal"],
    "maxResults": 20,
}

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

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

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

```

## CLI example

```bash
echo '{
  "locations": [
    "Lisbon, Portugal"
  ],
  "maxResults": 20
}' |
apify call myth84/expedia-hotels-scraper --silent --output-dataset

```

## MCP server setup

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

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

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/lrCa0HGdAwtqPI0Ce/builds/koqOHt2zwLhpdsNYV/openapi.json
