# Expedia Hotels Scraper — Prices, Ratings & Reviews (`haketa/expedia-scraper`) Actor

Scrape hotels from Expedia by destination and dates: name, nightly price, guest rating, reviews count, location, deals and link. Optionally attach real guest reviews per hotel (text, score, date, reviewer, manager replies). Export JSON/CSV for rate shopping, price intelligence and review analysis.

- **URL**: https://apify.com/haketa/expedia-scraper.md
- **Developed by:** [Haketa](https://apify.com/haketa) (community)
- **Categories:** Travel
- **Features:** Limited permissions
- **Stats:** 11 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 results

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

<h1 align="center">Expedia Hotels Scraper — Nightly Prices, Ratings, Deals & Guest Reviews</h1>

<p align="center"><b>Scrape hotel listings, live nightly prices, guest ratings, review counts, promotional deal badges, and verified guest reviews from <a href="https://www.expedia.com/">Expedia</a> across any destination and travel date window. Built for hotel revenue management, OTA rate shopping, competitive benchmarking, and travel market intelligence.</b></p>

<p align="center">
  <img src="https://img.shields.io/badge/Platform-Apify-00C853?style=for-the-badge&logo=apify&logoColor=white" alt="Apify Platform" />
  <img src="https://img.shields.io/badge/Data-Expedia%20Hotels%20%26%20Reviews-1E88E5?style=for-the-badge" alt="Expedia Hotels & Reviews" />
  <img src="https://img.shields.io/badge/Pagination-1%2C000%2B%20Multi--City%20Scale-8E24AA?style=for-the-badge" alt="1,000+ Pagination" />
  <img src="https://img.shields.io/badge/Use%20Case-Rate%20Shopping%20%26%20RevPAR-F4511E?style=for-the-badge" alt="Rate Shopping & RevPAR" />
  <img src="https://img.shields.io/badge/Export-JSON%20%7C%20CSV%20%7C%20Excel%20%7C%20API-43A047?style=for-the-badge" alt="Export Formats" />
</p>

***

### ⚡ At a glance

| Feature | Details |
| :--- | :--- |
| 🏨 **Primary Target** | Expedia (`expedia.com`) Hotel Search & Property Guest Reviews |
| 💰 **Core Pricing & Rank Data** | Lead nightly price (`priceNightly`), currency, all card price figures (`allPrices`), deal badges, organic/sponsored rank |
| ⭐ **Ratings & Reviews** | Overall guest score out of 10 (`rating`), `ratingLabel` (`Exceptional`, `Wonderful`, etc.), `reviewCount`, plus optional full review text |
| 🌍 **Search Modes** | 25 built-in global destinations, custom city/region names (`customDestinations`), or custom filtered `startUrls` |
| 📈 **Pagination & 1,000+ Scale** | Automated infinite-scroll + `"Show more"` expansion, multi-sort deep inventory discovery, and 25-city scaling for **1,000+ hotels** |
| ⚡ **Speed & Reliability** | Fast prefill (`30` hotels in **~35–60 seconds**); automatic session rotation and past-date auto-adjustment |
| 📦 **Bulk Export Formats** | JSON, CSV, Excel (XLSX), HTML, XML, RSS, and direct Apify REST API / Webhooks |

***

### 🔎 Why scrape Expedia hotels & prices?

**Expedia** is one of the world's largest online travel agencies (OTAs), setting the benchmark for real-time hotel pricing, room availability, promotional discounting, and guest sentiment across thousands of global destinations. For revenue managers, hospitality groups, metasearch analysts, and travel tech teams, Expedia's search results represent a live pulse of hospitality supply and demand.

However, Expedia does not offer a public API for competitive rate shopping. Its search interface is a complex single-page application (SPA) that lazy-loads properties via infinite scroll, mixes sponsored ads with organic rankings, and enforces strict anti-bot rate limits. Manually tracking nightly rates across multiple check-in dates, party sizes, and competitor sets is impossible at scale.

This **Expedia scraper** automates the entire extraction process: it renders the live Hotel-Search results over residential proxies, scrolls through the full property list, extracts structured pricing and rating metrics, optionally attaches verified guest reviews, and deduplicates every property by `hotelId`.

#### Key reasons teams use this Expedia data extractor:

- 💷 **Automated OTA rate shopping:** Track your property's and competitors' exact nightly rates (`priceNightly`) and total stay prices (`allPrices`) across future check-in/check-out windows.
- 📊 **Competitive set (CompSet) benchmarking:** Compare guest ratings (`rating`), review volumes (`reviewCount`), and promotional badges (`dealBadge`) across neighborhoods and markets.
- 🏷️ **Visibility & sponsored-placement auditing:** Monitor organic search rank (`rank`) versus paid sponsored placements (`isSponsored`) for target destination queries.
- 💬 **Guest sentiment & reputation intelligence:** Enable `scrapeReviews` to extract verified guest review text, scores, sentiment themes (`Liked: Cleanliness, staff & service`), and hotel management responses.
- 🌐 **Multi-city hospitality market research:** Aggregate **1,000+ hotel listings** across dozens of cities to model seasonal ADR (Average Daily Rate) trends and supply distribution.

***

### ✨ What this Expedia scraper does

- ✅ **Search by destination, dates & occupancy:** Choose from 25 built-in top destinations, enter any city or landmark in `customDestinations` (e.g., `"Reykjavik"`, `"Scottsdale"`, `"Santorini"`), and configure `checkIn`, `checkOut`, `adults`, `rooms`, and `sortBy`.
- ✅ **Custom `startUrls` support:** Paste any pre-filtered Expedia Hotel-Search URL (with star ratings, neighborhood filters, amenities, or price bounds applied in your browser).
- ✅ **Deep infinite-scroll & multi-sort pagination for 1,000+ hotels:** Automatically scrolls and clicks **Show more** up to 120 iterations per page, and automatically expands across sort orders and 25 global cities when `maxItems` / `maxItemsPerSearch` targets **1,000+ properties**.
- ✅ **Automatic past-date protection:** If a saved task or input passes a `checkIn` date in the past, the actor automatically shifts the stay window 30 days into the future so scheduled runs never fail with empty results.
- ✅ **Complete hotel card metrics:** Extracts `hotelId`, `name`, `url`, `priceNightly`, `priceCurrency`, `allPrices`, `rating`, `ratingLabel`, `reviewCount`, `location`, `dealBadge`, `isSponsored`, `image`, `searchDestination`, `checkIn`, `checkOut`, `rank`, and `scrapedAt`.
- ✅ **Optional verified guest reviews (`scrapeReviews`):** Extracts up to `maxReviewsPerHotel` recent reviews per property, including `reviewId`, numeric `score`, `scoreText`, `superlative`, `title`, `text`, `date`, `verified` status, `author`, `themes`, and `managerResponse`.
- ✅ **Global deduplication:** Deduplicates hotels by `hotelId` across all pages, sort modes, and destinations within a run.

***

### 🎯 Use cases

| Role / Team | How they use this Expedia scraper |
| :--- | :--- |
| **Hotel Revenue Managers** | Schedule daily rate-shopping runs across 7-, 30-, and 60-day advance booking windows to optimize RevPAR and ADR. |
| **OTA & Metasearch Analysts** | Audit rate parity, promotional discounting (`Member Price`, `Save 20%`), and sponsored ad share (`isSponsored`). |
| **Hospitality Investors & Consultants** | Map hotel supply, price tiers, and guest rating distributions across target acquisition markets. |
| **Vacation Rental & Short-Term Managers** | Benchmark Airbnb/Vrbo nightly rates against comparable local hotel inventory on Expedia during peak events. |
| **Guest Experience & Brand Teams** | Extract recent guest reviews (`scrapeReviews: true`) to analyze competitor weaknesses and manager response rates. |
| **Travel Data & BI Engineers** | Feed structured JSON/CSV hotel pricing feeds into Snowflake, BigQuery, PowerBI, Tableau, or Google Sheets. |

***

### 📥 Input configuration

All parameters are optional. Leaving the input empty runs a multi-city sample across top global destinations.

| Parameter | Type | Default / Prefill | Description |
| :--- | :--- | :--- | :--- |
| `destinations` | `array<string>` | `Prefill: ["New York"]` | Select one or more popular cities from the built-in 25-city dropdown (New York, Las Vegas, Orlando, Miami, London, Paris, Tokyo, Dubai, etc.). |
| `customDestinations` | `array<string>` | `[]` | Enter any city, island, region, or landmark not in the dropdown (e.g., `["Bali", "Aspen", "Lisbon"]`). |
| `checkIn` | `string` | `Prefill: "2027-03-15"` | Check-in date in `YYYY-MM-DD` format. Past dates are automatically advanced to upcoming dates. |
| `checkOut` | `string` | `Prefill: "2027-03-17"` | Check-out date in `YYYY-MM-DD` format. |
| `adults` | `integer` | `2` | Number of adults per room (`1`–`14`). |
| `rooms` | `integer` | `1` | Number of rooms (`1`–`8`). |
| `sortBy` | `string` | `"RECOMMENDED"` | Sort order: `RECOMMENDED`, `PRICE_LOW_TO_HIGH`, `PRICE_HIGH_TO_LOW`, `REVIEW`, or `DISTANCE`. |
| `maxItemsPerSearch` | `integer` | `0` (Prefill: `30`) | Maximum hotels to collect per destination. Set `0` for all loaded hotels on the page, or `30` for a fast preview. |
| `scrapeReviews` | `boolean` | `false` | When `true`, fetches recent guest reviews for each extracted hotel. |
| `maxReviewsPerHotel` | `integer` | `10` | Maximum guest reviews to fetch per hotel when `scrapeReviews: true`. |
| `startUrls` | `array<object>` | `[]` | Optional custom Expedia `Hotel-Search` URLs with advanced browser filters applied. |
| `proxyConfiguration` | `object` | `US RESIDENTIAL` | Apify Proxy configuration. US Residential proxies are pre-configured and required for reliable access. |
| `maxConcurrency` | `integer` | `1` | Parallel browser sessions (`1`–`10`). Keep at `1`–`2` for highest reliability and lowest proxy usage. |

#### Example 1: Fast prefill run (30 New York hotels)

```json
{
  "destinations": ["New York"],
  "checkIn": "2027-03-15",
  "checkOut": "2027-03-17",
  "adults": 2,
  "rooms": 1,
  "sortBy": "RECOMMENDED",
  "maxItemsPerSearch": 30,
  "scrapeReviews": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "US"
  },
  "maxConcurrency": 1
}
```

#### Example 2: Multi-city rate shopping for 1,000+ hotels

```json
{
  "destinations": [
    "New York", "Las Vegas", "Orlando", "Los Angeles", "Miami",
    "Chicago", "San Francisco", "London", "Paris", "Rome"
  ],
  "customDestinations": ["Nashville", "Austin"],
  "checkIn": "2027-05-10",
  "checkOut": "2027-05-14",
  "adults": 2,
  "rooms": 1,
  "sortBy": "PRICE_LOW_TO_HIGH",
  "maxItemsPerSearch": 120,
  "scrapeReviews": false
}
```

#### Example 3: Deep hotel competitor analysis with guest reviews

```json
{
  "destinations": ["Miami"],
  "checkIn": "2027-04-01",
  "checkOut": "2027-04-04",
  "maxItemsPerSearch": 25,
  "scrapeReviews": true,
  "maxReviewsPerHotel": 15
}
```

***

### 📤 Output schema & field reference

Each hotel is saved as a structured JSON record. Below is a verified output item from a live run:

```json
{
  "hotelId": "h40797",
  "name": "Palace Station Hotel and Casino",
  "url": "https://www.expedia.com/Las-Vegas-Hotels-Palace-Station-Hotel-And-Casino.h40797.Hotel-Information",
  "priceNightly": 82,
  "priceCurrency": "USD",
  "allPrices": [82, 82, 369, 369, 287, 287],
  "rating": 8.8,
  "ratingLabel": "Excellent",
  "reviewCount": 4453,
  "location": "Las Vegas",
  "dealBadge": "Member Price",
  "isSponsored": true,
  "image": "https://a.travel-assets.com/media/meso_cm/PAPI/Images/lodging/1000000/50000/40800/40797/7c123e6b_b.jpg",
  "searchDestination": "Las Vegas",
  "checkIn": "2027-03-15",
  "checkOut": "2027-03-17",
  "scrapedAt": "2026-11-10T02:30:00.000Z",
  "rank": 1
}
```

#### 🏨 Hotel Identity, Pricing & Ranking Fields

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| `hotelId` | `string` | 🟢 High (100%) | Unique Expedia property ID (e.g., `"h40797"`, used for deduplication) |
| `name` | `string` | 🟢 High (100%) | Official property name on Expedia |
| `url` | `string` | 🟢 High (100%) | Direct canonical URL to the hotel's Expedia detail page |
| `priceNightly` | `integer` | 🟢 High (~99%) | Lead nightly rate for the selected dates and occupancy |
| `priceCurrency` | `string` | 🟢 High (~99%) | Currency code (e.g., `"USD"`) |
| `allPrices` | `array<integer>` | 🟢 High (~99%) | All numeric price points displayed on the card (nightly, total with taxes, strikethrough rate) |
| `dealBadge` | `string` | 🟡 Conditional (~35%) | Promotional badge when active (`"Member Price"`, `"Save 20%"`, `"Book now, pay later"`) |
| `isSponsored` | `boolean` | 🟢 High (100%) | `true` if the card is a paid sponsored placement (`Ad`), `false` if organic |
| `rank` | `integer` | 🟢 High (100%) | 1-based position of the hotel within the destination search results |

#### ⭐ Guest Rating, Location & Context Fields

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| `rating` | `number` | 🟢 High (~99%) | Guest review score out of 10 (e.g., `8.8`, `9.4`) |
| `ratingLabel` | `string` | 🟢 High (~97%) | Qualitative rating tier (`"Exceptional"`, `"Wonderful"`, `"Excellent"`, `"Very good"`, `"Good"`) |
| `reviewCount` | `integer` | 🟢 High (~98%) | Total number of verified guest reviews |
| `location` | `string` | 🟢 High (~99%) | Neighborhood or city area displayed on the property card |
| `image` | `string` | 🟡 Conditional (~25%) | Thumbnail image URL when present in initial DOM attributes |
| `searchDestination` | `string` | 🟢 High (100%) | Destination query that produced the listing |
| `checkIn` / `checkOut` | `string` | 🟢 High (100%) | Check-in and check-out dates (`YYYY-MM-DD`) used for pricing |
| `scrapedAt` | `string` | 🟢 High (100%) | ISO 8601 timestamp when the property was extracted |

#### 💬 Optional Guest Review Fields (`when scrapeReviews: true`)

| Field | Type | Coverage | Description |
| :--- | :--- | :--- | :--- |
| `reviewsScraped` | `integer` | 🟡 Opt-in (100%) | Count of guest reviews attached to the hotel object |
| `reviews[].reviewId` | `string` | 🟡 Opt-in (100%) | Unique review identifier |
| `reviews[].score` | `number` | 🟡 Opt-in (100%) | Numeric review score out of 10 |
| `reviews[].scoreText` | `string` | 🟡 Opt-in (100%) | Formatted score label (e.g., `"9/10 Wonderful"`) |
| `reviews[].title` / `text` | `string` | 🟡 Opt-in (~97%) | Guest review headline and full body text |
| `reviews[].date` | `string` | 🟡 Opt-in (100%) | Localized submission date (e.g., `"Jun 14, 2026"`) |
| `reviews[].verified` | `boolean` | 🟡 Opt-in (100%) | `true` when flagged as a verified stay |
| `reviews[].author` | `string` | 🟡 Opt-in (~98%) | Reviewer display name |
| `reviews[].themes` | `array<string>` | 🟡 Opt-in (~65%) | Highlighted sentiment tags (e.g., `["Liked: Cleanliness, staff & service"]`) |
| `reviews[].managerResponse` | `string` | 🟡 Opt-in (~30%) | Official reply from the hotel's management team, when present |

***

### 🔁 Pagination & 1,000+ scale architecture

Expedia does not use numbered URL pages (`?page=2`); instead, it uses a virtualized infinite scroll feed with a **"Show more"** trigger. This scraper handles scale at three levels:

1. **Deep single-search scrolling:** Within each destination, the browser scrolls and clicks `"Show more"` up to **120 times** until `maxItemsPerSearch` is reached or the city's inventory is exhausted.
2. **Multi-sort inventory expansion:** When you request `maxItemsPerSearch >= 300` (or `maxItems >= 500`) across 1–3 cities, the scraper automatically queues alternate sort orders (`PRICE_LOW_TO_HIGH`, `PRICE_HIGH_TO_LOW`, `REVIEW`, `DISTANCE`) to surface properties beyond a single feed's scroll depth.
3. **25-city global expansion:** For large multi-market runs (`maxItems: 1000+`), pass multiple `destinations` / `customDestinations` (or let the 25-city expanded default list run) with global `hotelId` deduplication.

***

### ⚙️ How to use

1. **Open the Actor** in the Apify Console.
2. **Pick your `destinations`** (or add `customDestinations` / `startUrls`) and set your `checkIn` and `checkOut` dates.
3. **Set `maxItemsPerSearch`:** use `30` for a fast preview, `100`–`300` for a deep city sweep, or `0` for all available listings.
4. **Keep US Residential Proxy enabled** (pre-filled by default).
5. **Click Start** and export your hotel dataset to **JSON, CSV, Excel, or API**.

#### Calling via Node.js (`apify-client`)

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('haketa/expedia-scraper').call({
    destinations: ['New York', 'Miami', 'Las Vegas'],
    checkIn: '2027-04-15',
    checkOut: '2027-04-18',
    adults: 2,
    maxItemsPerSearch: 50,
    scrapeReviews: false,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Extracted ${items.length} Expedia hotels`);
```

***

#### Calling via Python (`apify-client`)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run = client.actor("haketa/expedia-scraper").call(run_input={
    "destinations": ["New York", "Orlando", "Las Vegas"],
    "checkIn": "2027-04-15",
    "checkOut": "2027-04-18",
    "adults": 2,
    "rooms": 1,
    "sortBy": "PRICE_LOW_TO_HIGH",
    "maxItemsPerSearch": 60,
    "scrapeReviews": False,
})

for hotel in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{hotel['rank']}. {hotel['name']} ({hotel['searchDestination']}) — ${hotel['priceNightly']}/night | Rating: {hotel['rating']}/10 ({hotel['reviewCount']} reviews)")
```

#### Calling via cURL (REST API)

```bash
curl -X POST "https://api.apify.com/v2/acts/haketa~expedia-scraper/runs?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "destinations": ["Miami", "Chicago"],
    "checkIn": "2027-05-01",
    "checkOut": "2027-05-03",
    "adults": 2,
    "maxItemsPerSearch": 50,
    "scrapeReviews": false
  }'
