# Expedia & Hotels.com Scraper - Hotels, Prices & Reviews (`topapi/expedia-hotels-scraper`) Actor

Scrape Expedia and Hotels.com: hotel search results with nightly price, stay total, guest score, star class, amenities, address and coordinates, plus guest reviews with score, text, trip type and hotel reply. 30 Expedia sites, Expedia filters, monitor. $2.30 per 1,000 hotels, $2 per 1,000 reviews.

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

## Pricing

from $2.30 / 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.

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

### What does Expedia & Hotels.com Scraper do?

**Expedia & Hotels.com Scraper** extracts hotels and guest reviews from [Expedia](https://www.expedia.com) and [Hotels.com](https://www.hotels.com). Type a destination and get one row per hotel with the nightly price, stay total, guest score, star class, amenities, address and map position for your dates; give it hotels and get one row per guest review with the score, text, trip type and the hotel's reply. Built for revenue managers, travel analysts, OTA and meta-search teams, and AI builders who need Expedia data in bulk.

Expedia scraper - Hotels.com scraper - Expedia hotels API - Expedia reviews scraper

<a href="https://console.apify.com/actors/d4GG89u0dl98UFLJJ"><img src="https://api.apify.com/v2/key-value-stores/qNQ9zP0xaj2yxGeMY/records/expedia-hotels-scraper-source.png" alt="Expedia hotel search results that Expedia & Hotels.com Scraper turns into rows" style="width:70%"></a>

- **Hotel search rows:** name, link, position, star class, guest score and label, review count, nightly price, stay total, was-price, deal badge, member price, VIP Access, free cancellation, pay later, rooms left, neighborhood, amenities, photos, full address and coordinates.
- **Guest reviews:** score out of 10 and its label, text, title, review date, stay month and nights, traveled-with, liked / disliked topics, guest photos, hotel response with its date, review language (as Expedia marks it), plus the hotel's score, review count and category scores on every row.
- **Every review Expedia serves:** all 5,759 reviews of one London hotel in a test, 50 per request; 150 reviews of one hotel took 4-5 seconds (two test runs).
- **Expedia's own filters:** dates, rooms, adults, children, sort order, price range, stars, guest rating, property type, amenities, meal plan, refundable, pay later, member / VIP deals, neighborhood, property name; for reviews: sort, traveler type and keyword.
- **30 Expedia sites:** expedia.com, Hotels.com, expedia.co.uk, .de, .fr, .ca, .com.au, .co.jp and more, each priced in its own currency.
- **Hotel details (add-on):** amenities by category, policies, important info, category scores, rating histogram, AI review summary, highlights, nearby places, the photo gallery, and every room with its rates for your stay.
- **Rate-position report (add-on):** where your hotel ranks and prices against its market.
- **Monitor mode:** only hotels and reviews you have not received yet, plus hotels whose stay price changed. A rate-position report, if on, is a fresh market snapshot on every run (charged each time).
- **No login, cookies or Expedia API key.** Export to JSON, CSV, Excel, XML; schedules, webhooks, Make, Zapier, n8n, Google Sheets, the Apify API and MCP.

### What data can you get from Expedia?

<table>
<tr>
<td>🏨 Hotel name, id (<code>hotelId</code>) and link</td>
<td>⭐ Star class (<code>starRating</code>)</td>
<td>💯 Guest score + label (<code>guestRating</code>)</td>
</tr>
<tr>
<td>🗣️ Review count</td>
<td>💲 Price per night (<code>pricePerNight</code>)</td>
<td>🧾 Stay total, was-price, taxes included</td>
</tr>
<tr>
<td>🏷️ Deal badge, member price, VIP Access</td>
<td>✅ Free cancellation, pay later, rooms left</td>
<td>📍 Address, postal code, latitude / longitude</td>
</tr>
<tr>
<td>🏙️ Neighborhood and search position</td>
<td>🛎️ Amenities</td>
<td>🖼️ Photos</td>
</tr>
<tr>
<td>💬 Review text, title and score 1-10</td>
<td>📅 Review date, stay month, nights</td>
<td>🧳 Traveled with (partner, family, solo, group, business)</td>
</tr>
<tr>
<td>👍 Liked / 👎 disliked topics</td>
<td>🏢 Hotel response and its date</td>
<td>🌐 Review language (Expedia's mark)</td>
</tr>
<tr>
<td>📊 Category scores + rating histogram</td>
<td>🤖 Expedia's AI review summary</td>
<td>🛏️ Rooms and rates for your dates</td>
</tr>
</table>

On a 100-hotel Lisbon run every row had the name, link, star class, guest score, review count, nightly price, stay total, neighborhood, amenities, photos, address and coordinates; 62% had a was-price, 51% a deal badge and 23% free cancellation. On a 500-hotel London run 99.2% had a price. On 1,000 reviews every row had the score, date, stay month and nights; 71% had review text, 58% a traveled-with and 86% a hotel response.

### How to scrape Expedia with Expedia & Hotels.com Scraper

1. [Create a free Apify account](https://console.apify.com/sign-up) - $5 of monthly credit, no card needed.
2. Open [Expedia & Hotels.com Scraper](https://apify.com/topapi/expedia-hotels-scraper) and click **Try for free**.
3. Type destinations into **Destinations** (for hotel rows) or paste hotel links, ids or names (for their reviews).
4. Set your dates, guests and filters, and **Max hotels per destination** / **Max reviews per hotel**.
5. Click **Start**. Rows stream into the dataset as each page is read.
6. Open the **Storage** tab and **Export** as JSON, CSV or Excel - or let a schedule run it for you.

### ⬇️ Input

| Parameter | Type | Description |
|---|---|---|
| **🔍 What to scrape** | | |
| `mode` | Select | `auto` (default): destinations give hotel rows, hotels give their reviews. `hotels`, `reviews`, `hotelsAndReviews` force one or both. |
| `locations` | List | Destinations as you would type them on Expedia: `"Lisbon"`, `"Times Square, New York"`, an airport (`"Heathrow Airport"` or its code `"JFK"`). For a name several places share, add the state or country (`"Dublin, Ireland"`, `"Dublin, Ohio"`); without it the place with its own major airport is used (Dublin -> Dublin, Ireland), and RUN_SUMMARY `notes` list the others with their region ids. |
| `startUrls` | List | Expedia / Hotels.com hotel links (any regional site, also Travelocity, Orbitz, Wotif, CheapTickets, ebookers), Hotel-Search links, `expe.app.link` share links or bare Expedia ids such as `179` (Hotels.com links need the hotel name in them). |
| `hotelNames` | List | Hotel names with their city: `"Four Seasons Hotel Ritz Lisbon"`. |
| `regionIds` | List | Expedia region ids (`regionId=` of a search link). |
| `googleMapsInputs` | List | Google Maps links of hotels; matched by name and position. |
| `site` | Select | Which Expedia site prices the stay. Default `expedia.com` (USD). |
| **🎯 Search filters** (applied by Expedia) | | |
| `checkIn` / `checkOut` | Text | `"2026-12-20"` or relative (`"30 days"`). Default: 30 days out, 2 nights. |
| `adults`, `rooms`, `childrenAges` | Numbers | Guests per room. Default 2 adults, 1 room. |
| `sortBy` | Select | Recommended, price low/high, distance, guest rating, property class. |
| `minPrice` / `maxPrice` | Integer | Nightly price range in the site's currency. |
| `starRatings`, `minGuestRating`, `propertyTypes`, `stayType`, `amenities`, `mealPlans`, `deals` | Select | Expedia's own filter values. |
| `freeCancellation`, `payLater`, `showAvailableOnly` | Boolean | Expedia's refundable / pay-later / availability switches. |
| `propertyName`, `neighborhoodId`, `customFilters` | Text / JSON | Name search, one neighborhood, and more Expedia filters by their id: `accessibility`, `travelerType`, `bedroomFilter`, `hotel_brand`, `neighborhood`, `room_views_group`, `room_amenities_group`, `beach_access_group`, `nearby_activities_group`, `amenities_facilities_group`, or Expedia's ids for the filters above (`star`, `guestRating`, `amenities`, `lodging`, `categorySearch`, `mealPlan`, `paymentType`, `rewards`, `availableFilter`); any other id is ignored with a note in RUN_SUMMARY. |
| **✂️ Refine results** | | |
| `minReviews`, `onlyWithPrice` | | Drop hotels with few reviews or no price. |
| `reviewsFrom` / `reviewsTo`, `minRating` / `maxRating`, `onlyWithText`, `reviewLanguages` | | Review date window (`"2026-01-01"`, or how far back: `"30 days"` = the last 30 days), score band, text-only, languages (matched on `language`; score-only reviews have none, so a language filter drops them). |
| **💬 Reviews** | | |
| `maxReviewsPerHotel` | Integer | Default `50`; `0` = every review Expedia serves. |
| `reviewSort`, `travelerType`, `reviewKeyword` | | Expedia's review order, traveler-type filter and review search. |
| `maxHotelsPerSearch` | Integer | In `reviews` mode, how many top hotels of each destination are read. Default `10`. |
| `includeReviewPhotos`, `includeOwnerResponses`, `includeReviewMarkdown`, `stripPersonalData` | Boolean | Photos and responses on by default; markdown copy for LLM pipelines. `stripPersonalData` (on by default) empties `authorName`, `reviewerName` and `hotelResponseAuthor`, and takes the greeting name, the reviewer's name and the staff name in the sign-off out of `hotelResponse`; a name staff write elsewhere in a reply can remain (turn off `includeOwnerResponses` to leave replies out). |
| **➕ Extra data** | | |
| `includeDetails` | Boolean | Hotel details on each hotel row, charged as **hotel-details** at $0.00095 per hotel. `includeRooms` and `maxPropertyImages` shape it. |
| `ratePositionReport`, `ratePositionSubject` | Boolean / Text | One report row per destination (up to 5 per run), charged as **rate-position-report** at $0.14. |
| **🔁 Monitoring** | | |
| `monitorMode`, `monitorPriceChanges`, `monitorStoreName` | | Only hotel and review rows not delivered by earlier runs; price changes re-delivered. Hotels are remembered per search (destination, dates, guests, filters, sort) and, for hotels you list, per list and stay (dates and guests). Reviews are remembered per hotel, shared by every search and list that uses the same store, so give each schedule its own `monitorStoreName`. The rate-position report is rebuilt and charged on every run. |
| **📦 Output** | | |
| `maxResults` | Integer | Hotels per destination. Default `100`; `0` = all Expedia serves (about 500). Hotels you list (links, ids, names) are not capped: each gets its row. |
| `compact` | Boolean | Core fields only, for AI agents and MCP. |

#### Input JSON

```json
{
  "locations": ["Lisbon"],
  "checkIn": "2026-12-20",
  "checkOut": "2026-12-22",
  "adults": 2,
  "starRatings": ["4", "5"],
  "maxResults": 100
}
```

Reviews of specific hotels:

```json
{
  "startUrls": ["https://www.expedia.com/London-Hotels-Strand-Palace-Hotel.h179.Hotel-Information"],
  "maxReviewsPerHotel": 500,
  "reviewSort": "newest"
}
```

#### Put hotels in the hotel fields, places in Destinations

A destination gives up to **Max hotels per destination** hotel rows; a hotel link, id or name gives that hotel's reviews (or its own row in `hotels` mode, every hotel you list). **Do:** `"locations": ["Lisbon"]` · **Don't:** paste a city into `startUrls` expecting reviews of every hotel - use `mode: "reviews"` with `maxHotelsPerSearch` for that.

For a city name several places share (Dublin, Vienna, Portland), write the state or country: `"Dublin, Ireland"`, `"Portland, Maine"`. Without it the actor takes, every run, the place with its own major airport (Dublin -> Dublin, Ireland; Athens -> Athens, Greece), then the one with the lowest Expedia region id, and names the other places with their region ids in RUN_SUMMARY `notes`. A destination whose matched name does not contain your text gets a note too.

#### Prices follow the site you pick

Each Expedia site prices in its own currency: `expedia.co.uk` gives GBP, `expedia.de` EUR. Setting `currency` on the default site switches to the matching site (EUR uses expedia.ie).

### ⬆️ Output

Every hotel, review and report becomes one dataset item, told apart by `type`. Here is the table view of a run for `Lisbon`:

<a href="https://console.apify.com/actors/d4GG89u0dl98UFLJJ"><img src="https://api.apify.com/v2/key-value-stores/qNQ9zP0xaj2yxGeMY/records/expedia-hotels-scraper-output.png" alt="Expedia & Hotels.com Scraper output table" style="width:70%"></a>

A hotel row as JSON (trimmed):

```json
{
  "type": "hotel",
  "hotelId": "7369640",
  "name": "Meliá Lisboa Aeroporto",
  "url": "https://www.expedia.com/Lisbon-District-Hotels-Melia-Lisboa-Aeroporto.h7369640.Hotel-Information?chkin=2026-11-07&chkout=2026-11-09&rm1=a2",
  "position": 1,
  "starRating": 4,
  "guestRating": 9.4,
  "guestRatingLabel": "Exceptional",
  "reviewCount": 3097,
  "pricePerNight": 204,
  "totalPrice": 451,
  "currency": "USD",
  "taxesIncluded": true,
  "neighborhood": "Olivais",
  "amenities": ["Spa", "Hot tub on site", "Bar and lounge"],
  "latitude": 38.770382,
  "longitude": -9.125218,
  "address": "Aeroporto Internacional de Lisboa, Rua C, Lisbon, 1700-008, PRT",
  "checkIn": "2026-11-07",
  "checkOut": "2026-11-09"
}
```

A review row (trimmed):

```json
{
  "type": "review",
  "hotelId": "179",
  "hotelName": "Strand Palace Hotel",
  "reviewId": "6ac3a2e59a328577543026e2",
  "reviewRating": 4,
  "reviewRatingLabel": "Poor",
  "reviewDate": "2026-10-05T00:00:00.000Z",
  "stayDate": "2026-10-01T00:00:00.000Z",
  "stayDuration": 2,
  "traveledWith": "Traveled with partner",
  "reviewText": "Poor Maintenance, Bad Management, Great Location. We arrived around 1 a.m. ...",
  "hotelResponse": "Dear Guest, Thank you for sharing your feedback ...",
  "hotelResponseDate": "2026-10-06T00:00:00.000Z",
  "language": "en",
  "hotelOverallRating": 9,
  "hotelTotalReviews": 5759
}
```

#### Fields

| Field | Type | What it is | Fill on test run |
|---|---|---|---|
| `hotelId`, `name`, `url`, `position` | string / number | Expedia property id (same on Hotels.com), name, link with your dates, rank in the results | 100% |
| `starRating` | number | Property class | 100% (100 hotels), 99.8% (500) |
| `guestRating`, `guestRatingLabel`, `reviewCount` | number / string | Guest score out of 10, its label, review count | 100% |
| `pricePerNight`, `totalPrice`, `priceText` | number / string | Nightly price and stay total in `currency` | 100% (100), 99.2% (500) |
| `strikeOutPrice`, `dealBadge` | number / string | Was-price and deal badge | 62%, 51% |
| `memberPrice`, `vipAccess`, `freeCancellation`, `payLater`, `roomsLeft` | boolean / number | Expedia's flags on the card | when Expedia shows them |
| `neighborhood`, `amenities`, `image`, `images` | string / array | Card location label, three top amenities, photos | 100% |
| `latitude`, `longitude`, `address`, `street`, `city`, `postalCode`, `countryCode` | number / string | Where the property is | 100% |
| `reviewRating`, `reviewRatingLabel`, `reviewDate`, `stayDate`, `stayDuration` | number / string | Review score, label, dates, nights | 100% (1,000 reviews) |
| `reviewText`, `reviewTitle` | string | What the guest wrote | 71%, rare titles |
| `traveledWith`, `liked`, `disliked` | string / array | Traveler type and topics | 58%, 80%, 4% |
| `hotelResponse`, `hotelResponseDate` | string | The property's reply; with `stripPersonalData` (default) without the greeting name, the reviewer's name or the staff name in the sign-off | 86% (one hotel), 59% (10 hotels) |
| `language`, `photos` | string / array | Language: the one Expedia marks on a review written in another language than the site's (`de`, `fr`, `ja`...), otherwise `en`, the site's language (a few untranslated non-English reviews read `en` too); empty on score-only reviews. Guest photos | 71%, 3-8% |
| `hotelOverallRating`, `hotelTotalReviews`, `hotelCategoryRatings` | number / array | The hotel's score, review count, category scores on every review | 100% |

### How can I use Expedia hotel data?

- 💹 **Revenue managers** - track your hotel's nightly rate and rank against the market every day with monitor mode and the rate-position report.
- 🧭 **OTA and meta-search teams** - compare Expedia prices, deals and refundable rates with other channels for the same dates.
- 🗺️ **Travel analysts** - map supply, star mix and price bands by neighborhood with coordinates on every row.
- ⭐ **Reputation teams** - collect every review and the hotel's responses; filter by traveler type, score band or keyword.
- 🤖 **AI and research teams** - feed review text, liked/disliked topics and markdown copies into an LLM or a RAG index.
- 📈 **Investors and consultants** - benchmark a property's guest score, category scores and pricing before a deal.

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

Expedia & Hotels.com Scraper is pay-per-result with no start fee:

| What | Price |
|---|---:|
| Hotel row (`hotel`) | **$2.30 per 1,000** ($0.0023 each) |
| Review row (`review`) | **$2.00 per 1,000** ($0.002 each) |
| Hotel details add-on (`hotel-details`) | $0.95 per 1,000 hotels |
| Rate-position report (`rate-position-report`) | $0.14 per report |

| Run | Cost |
|---|---:|
| 25 hotels | $0.06 |
| 100 hotels | $0.23 |
| 500 hotels (all of London) | $1.15 |
| 100 hotels with details | $0.33 |
| 1,000 reviews | $2.00 |
| 10 hotels x 100 reviews | $2.00 |

There is nothing else to pay: Apify platform usage is included in these prices. You are charged only for rows written to the dataset. On the default 256 MB a 100-hotel run took 6-9 seconds and 150 reviews of one hotel 4-5 seconds (two runs each).

### Integrations, API, scheduling & MCP

- **Schedules:** run Expedia & Hotels.com Scraper daily from the **Schedules** tab; turn on `monitorMode` to get only new hotels, price changes and new reviews of the hotels you follow.
- **Webhooks:** fire a URL when a run finishes - push rows to your database, Slack or a sheet.
- **No-code:** Make, Zapier, n8n, Google Sheets, Airtable, Slack via [Apify integrations](https://docs.apify.com/integrations).
- **API:** call it from Node.js or Python with `apify-client` - code on the [API tab](https://apify.com/topapi/expedia-hotels-scraper/api/python) and the [Apify API reference](https://docs.apify.com/api/v2).
- **MCP / AI agents:** connect Claude, Cursor or any MCP client through the [MCP tab](https://apify.com/topapi/expedia-hotels-scraper/api/mcp) and ask for Expedia hotels or reviews in plain language.

### More hotel and review scrapers

<table>
<tr>
<td>📊 <a href="https://apify.com/topapi/similarweb-scraper">SimilarWeb Scraper</a></td>
<td>🔎 <a href="https://apify.com/topapi/google-hotels-scraper">Google Hotels Scraper</a></td>
<td>💬 <a href="https://apify.com/topapi/agoda-reviews-scraper">Agoda Reviews Scraper</a></td>
</tr>
<tr>
<td>📍 <a href="https://apify.com/topapi/google-maps-reviews-scraper">Google Maps Reviews Scraper</a></td>
<td>⭐ <a href="https://apify.com/topapi/yelp-reviews-scraper">Yelp Reviews Scraper</a></td>
<td>✅ <a href="https://apify.com/topapi/trustpilot-reviews-scraper">Trustpilot Reviews Scraper</a></td>
</tr>
<tr>
<td>👍 <a href="https://apify.com/topapi/facebook-reviews-scraper">Facebook Reviews Scraper</a></td>
<td>🗺️ <a href="https://apify.com/topapi/apple-maps-scraper">Apple Maps Scraper</a></td>
<td>🌐 <a href="https://apify.com/topapi/google-geocoding-scraper">Google Geocoding Scraper</a></td>
</tr>
<tr>
<td colspan="3">🧭 <a href="https://apify.com/topapi">All TopApi actors</a></td>
</tr>
</table>

### Limits & empty runs

- **Hotels per destination:** Expedia serves about 500 hotels for one search (London 500, Lisbon 488). Split a city into neighborhoods or price bands to go deeper.
- **Reviews:** every review Expedia lists for the property; the score, date and stay month are on every row, text on about 70% (Expedia accepts score-only reviews).
- **Not available:** the property's long description (Expedia's API returns none for it; the details block carries the area description, highlights and amenities instead).
- **Empty dataset:** the destination or hotel was not matched (RUN_SUMMARY lists each input and why), every hotel was filtered out, or monitor mode found nothing new. Nothing is charged.
- **Proxy:** Expedia answers residential connections only; keep the default RESIDENTIAL proxy.

### FAQ

#### How many hotels can Expedia & Hotels.com Scraper collect in one run?

About 500 per destination (all Expedia serves for one search), across as many destinations as you list. Hotels are read 100 per request; a 100-hotel destination took 6-9 seconds in two test runs.

#### How many reviews can Expedia & Hotels.com Scraper read per hotel?

All of them: set `maxReviewsPerHotel` to `0`. A test read all 5,759 reviews of the Strand Palace Hotel, 50 per request.

#### Can I run Expedia & Hotels.com Scraper on a schedule to track prices?

Yes. Save your input as a task, open **Schedules**, pick the cadence and turn on `monitorMode`: each run delivers only hotels you have not received for that search (or, for hotels you list, that list and stay), hotels whose stay price changed (`changeType: "priceChanged"` with `previousTotalPrice`), and reviews not yet delivered for that hotel. Review memory is per hotel and shared by every run that uses the same monitor store, so give each schedule its own **Monitor store name** (`monitorStoreName`). In `hotelsAndReviews` mode the new reviews come from the top **Max hotels per destination** hotels of each search plus any hotel delivered in that run, whether or not their hotel row came back. A rate-position report, if on, is rebuilt and charged on every run (a fresh market snapshot).

#### Does Expedia & Hotels.com Scraper work with Hotels.com and regional Expedia sites?

Yes. Pick the site in **Expedia site** (30 sites). In **Hotel or search links** paste Hotels.com links with the hotel name in them (`hotels.com/ho114409/strand-palace-hotel-london-united-kingdom/`) or Expedia hotel ids; a bare Hotels.com ho-number is a different numbering and is not accepted. Reviews are the same pool on every Expedia Group site.

#### Can I integrate Expedia & Hotels.com Scraper with other apps?

Yes - Make, Zapier, n8n, Google Sheets, Slack and more via [Apify integrations](https://docs.apify.com/integrations), or [webhooks](https://docs.apify.com/integrations/webhooks) when a run finishes.

#### Can I use Expedia & Hotels.com Scraper with the Apify API?

Yes. Use `apify-client` for [Node.js](https://apify.com/topapi/expedia-hotels-scraper/api/javascript) or [Python](https://apify.com/topapi/expedia-hotels-scraper/api/python); the API tab has ready-to-paste code.

#### Can I use Expedia & Hotels.com Scraper through an MCP server?

Yes. Open the [MCP tab](https://apify.com/topapi/expedia-hotels-scraper/api/mcp), connect your MCP client and ask for hotels or reviews in plain language. Turn on `compact` for shorter rows.

#### Do I need an Expedia account, cookies or an API key?

No. Expedia & Hotels.com Scraper reads what Expedia shows any visitor; you pass destinations, hotel links, ids or names.

#### What is in the hotel details add-on of Expedia & Hotels.com Scraper?

Amenities by category, policies (check-in/out, pets, children), important info and fees, category scores, the 5-band rating histogram, Expedia's AI review summary, highlights, nearby places with walk/drive times, the photo gallery, and every room with its rates (meal plan, nightly and total price, payment options) for your dates.

#### Why did my Expedia & Hotels.com Scraper run return no results?

Most often the destination or hotel name was not matched (see `notFound` in RUN_SUMMARY, with candidates for names), filters removed every hotel or review (RUN_SUMMARY `filtered` and `notes` say which), or monitor mode had already delivered everything. A check-in date in the past does not empty a run: it is moved to tomorrow (see the run log). Nothing is charged for an empty run.

#### Is it legal to scrape Expedia?

Expedia & Hotels.com Scraper reads only publicly visible hotel listings and reviews; it does not log in. Review rows can contain first names, which data-protection laws such as the GDPR regulate, so by default (`stripPersonalData`) the reviewer and responder name fields are empty, and the greeting name, the reviewer's name and the staff name in the sign-off are taken out of hotel replies. A name staff write elsewhere in a reply can remain; turn off `includeOwnerResponses` to leave replies out. This actor is not affiliated with, endorsed or sponsored by Expedia Group, Expedia.com or Hotels.com; trademarks belong to their owners.

#### Your feedback

We keep improving Expedia & Hotels.com Scraper. Found a bug or missing a field? Open an issue on the [Issues tab](https://apify.com/topapi/expedia-hotels-scraper/issues/open).

# Actor input Schema

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

Auto: destinations -> hotel search rows, hotels -> their reviews. Hotels: hotel rows only (a hotel link gives its row with the lead room price). Reviews: reviews only (of the hotels you list, or of the top hotels of each destination). Hotels + reviews: both.

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

Cities, neighborhoods, landmarks or airports (by name or code, e.g. "Heathrow Airport", "JFK"), as you would type them on Expedia, e.g. "Lisbon", "Times Square, New York", "Dublin, Ireland". For a name several places share, add the state or country ("Dublin, Ohio"); without it the place with its own major airport is used (Dublin -> Dublin, Ireland), then the lowest Expedia region id, and RUN_SUMMARY notes list the others with their region ids. Each gives up to "Max hotels per destination" hotel rows.

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

Expedia or Hotels.com hotel links (any regional site, also Travelocity / Orbitz / Wotif / CheapTickets / ebookers), Hotel-Search links, expe.app.link share links, bare Expedia hotel ids (Hotels.com links need the hotel name in them), e.g. "https://www.expedia.com/London-Hotels-Strand-Palace-Hotel.h179.Hotel-Information", "179".

## `hotelNames` (type: `array`):

Hotel names with their city, e.g. "Four Seasons Hotel Ritz Lisbon". Matched on Expedia's own search; a name without a confident match is listed in RUN_SUMMARY and not guessed.

## `regionIds` (type: `array`):

Expedia region ids (the regionId= of a search link), e.g. "2114" for London. Skips the destination lookup.

## `googleMapsInputs` (type: `array`):

Google Maps place links of hotels, e.g. "https://www.google.com/maps/place/Strand+Palace+Hotel/@51.51,-0.12,17z". The hotel name and position are matched against Expedia's hotels (within 2 km).

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

Which Expedia site prices the stay. Prices come in that site's currency (expedia.co.uk -> GBP). Hotels.com gives Hotels.com links.

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

YYYY-MM-DD or relative, e.g. "2026-12-20", "30 days", "tomorrow". Empty = 30 days from today.

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

YYYY-MM-DD or nights after check-in, e.g. "2026-12-22" or "3 days". Empty = 2 nights.

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

Adults in each room.

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

Number of rooms (each with the adults above).

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

One age (0-17) per child, e.g. "5", "9". Children stay in the first room.

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

Expedia's own sort orders.

## `minPrice` (type: `integer`):

Lowest nightly price in the site's currency, e.g. 80.

## `maxPrice` (type: `integer`):

Highest nightly price in the site's currency, e.g. 300.

## `starRatings` (type: `array`):

Only these property classes. Empty = any.

## `minGuestRating` (type: `string`):

Expedia's guest-score filter.

## `amenities` (type: `array`):

Only properties with all of these.

## `propertyTypes` (type: `array`):

Only these property types. Empty = any.

## `stayType` (type: `string`):

Expedia's "Type of place" switch.

## `mealPlans` (type: `array`):

Only properties offering these meal plans.

## `freeCancellation` (type: `boolean`):

Only properties with a fully refundable rate.

## `payLater` (type: `boolean`):

Only properties that let you pay at the property.

## `deals` (type: `array`):

Expedia's One Key / deals filters.

## `propertyName` (type: `string`):

Expedia's "Search by property name" filter, e.g. "marriott".

## `showAvailableOnly` (type: `boolean`):

Hide sold-out properties.

## `neighborhoodId` (type: `string`):

Limit a search to one neighborhood (its Expedia region id, e.g. "179463" for Baixa, Lisbon).

## `customFilters` (type: `object`):

More Expedia filters by their id: accessibility, travelerType, bedroomFilter, hotel_brand, neighborhood, room_views_group, room_amenities_group, beach_access_group, nearby_activities_group, amenities_facilities_group, or Expedia's ids for the filters above (star, guestRating, amenities, lodging, categorySearch, mealPlan, paymentType, rewards, availableFilter). Any other id is ignored with a note in RUN_SUMMARY. E.g. {"accessibility": \["ELEVATOR"], "travelerType": \["family_friendly"], "bedroomFilter": \["2"], "hotel_brand": \["2680"]}.

## `minReviews` (type: `integer`):

Drop hotels with fewer guest reviews, e.g. 50.

## `onlyWithPrice` (type: `boolean`):

Drop hotels Expedia shows without a price for your dates.

## `reviewsFrom` (type: `string`):

Only reviews written on or after this day: YYYY-MM-DD, or how far back from today, e.g. "2026-01-01", "30 days" (the last 30 days), "6 months".

## `reviewsTo` (type: `string`):

Only reviews written on or before this day: YYYY-MM-DD, or how far back from today, e.g. "2026-06-30", "7 days".

## `minRating` (type: `integer`):

Only reviews scoring at least this (Expedia's 1-10 scale).

## `maxRating` (type: `integer`):

Only reviews scoring at most this, e.g. 4 for complaints.

## `onlyWithText` (type: `boolean`):

Skip score-only reviews.

## `reviewLanguages` (type: `array`):

Two-letter codes, e.g. "en", "fr". Empty = all. Matched on the row's language: the one Expedia marks on a review written in another language than the site's, otherwise en, the site's language (a few untranslated non-English reviews read en too). Score-only reviews have no language, so this filter drops them.

## `maxReviewsPerHotel` (type: `integer`):

0 = every review Expedia serves (all 5,759 of Strand Palace Hotel in a test).

## `reviewSort` (type: `string`):

Expedia's own review orders.

## `travelerType` (type: `string`):

Expedia's traveler-type review filter.

## `reviewKeyword` (type: `string`):

Expedia's "Search reviews" box, e.g. "breakfast".

## `maxHotelsPerSearch` (type: `integer`):

In Reviews mode, how many top hotels of each destination have their reviews read.

## `includeReviewPhotos` (type: `boolean`):

Photo links guests attached.

## `includeOwnerResponses` (type: `boolean`):

The property's reply and its date.

## `includeReviewMarkdown` (type: `boolean`):

Adds reviewMarkdown: the review as one markdown block for LLM / RAG pipelines.

## `stripPersonalData` (type: `boolean`):

ON: authorName, reviewerName and hotelResponseAuthor are empty, and the greeting name, the reviewer's name and the staff name in the sign-off are taken out of hotelResponse (and reviewMarkdown). A name staff write elsewhere in a reply can remain; turn off Hotel responses to leave replies out. OFF: names are filled and replies are kept as written.

## `includeDetails` (type: `boolean`):

Adds to each hotel row: amenities by category, policies, important info, scores by category, rating histogram, AI review summary, highlights, nearby places, photo gallery, rooms and rates. Charged as hotel-details at $0.00095 per hotel.

## `includeRooms` (type: `boolean`):

Room types with size, beds, photos and every rate (meal plan, price, payment options) for your dates. Part of hotel details.

## `maxPropertyImages` (type: `integer`):

Cap the gallery in hotel details, e.g. 20. 0 = all.

## `ratePositionReport` (type: `boolean`):

One report row per destination (up to 5 per run): nightly-rate and guest-score spread, prices by star class, and where your hotel ranks. Charged as rate-position-report at $0.14 per report; never charged when fewer than 3 hotels have a price.

## `ratePositionSubject` (type: `string`):

Part of your hotel's name or its Expedia id, e.g. "Strand Palace".

## `monitorMode` (type: `boolean`):

Skip hotels and reviews delivered by earlier runs: hotels per search, or for hotels you list per list and stay (dates and guests); reviews per hotel, whichever search or list delivered them. Hotels come back when their stay price changes (see below). Use a separate monitor store per schedule. A rate-position report is rebuilt and charged on every run.

## `monitorPriceChanges` (type: `boolean`):

In monitor mode, deliver a hotel again when its stay price changed (changeType "priceChanged" + previousTotalPrice).

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

Named key-value store that remembers delivered rows. Use one per schedule: review memory is per hotel, so schedules sharing a store share it. Default: expedia-hotels-monitor.

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

0 = all Expedia serves for the search (about 500 hotels per destination, measured on London and Lisbon). Split a city into neighborhoods to go deeper. Hotels you list (links, ids, names) are not capped: each gets its row.

## `compact` (type: `boolean`):

Core fields only, sized for AI agents and MCP. Details fields stay when hotel details are on.

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

Expedia answers residential connections only (datacenter proxies are refused). Keep RESIDENTIAL.

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

Parallel requests.

## Actor input object example

```json
{
  "mode": "auto",
  "locations": [
    "Lisbon"
  ],
  "site": "expedia.com",
  "adults": 2,
  "rooms": 1,
  "sortBy": "RECOMMENDED",
  "minGuestRating": "ANY",
  "stayType": "any",
  "freeCancellation": false,
  "payLater": false,
  "showAvailableOnly": false,
  "onlyWithPrice": false,
  "onlyWithText": false,
  "maxReviewsPerHotel": 50,
  "reviewSort": "newest",
  "travelerType": "all",
  "maxHotelsPerSearch": 10,
  "includeReviewPhotos": true,
  "includeOwnerResponses": true,
  "includeReviewMarkdown": false,
  "stripPersonalData": true,
  "includeDetails": false,
  "includeRooms": true,
  "maxPropertyImages": 0,
  "ratePositionReport": false,
  "monitorMode": false,
  "monitorPriceChanges": true,
  "maxResults": 25,
  "compact": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  },
  "maxConcurrency": 3
}
```

# Actor output Schema

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

Hotel rows, review rows and rate-position report rows (field "type").

## `summary` (type: `string`):

Per destination and per hotel: pages read, rows delivered, inputs not matched, filtered rows, request success rate.

# 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"
    ],
    "maxResults": 25,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("topapi/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"],
    "maxResults": 25,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("topapi/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"
  ],
  "maxResults": 25,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call topapi/expedia-hotels-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,topapi/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/d4GG89u0dl98UFLJJ/builds/zTOD3WH9zKENylSUE/openapi.json
