Expedia Reviews Scraper avatar

Expedia Reviews Scraper

Pricing

from $3.00 / 1,000 result scrapeds

Go to Apify Store
Expedia Reviews Scraper

Expedia Reviews Scraper

Scrapes guest reviews from Expedia hotel/product pages. Extracts ratings, review text, stay info, management responses, photos, and hotel metadata (address, coordinates, star rating, rating distribution).

Pricing

from $3.00 / 1,000 result scrapeds

Rating

0.0

(0)

Developer

Reviewly

Reviewly

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Share

🏨 Expedia Reviews Scraper — Extract Hotel Reviews Without an API Key

Turn any Expedia hotel page into a clean dataset of guest reviews — scores, review text, stay details, traveller photos, and management responses — plus the hotel's full rating profile.

  • ⭐ Scrape every guest review of a property, newest-first, with full text and stay info
  • 🏨 Capture the hotel profile: address, coordinates, star rating, guest rating, rating distribution, category scores (cleanliness, location, staff…)
  • 🛡️ Anti-bot protection handled for you — a fast HTTP client with a real browser TLS fingerprint, with an automatic hardened-browser fallback and IP rotation when blocked
  • 📅 Incremental scraping with a date cutoff, perfect for daily or weekly review monitoring
  • 📦 Export to JSON, CSV, or Excel, or pull results straight into your app via the Apify API

Paste an Expedia hotel URL, press Start, get data.


📌 What This Actor Does

Give it one or more Expedia hotel/product page URLs — any slug form works, on any Expedia country site:

URL formExample
Long slughttps://www.expedia.co.uk/Kastoria-Hotels-Hotel-Anastassiou.h6136437.Hotel-Information
Short pathhttps://www.expedia.com/h17369936.Hotel-Information
Minimal slughttps://www.expedia.com/Hotel.h600217.Hotel-Information

The country site you use (expedia.com, expedia.co.uk, …) decides the language and currency of the responses. For every property the Actor returns one structured record combining the hotel profile and as many reviews as you ask for, pulled from Expedia's own internal GraphQL API — not from fragile HTML selectors.


⚙️ Input

FieldTypeDefaultDescription
startUrlsarrayExpedia hotel page URLs (objects with url, or plain strings).
maxReviewsinteger1000Max reviews per property. 0 = no limit.
reviewSortselectnewestnewest, relevant, highest, or lowest.
targetDatestringISO date cutoff — stop at reviews older than this (forces newest-first).
includeRatingsOnlyReviewsbooleantrueInclude reviews that carry only a score, no text.
proxyobjectProxy configuration. Residential recommended. (proxyConfiguration is accepted as an alias.)
{
"startUrls": [
{ "url": "https://www.expedia.co.uk/Kastoria-Hotels-Hotel-Anastassiou.h6136437.Hotel-Information" }
],
"maxReviews": 200,
"reviewSort": "newest",
"targetDate": "2024-01-01",
"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

📤 Output

One dataset record per property:

{
"propertyId": "6136437",
"name": "Hotel Anastassiou",
"description": "Morning coffee by Kastoria Lake sets the tone…",
"starRating": 2,
"rating": 8,
"superlative": "Very good",
"reviewCount": 70,
"ratingCounts": [
{ "rating": 10, "count": 21, "percent": 30, "description": "10 - Excellent" }
],
"categoryRatings": [
{ "label": "Cleanliness", "score": 8.4 },
{ "label": "Location", "score": 8.2 }
],
"address": {
"street": "1st km Highway Kastoria-Athens",
"city": "Kastoria",
"region": "Western Macedonia",
"postalCode": "52100",
"country": "GRC"
},
"coordinates": { "latitude": 40.498285, "longitude": 21.266815 },
"image": "https://images.trvl-media.com/lodging/…",
"priceRange": "from £40 - per night (includes taxes and fees)",
"petsAllowed": "Pets not allowed…",
"url": "https://www.expedia.co.uk/Kastoria-Hotels-Hotel-Anastassiou.h6136437.Hotel-Information",
"reviews": [
{
"reviewId": "65f2cdfd6167c03fb85cefe7",
"rating": 10,
"ratingOutOf": 10,
"superlative": "Excellent",
"title": "Love this town!!",
"text": "Nice hotel. Nice room. Nice people!!…",
"locale": "en_US",
"date": "2024-03-14",
"dateText": "14 Mar 2024",
"verified": true,
"stayInfo": "Stayed 1 night in Mar 2024",
"themes": ["Liked: Cleanliness, staff & service…"],
"helpfulCount": 0,
"reviewer": "Jaymi",
"travelers": [],
"photos": ["https://a.travel-assets.com/ugc/hotel-reviews/…"],
"managementResponses": [
{ "header": "Response from Anastassiou hotel on 8 Apr 2025", "date": "2025-04-08", "text": "Thank you…" }
]
}
]
}

Reviews are null-dated (with dateText kept) only when the site locale renders dates in a non-English format.


🧠 How It Works

  1. Fast path (default): an HTTP client with a genuine Firefox TLS/HTTP2 fingerprint (impit) fetches the hotel page, earns Expedia's Akamai Bot Manager cookies, and parses the hotel profile from the page's schema.org microdata and server-rendered state.
  2. Reviews via GraphQL: the Actor then pages through Expedia's internal PropertyReviewsQuery API (25 reviews per request) on the same session, absorbing rotated cookies on every response.
  3. Fallback on hard blocks: if an IP is challenged, a fingerprint-hardened Firefox (Camoufox) solves the check (DataDome interstitial reload loop included), and impit replays the browser's own identity — same proxy session, same Firefox shape, no client hints.
  4. IP rotation: each start URL gets up to 8 fresh proxy sessions before giving up; a working session is reused across properties.
  5. When a fallback attempt fails to clear, a debug screenshot + challenge iframe details are stored in the run's key-value store so failures are self-diagnosing.

Maintenance notes

  • The reviews API uses a persisted query hash (REVIEWS_QUERY_HASH in src/scraper.js). If Expedia bumps its client, requests return PersistedQueryNotFound — recapture the hash from the browser DevTools Network tab (filter graphql, operation PropertyReviewsQuery, copy extensions.persistedQuery.sha256Hash).
  • The GraphQL gateway requires a client-info header (CLIENT_INFO in src/scraper.js); any recent value captured the same way works.

🖥️ Running Locally

pnpm install
# optional, only needed for the browser fallback:
npx camoufox-js fetch
# input lives in storage/key_value_stores/default/INPUT.json
pnpm start

Set the Apify run timeout to ≥ 900 s — a run that needs several browser solves can take a while.