```

***

### 📚 Built-In Destinations & Sort Order Reference

#### Supported `sortBy` Modes

| `sortBy` Value | Expedia Ordering | Best Use Case |
| :--- | :--- | :--- |
| `"RECOMMENDED"` | Expedia default relevance & commercial rank | Auditing organic vs. sponsored (`isSponsored`) visibility and market share |
| `"PRICE_LOW_TO_HIGH"` | Lowest nightly price first | Discovering budget inventory and rate floors across a destination |
| `"PRICE_HIGH_TO_LOW"` | Highest nightly price first | Benchmarking luxury 5-star resorts and penthouse/suite pricing |
| `"REVIEW"` | Highest guest review score first | Identifying top-rated boutique and flagship competitors (`rating >= 9.0`) |
| `"DISTANCE"` | Closest to city center / landmark | Mapping downtown core hotel supply and pricing density |

#### Built-In Global Destinations (`destinations` dropdown)

| Region | Included Cities |
| :--- | :--- |
| **U.S. East & South** | `New York`, `Miami`, `Orlando`, `Washington, D.C.`, `Boston`, `Nashville`, `New Orleans`, `Austin` |
| **U.S. West & Midwest** | `Las Vegas`, `Los Angeles`, `Chicago`, `San Francisco`, `San Diego`, `Seattle`, `Honolulu` |
| **Europe** | `London`, `Paris`, `Rome`, `Barcelona`, `Amsterdam` |
| **Middle East, Asia & Americas** | `Dubai`, `Tokyo`, `Bangkok`, `Cancun`, `Toronto` |
| **Any Other City Worldwide** | Add any city, island, neighborhood, or airport code in `customDestinations` (e.g., `["Zurich", "Kyoto", "Tulum", "Sydney"]`) |

***

### 🔄 Automated Hospitality & Rate-Shopping Workflows

1. **Daily CompSet Rate Matrix:** Schedule the scraper to run every morning at 6:00 AM across your target cities and future check-in horizons (+7 days, +30 days, +60 days), piping `hotelId`, `name`, `priceNightly`, `dealBadge`, and `rank` into BigQuery, Snowflake, or Google Sheets.
2. **OTA Promotional & Sponsored Ad Monitoring:** Track which competitors are running `"Member Price"`, `"Save 20%"`, or paid sponsored placements (`isSponsored: true`) during high-demand conference or holiday dates.
3. **Guest Review Sentiment Pipeline:** Run weekly with `scrapeReviews: true` and `maxReviewsPerHotel: 20` on your target destination to feed recent guest complaints, `themes`, and `managerResponse` data into an LLM or BI dashboard.

***

### 💡 Pro tips for best results

- **Keep `scrapeReviews: false` for fast rate-shopping:** Price and rating summary metrics (`priceNightly`, `rating`, `reviewCount`, `dealBadge`) are already extracted from the search cards. Enable `scrapeReviews: true` only when you need full review text.
- **Minimize proxy transfer cost:** Non-essential images, fonts, media, and third-party ad trackers are automatically blocked during browser rendering so residential proxy bandwidth stays low and pages load faster.
- **Rate-shop multiple stay lengths:** Schedule separate tasks for 1-night weekday stays vs. 3-night weekend stays to capture length-of-stay (LOS) discount tiers.

***

### ⚠️ Honest limitations

- **Requires US Residential Proxy:** Expedia blocks standard datacenter IP addresses. The input pre-fills Apify's US Residential proxy group, and the crawler automatically rotates sessions if a residential IP hits a temporary rate limit.
- **Thumbnail `image` coverage:** Because image assets are blocked during rendering to reduce residential proxy cost and speed up page loads, `image` is populated only when the URL is already present in initial DOM attributes (~25%). All pricing, rating, location, and URL fields populate at ~98–100%.

***

### ❓ Frequently Asked Questions (FAQ)

**Do I get exact prices for my check-in and check-out dates?**
Yes. Both `priceNightly` and `allPrices` reflect the exact `checkIn`, `checkOut`, `adults`, and `rooms` parameters you specify.

**What happens if I leave `checkIn` / `checkOut` in the past on a scheduled run?**
The scraper automatically detects past dates and shifts them 30 days into the future (`2-night stay`) so recurring scheduled tasks never fail.

**How many hotels can I extract per run?**
A single city search typically yields **30 to 250+ hotels**, and multi-city or multi-sort runs scale cleanly to **1,000+ unique hotels**.

**Can I use custom Expedia search filters like 4-star+ or free breakfast?**
Yes. Apply any filters on `expedia.com` in your browser, copy the resulting `Hotel-Search?...` URL, and paste it into `startUrls`.

**How fast is the prefill run?**
With the default prefill (`destinations: ["New York"]`, `maxItemsPerSearch: 30`), the run typically completes in **35 to 60 seconds**.

***

### 🔗 Related Travel & Hospitality Scrapers

- [HRS Hotel & Reviews Scraper](https://apify.com/haketa/hrs-scraper) — Extract European & global hotel prices, ratings, and guest reviews from HRS.
- [Furnished Finder Scraper](https://apify.com/haketa/furnishedfinder-scraper) — Extract mid-term furnished rentals and landlord leads.
- [Eventbrite Scraper](https://apify.com/haketa/eventbrite-scraper) — Track major conferences and local events driving hotel demand surges.
- [Meetup Scraper](https://apify.com/haketa/meetup-scraper) — Extract destination events and group activity.

***

### 📋 Changelog

- **v1.2 (2026-11):** Unlocked **1,000+ hotel scaling & fast prefill** — added deep 120-step scroll pagination, automatic multi-sort expansion for high-volume single-city pulls, 25-city expanded default scaling, global `hotelId` deduplication, automatic past-date advancement, and a fast `30`-hotel prefill (`< 60s`).
- **v1.1 (2026-10):** Added optional verified guest reviews enrichment (`scrapeReviews` & `maxReviewsPerHotel`) with manager responses and sentiment themes.
- **v1.0 (2026-07):** Initial release of the Expedia Hotels Scraper.

# Changelog

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

# Actor input Schema

## `destinations` (type: `array`):

Pick one or more popular destinations to search hotels in. Leave everything empty to get a ready-made sample of hotels from top cities.

## `customDestinations` (type: `array`):

Search any city or place not in the list above — just type its name, e.g. 'Reykjavik', 'Bali', 'Cape Town'. One entry per line.

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

Check-in date in YYYY-MM-DD format. Leave empty to use Expedia's default upcoming dates.

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

Check-out date in YYYY-MM-DD format. Leave empty to use Expedia's default upcoming dates.

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

Number of adults per room.

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

Number of rooms.

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

How the hotel results should be ordered.

## `maxItemsPerSearch` (type: `integer`):

Cap how many hotels to collect per destination. 0 = all hotels on the results page.

## `scrapeReviews` (type: `boolean`):

Also fetch real guest review text (with score, date, author, themes and manager responses) for each hotel. Adds time per hotel.

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

How many recent guest reviews to fetch per hotel when 'Scrape guest reviews' is on.

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

Optional: paste Expedia Hotel-Search URLs with your own filters instead of using the destination picker above.

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

US residential proxy is strongly recommended for reliable results.

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

Parallel browser pages. Keep at 1 for the most reliable results and lowest cost; raise to scrape faster.

## Actor input object example

```json
{
  "destinations": [
    "New York"
  ],
  "customDestinations": [],
  "checkIn": "2027-03-15",
  "checkOut": "2027-03-17",
  "adults": 2,
  "rooms": 1,
  "sortBy": "RECOMMENDED",
  "maxItemsPerSearch": 30,
  "scrapeReviews": false,
  "maxReviewsPerHotel": 10,
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  },
  "maxConcurrency": 1
}
```

# Actor output Schema

## `hotelId` (type: `string`):

Expedia hotel ID

## `name` (type: `string`):

Hotel name

## `url` (type: `string`):

Hotel page URL

## `priceNightly` (type: `string`):

Nightly price

## `priceCurrency` (type: `string`):

Price currency

## `allPrices` (type: `string`):

All prices shown on the card

## `rating` (type: `string`):

Guest rating (out of 10)

## `ratingLabel` (type: `string`):

Rating word (e.g. Excellent)

## `reviewCount` (type: `string`):

Number of reviews

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

Location / neighborhood

## `dealBadge` (type: `string`):

Deal / promo badge

## `isSponsored` (type: `string`):

Sponsored (Ad) listing

## `image` (type: `string`):

Hotel image URL

## `searchDestination` (type: `string`):

Destination searched

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

Check-in date

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

Check-out date

## `scrapedAt` (type: `string`):

ISO timestamp

# 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 = {
    "destinations": [
        "New York"
    ],
    "customDestinations": [],
    "checkIn": "2027-03-15",
    "checkOut": "2027-03-17",
    "maxItemsPerSearch": 30,
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/expedia-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 = {
    "destinations": ["New York"],
    "customDestinations": [],
    "checkIn": "2027-03-15",
    "checkOut": "2027-03-17",
    "maxItemsPerSearch": 30,
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/expedia-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 '{
  "destinations": [
    "New York"
  ],
  "customDestinations": [],
  "checkIn": "2027-03-15",
  "checkOut": "2027-03-17",
  "maxItemsPerSearch": 30,
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call haketa/expedia-scraper --silent --output-dataset

```

## MCP server setup

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