Expedia Hotels Scraper at a glance
Expedia Hotels Scraper is a ready-to-run Apify actor from abotapi for collecting travel data. Its documented output includes property, stars, rating, rating label and total reviews, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $1.70 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify.
- Runs on
- Apify cloud: console, API, schedules and integrations
- Data type
- Travel, Developer Tools, Automation
- Pricing
- $1.70 per 1,000 results (Free plan), from $1.00 on paid plans
- Output
- Documented below · JSON, CSV, Excel
- Inputs
- 48 options
From $1/1K. Scrape Expedia.com hotel listings and reviews for any destination. Extract prices, ratings, review text, photos, location details, hotel information, and more in clean, structured data.
What Expedia Hotels Scraper can do
- Two ways in. Search by a plain destination name, or paste any Expedia link: hotel pages (any Expedia country site or the mobile host), share links from the Expedia app (expe.onelink.me and similar, resolved automatically), search result pages and destination guide pages, or just a bare property id.
- Two outputs from the same input. Aggregate hotel cards by default, or turn on Scrape reviews only for individual review records, one row per review.
- Every filter guests use. Check in and check out dates, adults, rooms, children with ages, minimum and maximum nightly price, star rating, guest rating, amenities, property type, cancellation/payment options, meal plan, traveler experience, accessibility, neighbourhood, brand and property name, typed as run input or read straight out of a pasted Expedia search URL. Turn on Include property details (address, coordinates, amenities, policies, fees, nearby places) or Include rooms and rates (per-room rate plans, cancellation terms, meal plan, pay-later, scarcity) for a deeper crawl.
- Review depth on demand. Cap reviews per hotel (default 20, down from an earlier default of 25, the same fleet-standard cap used across other review-capable actors), embed a sample of reviews inside each hotel card, or pull every review as its own record with sentiment, stay details, helpful-vote counts, verified/translated flags and management replies. Filter and sort reviews by date, rating, and relevance/newest/highest/lowest.
- 30 locales and 36 currencies. Cards and reviews come back in the guest's own language and currency.
- Built for schedules. Incremental mode returns only new, updated and reappeared hotels on repeat runs against the same search or URLs, and a blocked run fails loudly instead of quietly returning an empty dataset.
Choose what to collect
These inputs let you configure Expedia Hotels Scraper - Prices, Ratings & Reviews. Open the actor on Apify to enter your values and review the current options.
| Input | What it controls |
|---|---|
checkInstring · required | Required. Pick a date, or type a relative value such as 1 day (tomorrow) or 7 days. |
checkOutstring · required | Required. Pick a date, or type a relative value such as 2 days (day after tomorrow). |
modestring | Search mode runs a destination query and paginates results. URL mode fetches hotels by property or search URL. |
destinationstring | Search mode only. Type a place name the way you would on the site, for example Paris, New York or Tokyo; the Actor looks it up itself. A bare Expedia region id (for example 2734) or the older "2734|Paris" form also works. |
destinationIdstring | Optional. You usually don't need this -- the Actor resolves the Destination text above on its own (Expedia's own lookup first, a geocoder fallback second). Set this only if you already know the numeric region ID from an Expedia URL (for example 2734 for Paris, 178293 for New York; it is the number after .d in any Expedia URL) and want to skip resolution entirely. |
startUrlsarray | URL mode only. Paste any Expedia link: a hotel page (…h891081.Hotel-Information, also on a localized site such as expedia.co.uk or the mobile m.expedia.com host), a share link (expe.onelink.me / expe.app.link), a Hotel-Search results page (its dates, guests, sort and filters are used), or a destination guide page (…d612707.Travel-Guide-Hotels). A bare property id such as 891081 also works. Hotel cards are priced for the Check in / Check out inputs (a hotel link's own dates are reported in the log, not used); a Hotel-Search link's own dates are used unless they are in the past. See the README for the full URL-shape table. |
adultsinteger | Number of adult guests. Affects pricing and availability in the results. |
Show 41 more inputs
| Input | What it controls |
|---|---|
childrenarray | Add one entry per child and type the age in years (0 to 17). Two kids age 5 and 10? Add 5 and 10. Two 5 year olds? Add 5 twice. |
roomsinteger | Number of rooms to book. Each room uses the same adult and children configuration. |
minPriceinteger | Minimum nightly price (the nightly price each hotel card shows, in the selected currency). Hotels without a price for your dates are skipped while a price filter is set. Leave empty for no minimum. |
maxPriceinteger | Maximum nightly price (the nightly price each hotel card shows, in the selected currency). Hotels without a price for your dates are skipped while a price filter is set. Leave empty for no maximum. |
starRatingsarray | Filter by star rating. Select one or more. Leave empty to include all star ratings. |
minGuestRatingstring | Only return properties rated at least this well by guests. Leave empty for any rating. |
amenitiesarray | Only return properties that have ALL of the selected amenities. Leave empty for no amenity filter. |
propertyTypesarray | Only return properties of ANY of these kinds (hotel, hostel, apartment and so on). Leave empty for all types. |
paymentOptionsarray | Only return properties offering the selected booking terms. |
mealPlansarray | Only return properties offering the selected meal plans. |
travelerExperiencearray | Only return properties tagged for ALL of the selected kinds of trip. |
accessibilityFeaturesarray | Only return properties with the selected accessibility features. |
neighborhoodIdsarray | Limit results to these neighborhoods. Use the number after neighborhood= in an Expedia search link after you pick a neighborhood filter on the site (for example 178676 is Montmartre in Paris). Pasting that whole search link into Start URLs applies it too. |
brandIdsarray | Limit results to ANY of these hotel brands. Use the number after hotel_brand= in an Expedia search link after you pick a brand filter on the site (for example 2141 is ibis). Pasting that whole search link into Start URLs applies it too. |
propertyNamestring | Only hotels whose name matches this text, e.g. Marriott or Ibis (the site's own Search by property name filter). Search mode, and pasted Hotel-Search links (their hotelName parameter). |
sortBystring | Order in which hotels are returned. |
includePropertyDetailsboolean | Search mode only: also fetch each hotel's address, map coordinates, full amenity list, policies, fees and what's nearby (one extra request per hotel). URL mode always includes these for hotel links. |
maxPropertyImagesinteger | Keep at most this many photo links per hotel. Leave empty to keep all. |
reviewsOnlyboolean | When enabled, the output is individual review records (one row per review) instead of hotel cards. Works in both Search and URL input types. |
includeReviewsboolean | When enabled, each hotel card gets up to Max Reviews per Hotel reviews embedded under extra.reviews. Ignored if Scrape reviews only is on. |
maxReviewsPerHotelinteger | Cap on reviews embedded in each hotel card (default 20). Only applies when Include reviews in hotel cards is on. Ignored in Scrape reviews only mode (Max Items caps the overall total there, and each review row is billed as a normal result). |
reviewsFromstring | YYYY-MM-DD. Only keep reviews on or after this date. Speeds up runs when you only need recent reviews. |
reviewSortstring | Order in which reviews are collected. Leave empty for the site's default (most relevant). When a review date range is set, empty means newest first. |
reviewsTostring | YYYY-MM-DD. Only keep reviews on or before this date. |
minReviewRatinginteger | Only keep reviews rated at least this (1 to 10). |
maxReviewRatinginteger | Only keep reviews rated at most this (1 to 10). Combine with Lowest rated first to collect complaints quickly. |
includeReviewPhotosboolean | Keep links to guest photos on each review. |
includeOwnerResponsesboolean | Keep the hotel's reply to each review (reviews only mode). |
includeCategoryRatingsboolean | Attach hotel level aggregate ratings (cleanliness, staff, location, and similar categories) to each review record. |
currencystring | Currency requested for prices. Expedia.com quotes its own prices in US dollars whatever is selected here, so check extra.priceCurrency on each hotel for the currency the prices are actually in. |
localestring | Language and region for content on hotel cards and for review language. |
maxItemsinteger | Hard cap on the total number of records saved to the dataset across all pages and hotels. |
resumeFromRunIdstring | Paste a previous run ID or dataset ID to continue a large crawl of hotels without returning or charging for hotels already collected there. Use this after an interrupted run, or when continuing a destination pull in another run. For recurring daily monitoring of the same search or URLs, use Incremental mode below instead. |
incrementalModeboolean | Turn this on for daily or recurring monitoring of the same destination search or hotel/search URLs. The first run returns all matching hotels as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED hotels. Turn on "Emit unchanged" or "Emit expired" only when you also want those hotels returned (and billed). Hotels are compared on their listing content (name, ratings, review count, price and totals, rooms, amenities, policies, address, deals); the photo set (extra.images, extra.gallery) is never compared because the site rotates it, and by default these are also left out of change detection but still returned: extra.checkIn and extra.checkOut (they roll forward daily when Check-in/Check-out are left empty), availability scarcity messages, sponsored flag, search rank, price messages, map image and search URL. Add more in Ignore fields when detecting changes below. State is kept separately for each mode/destination/URL/filter setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above. |
stateKeystring | Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the destination/URLs and filters. Different searches then never mix state with each other. |
emitUnchangedboolean | Off by default. Turn on to also return hotels that have not changed since the last run, marked UNCHANGED. This returns and bills extra rows you already have, so leave it off unless you specifically want the full snapshot every run. |
emitExpiredboolean | Off by default. Turn on to also return hotels that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search/URLs, not when Max Items capped it or when Resume was used. This returns and bills extra synthetic rows, so leave it off unless you need expiry tracking. |
ignoreFieldsForChangesarray | Output field names (or extra. nested paths) that should NOT make a hotel count as UPDATED. Always ignored by default: extra.checkIn and extra.checkOut (left empty, Check-in/Check-out default to "tomorrow"/"the day after", which rolls forward every day on a scheduled run), the site's scarcity text (extra.availabilityMessage), ad placement (extra.sponsored), the card's search rank (extra.searchRank), the price block's text lines that carry the dates (extra.priceMessages), the card's highlighted amenities and booking-terms text (extra.highlightedAmenities, extra.offerMessages), the map link (extra.staticMapImage) and your own customData. Add fields such as hotelTotalReviews or extra.priceFormatted here if changes to them are not relevant to your monitoring. Ignored fields are still returned in the output, only change detection skips them. |
mcpConnectorsarray | Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify > Settings > Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON; the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com). |
notionParentPageUrlstring | URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors. |
maxNotifyListingsinteger | Cap on items written to each connector per run. Does not affect the dataset. |
Fields in the output
The documented dataset includes the fields below. Availability can depend on the source page and selected mode.
placeNameProperty (text)extra.starRatingStars (number)hotelOverallRatingRating (number)hotelRatingLabelRating label (text)hotelTotalReviewsTotal Reviews (number)extra.priceFromNightly price (number)extra.totalPriceStay total (number)extra.priceCurrencyCurrency (text)extra.neighborhoodArea (text)extra.freeCancellationFree cancellation (boolean)extra.dealBadgeDeal (text)extra.checkInCheck-in (text)Show 37 more fields
extra.checkOutCheck-out (text)reviewRatingReview Rating (number)reviewTextReview (text)hotelUrlURL (link)hotelIdProperty ID (text)extra.addressAddress (text)extra.latitudeLatitude (number)extra.longitudeLongitude (number)extra.vacationRentalVacation rental (boolean)extra.amenityGroupsAmenities (array)extra.highlightsHighlights (array)extra.policiesPolicies (array)extra.importantInformationFees and rules (array)extra.nearbyPlacesNearby (array)extra.locationDescriptionAbout the area (text)extra.faqsFAQs (array)extra.vipAccessVIP Access (boolean)extra.staticMapImageMap (image)extra.adultsAdults (number)extra.roomsRooms and rates (array)reviewRatingLabelLabel (text)reviewTitleTitle (text)reviewDateDate (text)authorNameGuest (text)stayDurationStay (text)sentimentLiked / disliked (object)helpfulVoteCountHelpful votes (number)verifiedVerified (boolean)reviewLocaleReview locale (text)hotelResponseHotel reply (text)hotelCategoryRatingsCategory ratings (object)extra.reviewsEmbedded reviews (array)reviewIdReview ID (text)changeTypeChange (text)changedFieldsChanged fields (array)firstSeenAtFirst seen (date)lastSeenAtLast seen (date)Example output
An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.
{
"mode": "search",
"placeName": "Hotel Example Paris",
"hotelId": "11111",
"hotelUrl": "https://www.expedia.com/Example-City-Hotels-Sample-Hotel.h11111.Hotel-Information",
"hotelOverallRating": 9.2,
"hotelRatingLabel": "Wonderful",
"hotelTotalReviews": 1843,
"provider": "expedia",
"scrapedAt": "2026-04-18T07:30:00.000Z",
"extra": {
"searchDestination": "Paris",
"starRating": 5,
"description": "Recently renovated boutique hotel steps from the city center",
"priceFrom": 420,
"priceFormatted": "$420 nightly",
"priceStrikeout": "$600",
"currency": "USD",
"images": [
"https://images.example.com/lodging/sample-1.jpg",
"https://images.example.com/lodging/sample-2.jpg"
],
"checkIn": "2026-11-10",
"checkOut": "2026-11-13",
"adults": 2,
"childrenAges": [],
"vacationRental": false,
"searchRank": 1,
"regionId": "2734",
"badges": [
"VIP Access",
"$58 off"
],
"priceMessages": [
"$420 nightly",
"Total with taxes and fees",
"for 3 nights",
"Nov 10 - Nov 13"
]
}
}Ways to use this data
- Rate and price monitoring: track nightly prices, discounts and availability for a set of properties across a date range.
- Reputation and sentiment analysis: pull every review for a property to find recurring compliments, complaints and how management responds.
- Scheduled market watching: run the same destination or property list on a schedule with incremental mode and only pay for what changed.
- Travel content and comparison sites: build destination guides with hotel photos, star ratings and pricing pulled straight from search results.
- Competitive benchmarking: compare star rating, guest rating and price band for a shortlist of properties in one destination.
Before you run
Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.
Questions about this actor
What data does Expedia Hotels Scraper return?
The documented output for Expedia Hotels Scraper includes property, stars, rating, rating label, total reviews, nightly price, stay total and currency. Availability of each field depends on the source page and the selected mode.
How much does Expedia Hotels Scraper cost?
It costs $1.70 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.
What is the difference between Resume and Incremental mode?
They solve different problems and are the actor's most common point of confusion. Resume (resumeFromRunId) continues one specific interrupted run so it doesn't restart from scratch. Incremental mode is for running the same destination search or hotel/search URLs again and again, for example daily, and getting back only the hotels that are new, changed, or gone since the last run.
Can I get only new or changed hotels on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Repeat runs then return only new, updated and reappeared hotels, and unchanged ones are not billed unless you turn on Emit unchanged.
Why did my run return fewer hotels than expected?
Price, star rating and destination filters narrow the result set, and Max items caps the total regardless of filters. A search with no matching hotels for the chosen dates and filters also returns fewer records without failing the run. A destination name that can't be resolved at all fails the run loudly instead (see below); it never silently returns fewer rows.
Why did my run fail instead of returning an empty dataset?
The run fails loudly, with a clear status message, in three cases instead of silently returning an empty dataset: Expedia blocks every single request even after retrying with a different session; Resume points at a run or dataset that can't be read (or clashes with existing incremental state for the same search); or the Destination text can't be resolved by either Expedia's own lookup or the geocoder fallback (try a more specific name, or set Destination ID directly). A search with genuinely zero matching hotels for the chosen dates/filters still succeeds with zero records; that is a real "no results," not a resolution failure.
