Google Hotels Scraper - Multi-Query OTA Price Comparison avatar

Google Hotels Scraper - Multi-Query OTA Price Comparison

Pricing

from $22.50 / 1,000 hotel results

Go to Apify Store
Google Hotels Scraper - Multi-Query OTA Price Comparison

Google Hotels Scraper - Multi-Query OTA Price Comparison

Search multiple hotel queries at once and compare prices across 30+ OTAs. Collect 5 data sections per hotel — Overview, Prices, Reviews, Photos, About — all from Google Hotels.

Pricing

from $22.50 / 1,000 hotel results

Rating

0.0

(0)

Developer

jy-labs

jy-labs

Maintained by Community

Actor stats

1

Bookmarked

106

Total users

13

Monthly active users

a day ago

Last modified

Share

Google Hotels Multi-Query Scraper & Price Comparison

Search multiple hotel queries at once and compare prices across 30+ Online Travel Agencies (OTAs). Collect 5 rich data sections per hotel — Overview, Prices, Reviews, Photos, and About — all from Google Hotels in a single run.


What does Google Hotels Multi-Query Scraper do?

Google Hotels Multi-Query Scraper uses Google Hotels as a meta-search layer to aggregate live pricing data from every major OTA simultaneously. Run multiple search queries (e.g., "hotels in New York", "hotels in Tokyo") in a single Actor run. Instead of visiting Booking.com, Hotels.com, Expedia, and Agoda separately, this Actor queries Google Hotels and extracts the full OTA comparison table plus 5 detailed data sections from each hotel's detail page.

The Actor is built on Crawlee's PlaywrightCrawler with a hybrid data extraction strategy: API interception for structured search data combined with DOM scraping for detail page content. This approach maximizes both data reliability and extraction completeness.

Each hotel result includes:

  • OTA price comparison — up to 30+ providers with individual prices, direct booking URLs, and cancellation policies
  • Overview — hotel description, address, phone number, highlights, and nearby places
  • Guest reviews — individual review text with rating, author, and date; plus aggregated third-party ratings from Tripadvisor, Priceline, Trip.com, and Hotels.com
  • Hotel photos — full photo gallery URLs
  • About / Amenities — check-in/out times and full amenities organized by category

Use Cases

1. Travel Price Comparison Platforms Aggregate live OTA prices across multiple cities or hotel chains, then surface the cheapest booking option to end users — without building direct integrations with each OTA.

2. Revenue Management and Rate Parity Monitoring Track competitor hotel prices across OTAs in real time. Detect rate parity violations and identify when specific OTAs undercut your contracted rates.

3. Automated Deal Alert Systems Schedule daily runs for target hotels. Trigger notifications when prices drop below a defined threshold using Apify webhooks combined with the maxPrice filter.

4. Travel Data Research and Analytics Build datasets covering price distributions, seasonal trends, and OTA markup patterns. Supports 22 countries and 22 currencies for global market coverage.

5. Hotel Booking Aggregators Power a meta-search engine or hotel booking widget with structured pricing and availability data across all major OTAs for any destination.

6. Business Travel Management Extract hotel options within rating and price constraints for a given city. Use minRating and maxPrice filters to enforce corporate travel policy compliance automatically.


Key Features

FeatureDetails
Multi-OTA price comparison30+ providers per hotel including Booking.com, Hotels.com, Agoda, Expedia, Trip.com, Klook, Vio.com, eDreams, and more
5 data sectionsOverview and Prices always included; optionally add Reviews, Photos, About
Smart currency detectionAutomatic detection from currency symbols; 22 currencies supported
22 countriesUS, UK, Singapore, Japan, South Korea, Germany, France, Australia, Canada, India, Thailand, Brazil, Italy, Spain, Netherlands, UAE, Hong Kong, Taiwan, Malaysia, Indonesia, Philippines, Vietnam
Flexible sortingSort output by price (low/high), rating, review count, or hotel name
FilteringFilter results by minimum Google rating and maximum price per night
ScaleUp to 100 hotels per query, 5 queries per run
Anti-detectionBrowser fingerprinting with a Chrome/Windows profile, automatic proxy selection, and resource blocking
Hybrid extractionAPI interception for reliable structured data + DOM scraping for detail content

How to Use

Step 1 - Set your search queries

Enter one or more natural-language queries in the Search Queries field. Examples:

  • hotels in New York
  • hotels in Tokyo Shibuya
  • luxury hotels Singapore Marina Bay
  • budget hotels Paris near Eiffel Tower

You can run up to 5 queries per run, each returning up to 100 hotels.

Step 2 - Set your travel dates

Enter Check-in Date and Check-out Date in YYYY-MM-DD format. If left empty, the Actor defaults to tomorrow and the following day.

Step 3 - Configure guests and locale

Set Number of Adults (1-10), Country (affects which OTAs appear and local pricing), and Currency (the currency for all displayed prices).

Step 4 - Choose data sections

The Actor always collects Overview and Prices (OTA comparison table) — these cannot be deselected. Optionally add:

  • Guest Reviews — individual guest reviews plus third-party aggregated ratings
  • Hotel Photos — full photo gallery
  • About / Amenities — check-in times, check-out times, and categorized amenities

More sections increase run time but provide richer data.

Step 5 - Apply filters and sorting

Use Minimum Rating (0-5) and Maximum Price Per Night to narrow results. Set both to 0 (default) to disable filtering. Choose a sort order for the output dataset.

Step 6 - Run and export

Click Save & Run. Results appear in the Dataset tab as structured JSON records. Export to JSON, CSV, Excel, or XML. Connect to downstream systems via the Apify API.


Input Parameters

ParameterTypeDefaultDescription
queriesstring[]requiredHotel search queries (max 5). E.g., ["hotels in New York"]
checkInstringtomorrowCheck-in date in YYYY-MM-DD format
checkOutstringday after tomorrowCheck-out date in YYYY-MM-DD format
adultsinteger2Number of adult guests (1-10)
countrystring"us"Country code for localized results (22 options)
currencystring"USD"Currency code for displayed prices (22 options)
maxResultsinteger20Maximum hotels per query (1-100)
scrapeOtaPricesbooleantrueVisit each hotel's detail page to collect OTA prices, reviews, photos, and about data
dataSectionsstring[]["overview", "prices"]Data sections to collect: overview, prices, reviews, photos, about
sortBystring"price_low"Sort order: price_low, price_high, rating, reviews, name
minRatingnumber0Minimum Google rating filter — set to 0 to disable
maxPriceinteger0Maximum nightly price filter — set to 0 to disable
proxyobjectchosen automaticallyHTTP proxy configuration. Left alone, the Actor picks the cheap datacenter pool for US dollar searches and Residential for every other locale — see Proxy selection
requestHandlerTimeoutSecsinteger600Maximum seconds allowed per request (120-1800)

Supported Countries

us, gb, sg, jp, kr, de, fr, au, ca, in, th, br, it, es, nl, ae, hk, tw, my, id, ph, vn

Supported Currencies

USD, EUR, GBP, JPY, KRW, SGD, AUD, CAD, INR, THB, BRL, TWD, MYR, IDR, PHP, VND, AED, HKD, CHF, SEK, NOK, DKK

Data Sections

ValueAlways IncludedDescription
overviewYes (cannot be removed)Hotel description, address, phone number, highlights, and nearby places
pricesYes (cannot be removed)Full OTA price comparison table (30+ providers, booking URLs, cancellation policies)
reviewsNoIndividual guest reviews, star rating breakdown, and third-party review site ratings
photosNoHotel photo gallery URLs
aboutNoFull hotel description, check-in/out times, address, and amenities by category

Proxy selection

Leave proxy unset and the Actor chooses for you:

Search localePool usedWhy
country: us, currency: USDdatacenterSame 20 hotels, same complete OTA prices, measured 13x cheaper and 40% faster
Anything elseresidentialGoogle quotes OTA prices in the exit IP's currency, so the exit has to be in-country

Google Hotels does not block datacenter IPs — that is a common assumption and it is wrong here. The real constraint is currency: run a KRW search through a US exit and Google prices everything in USD, which the Actor detects and rejects rather than handing you mislabelled prices.

Override proxy only if you are being blocked; an explicit apifyProxyGroups is always respected.


Output

Each hotel is saved as a single JSON object in the dataset. Optional fields are present only when the corresponding dataSections entry is selected.

Base Fields (always present)

FieldTypeDescription
querystringThe search query that returned this hotel
hotelNamestringHotel name
addressstring | nullHotel address or location description
ratingnumber | nullGoogle rating score (e.g., 4.2)
reviewCountinteger | nullTotal number of reviews
starRatinginteger | nullHotel star classification (2-5)
lowestPricenumber | nullLowest nightly price found across all OTAs
currencystringCurrency code for all prices
pricesOtaPrice[]OTA price comparison array
amenitiesstring[]Hotel amenities list
imageUrlstring | nullHotel thumbnail image URL
latitudenumber | nullLatitude coordinate (from API intercept)
longitudenumber | nullLongitude coordinate (from API intercept)
checkInstringCheck-in date in YYYY-MM-DD format
checkOutstringCheck-out date in YYYY-MM-DD format
adultsintegerNumber of adult guests
dealTextstring | nullSpecial deal text (e.g., "25% less than usual")
urlstringGoogle Hotels URL for this hotel
scrapedAtstringISO 8601 timestamp of when data was scraped

Price-monitoring fields (always present)

These exist so you can diff one run against the next without inventing your own keys.

FieldTypeDescription
queryIndexintegerWhich entry of queries produced this row
snapshotDatestringYYYY-MM-DD the run was taken, for grouping daily snapshots
hotelIdstringStable identity for the property across runs, derived from Google's entity ID
dedupeKeystringIdentity of the property within one snapshot
priceKeystringIdentity of hotel + dates + occupancy + currency. Two rows with the same priceKey on different snapshotDates are the same offer at two points in time — diff these
priceContextStatus"validated" | "unpriced" | "mismatch"validated means the price was read in the currency you asked for. unpriced means no price was shown. mismatch means the page quoted a different currency and the row was not charged
otaPriceStatus"complete" | "missing"missing means you asked for OTA prices and none were found; those rows are delivered but not charged

Rows that fail the price-context check are not billed to you, and the run log names them.

OTA Price Object (prices[])

FieldTypeDescription
providerstringOTA provider name (e.g., "Booking.com")
pricenumberNightly price from this provider
currencystringCurrency code
bookingUrlstringDirect link to book at this provider
cancellationstring | nullCancellation policy (e.g., "Free cancellation")
featuresstring[]Additional features (e.g., "Breakfast included")

Optional Nested Objects

overview (when overview section selected)

FieldTypeDescription
descriptionstring | nullHotel description and highlights summary
addressstring | nullHotel address
phonestring | nullHotel phone number
highlightsstring[]Key highlights and features
nearbyPlacesstring[]Nearby points of interest

reviews (when reviews section selected)

FieldTypeDescription
overallRatingnumber | nullOverall review score
totalReviewsstring | nullTotal review count text
ratingBreakdownobjectStar rating distribution (1-5 stars)
reviewsReviewItem[]Individual guest reviews (text, rating, date, author)
thirdPartyReviewsThirdPartyReview[]Aggregated ratings from Tripadvisor, Priceline, etc.

photos (when photos section selected)

FieldTypeDescription
photosstring[]Array of hotel photo URLs

about (when about section selected)

FieldTypeDescription
descriptionstring | nullFull hotel description
checkInTimestring | nullCheck-in time (e.g., "3:00 PM")
checkOutTimestring | nullCheck-out time (e.g., "12:00 PM")
addressstring | nullHotel address
amenitiesByCategoryobjectAmenities organized by category name

Sample Output

The following data is from an actual test run searching "hotels in New York" with all 5 data sections enabled.

The Manhattan at Times Square Hotel

{
"query": "hotels in New York",
"hotelName": "The Manhattan at Times Square Hotel",
"address": "790 7th Ave, New York, NY 10019",
"rating": 4.2,
"reviewCount": 8547,
"starRating": 4,
"lowestPrice": 259,
"currency": "USD",
"prices": [
{
"provider": "Vio.com",
"price": 259,
"currency": "USD",
"bookingUrl": "https://...",
"cancellation": "Free cancellation",
"features": []
},
{
"provider": "Booking.com",
"price": 271,
"currency": "USD",
"bookingUrl": "https://...",
"cancellation": "Free cancellation",
"features": []
},
{
"provider": "Hotels.com",
"price": 285,
"currency": "USD",
"bookingUrl": "https://...",
"cancellation": "Free cancellation",
"features": []
},
{
"provider": "eDreams",
"price": 377,
"currency": "USD",
"bookingUrl": "https://...",
"cancellation": null,
"features": []
}
],
"amenities": ["Free Wi-Fi", "Parking ($)", "Air conditioning", "Pet-friendly", "Fitness center", "Restaurant"],
"checkIn": "2025-12-01",
"checkOut": "2025-12-02",
"adults": 2,
"dealText": null,
"scrapedAt": "2025-12-01T09:15:22.000Z",
"overview": {
"description": "Located in the heart of Midtown Manhattan, steps from Times Square...",
"address": "790 7th Ave, New York, NY 10019",
"phone": "+1 212-581-3300",
"highlights": ["Prime Times Square location", "Recently renovated rooms"],
"nearbyPlaces": ["Times Square (0.1 mi)", "Central Park (1.2 mi)", "Empire State Building (0.8 mi)"]
},
"reviews": {
"overallRating": 4.2,
"totalReviews": "8,547",
"ratingBreakdown": { "5": 3200, "4": 2800, "3": 1500, "2": 700, "1": 347 },
"reviews": [
{
"text": "Great location, clean rooms, friendly staff. Would stay again.",
"rating": 5,
"date": "2025-07-15",
"author": "John D."
}
],
"thirdPartyReviews": [
{ "siteName": "Tripadvisor", "rating": "4.0", "reviewCount": "4,200" },
{ "siteName": "Priceline", "rating": "8.2", "reviewCount": "1,100" },
{ "siteName": "Trip.com", "rating": "4.1", "reviewCount": "980" },
{ "siteName": "Hotels.com", "rating": "8.4", "reviewCount": "2,300" }
]
},
"photos": {
"photos": ["https://lh5.googleusercontent.com/p/AF1QipN...", "https://lh5.googleusercontent.com/p/AF1QipN..."]
},
"about": {
"checkInTime": "4:00 PM",
"checkOutTime": "12:00 PM",
"address": "790 7th Ave, New York, NY 10019",
"amenitiesByCategory": {
"Connectivity": ["Free Wi-Fi", "Business center"],
"Dining": ["Restaurant", "Bar/Lounge", "Room service"],
"Fitness": ["Fitness center"],
"Policies": ["Pet-friendly", "Parking ($)", "Air conditioning"]
}
}
}

26 unique OTA providers found — prices ranged from $259 (Vio.com) to $377 (eDreams). 10 guest reviews + 4 third-party rating sources (Tripadvisor, Priceline, Trip.com, Hotels.com). 277 hotel photos collected.

Pod 51

  • 19 unique OTA providers
  • 10 guest reviews + 3 third-party rating sources
  • 214 hotel photos

DoubleTree by Hilton Hotel New York Times Square West

  • 27 unique OTA providers
  • Check-in: 3:00 PM / Check-out: 11:00 AM
  • 10 guest reviews + 3 third-party rating sources
  • 218 hotel photos

How Much Will It Cost?

This Actor uses Pay-Per-Event (PPE) pricing, plus Apify platform usage.

EventPriceDescription
hotel-result$0.025 per hotelCharged once per hotel result pushed to the dataset
Actor start$0.00005 per runNominal
Platform usagemetered by ApifyCompute and proxy transfer, billed on your Apify account

You are charged the hotel event only for hotels actually extracted and delivered to your dataset. Queries that return zero results produce no hotel events.

Platform usage, stated plainly

Google Hotels is a heavy single-page application: roughly 17 MB of Google's own JavaScript and data has to load before any price exists to read, and no blocking rule can avoid it. That transfer is billed to your Apify account on top of the event price above, so it is worth knowing before you schedule a large run.

The size of it depends on the proxy pool your locale needs:

Search localeProxyMeasured platform usage
US / USDdatacenterabout $0.003 per hotel
Any other country or currencyresidentialabout $0.025 per hotel

US searches used to cost the same as the rest; moving them to the datacenter pool cut their platform usage by roughly 92%.

Cost Examples

Event charges, with typical platform usage in brackets:

ScenarioHotelsUS / USDOther locales
Single city, 20 hotels20$0.50 (+ ~$0.06)$0.50 (+ ~$0.50)
3-city comparison, 20 hotels each60$1.50 (+ ~$0.18)$1.50 (+ ~$1.50)
Full 5-query run, 50 hotels each250$6.25 (+ ~$0.75)$6.25 (+ ~$6.25)
Daily monitoring, 5 cities × 10 hotels50 per day$1.25 (+ ~$0.15)$1.25 (+ ~$1.25)

Platform usage varies with how long Google takes to respond, so treat those as typical rather than fixed. The run detail page in Apify Console is the source of truth.

Value Comparison

Each hotel result includes cross-OTA price comparison from 30+ providers — data that would otherwise mean scraping each OTA separately. One run replaces a set of per-OTA scrapers and the reconciliation work between them.


Performance

TaskApproximate Time
Search extraction for 20 hotels5-8 seconds per query
Per hotel — Overview + Prices only5-10 seconds
Per hotel — all 5 sections10-20 seconds
3 hotels with all sectionsapproximately 2 minutes
20 hotels with all sectionsapproximately 3-4 minutes

What counts as a failed run

A run that returns nothing is not automatically a failure, and the Actor does not pretend otherwise.

  • A search with no matching hotels finishes successfully. It is recorded as empty and exits 0. Searching a location with no availability on your dates is a legitimate answer, not a fault.
  • A search page that never renders is retried on a fresh proxy exit IP before the query is given up on. This is the failure most likely to clear on a second attempt, so it gets one.
  • Partial results are delivered, not discarded. If the run reaches its time budget partway through the detail pages, everything collected so far is pushed and the reason is named in SUMMARY.
  • A run is only marked failed when every query failed, or when the currency gate rejected every row (see priceContextStatus) — which means the results were quoted in the wrong currency and nothing billable survived.

Every run writes a SUMMARY record to the key-value store with per-query status, counts and reasons, so you can tell these apart programmatically instead of guessing from an exit code.

A failed run charges no hotel-result events — you are only billed for hotels actually delivered. Apify platform usage still accrues for the time the run was working, and a retried query pays for both attempts, so a run that fails is cheap but not free.


Tips and Best Practices

Leave the proxy setting alone The Actor already picks the right pool for your locale, and the choice is not obvious. Google Hotels does not block datacenter IPs — a measured US search returned the same 20 hotels with complete OTA prices over datacenter as over Residential, faster and at a fraction of the cost. What datacenter cannot do is quote a non-US currency: the exit IP decides the currency Google shows, so a KRW run over a US pool comes back priced in USD and the Actor rejects almost every row. That is why non-US or non-USD searches use Residential automatically.

Start with a small test run Set maxResults to 5-10 and dataSections to ["overview", "prices"] for your first run to validate your queries and date range before scaling up.

Enable only the sections your pipeline uses Each additional data section adds 5-15 seconds per hotel. For runs with 50-100 hotels, collecting all sections significantly increases total run time. Select only the sections you will actually consume downstream.

Use specific, location-aware queries More specific queries return more relevant results. "hotels in Tokyo Shibuya near station" is more precise than "hotels in Japan". Google Hotels returns city-level results — overly broad geographic queries may not return useful data.

Disable scrapeOtaPrices for fast metadata runs When you only need hotel names, ratings, and summary prices from the search results page, set scrapeOtaPrices: false. This reduces run time by approximately 80% and still provides basic pricing data.

Schedule daily runs for price monitoring Use Apify Scheduling to run this Actor on a daily cadence with the same queries. Use the Apify API to compare datasets across runs and detect price changes over time.

Increase requestHandlerTimeoutSecs for large runs When scraping 50+ hotels with all data sections, consider increasing the timeout to 1200-1800 seconds to avoid timeout errors on slow proxy connections.


Limitations

  • Maximum 5 queries per run — each query is a separate Google Hotels search
  • Maximum 100 hotels per query — capped by Google Hotels' result set pagination
  • Display prices only — prices reflect what Google Hotels shows at scrape time and do not include taxes, fees, or member-only discounts applied during checkout
  • Dynamic DOM dependency — Google Hotels updates its frontend periodically; minor extraction issues may occur after major UI changes
  • OTA coverage varies by hotel — smaller or boutique properties may have fewer OTA partnerships and fewer prices in the comparison table
  • Currency follows the exit IP — Google quotes OTA prices in the currency of the proxy's country, not the currency you request, so the two must agree. The Actor handles this by choosing the proxy pool for you; if you override proxy manually, match it to your country and currency or the price-context check will reject the rows
  • Adults-only occupancy — currently supports adult guest count only; children and multi-room configurations are not supported

Integrations

Apify API

Trigger runs and retrieve results programmatically:

# Start a run
curl -X POST \
"https://api.apify.com/v2/acts/YOUR_ACTOR_ID/runs?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"queries": ["hotels in Singapore"],
"checkIn": "2025-09-01",
"checkOut": "2025-09-02",
"maxResults": 20,
"dataSections": ["overview", "prices", "reviews"]
}'
# Retrieve results from the dataset
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_API_TOKEN&format=json"

Webhooks

Configure webhooks in the Actor settings to receive a POST notification when a run completes. Use this to trigger downstream processing — for example, loading price data into a database, calculating savings, or sending deal alerts via Slack or email.

Scheduled Runs

Use Apify Scheduling to run this Actor on a daily or weekly cadence. Combine with webhooks to build fully automated price monitoring pipelines without additional infrastructure.

Data Export Formats

Results can be exported directly from the Dataset tab:

  • JSON — full structured data, ideal for API consumers and data pipelines
  • CSV — flat format for spreadsheet analysis (nested objects are serialized)
  • Excel (.xlsx) — for manual review and reporting
  • XML — for legacy system integration

Zapier and Make

Connect Actor runs to Zapier or Make (Integromat) workflows via the native Apify integration. Push hotel price data automatically to Google Sheets, Airtable, Slack, or any connected service.


FAQ

Does this Actor require a Google account or API key?

No. The Actor accesses Google Hotels as a standard browser session. No Google account, API key, or special credentials are required.

How accurate are the prices?

Prices reflect what Google Hotels displays at scrape time for the specified dates and guest count. They are display prices before taxes and fees. Actual checkout prices on OTA sites may differ due to taxes, service charges, or member-only discounts.

Can I search for a specific hotel by name?

Yes. Use a precise query such as "Marriott Marquis Times Square New York" to target a specific property. Note that Google may still return nearby alternatives. You can filter by hotelName in post-processing.

Why do some hotels have fewer OTA providers?

Smaller or boutique hotels may have fewer OTA partnerships. If a hotel has no price comparison data on Google Hotels, prices will be an empty array and lowestPrice will be null.

Can I run multiple queries to compare prices across different date ranges?

Yes. Create a separate entry in queries for each date or destination combination. You are charged per hotel result ($0.025/hotel), not per query.

What happens if Google updates its UI?

The Actor uses a hybrid approach: API interception (more stable, unaffected by UI changes) combined with DOM selectors (less stable). If Google updates its frontend, the DOM-based extraction may need selector updates. Check the Apify Store listing for version updates.

Why is scrapeOtaPrices enabled by default?

OTA price comparison is the primary purpose of this Actor. Disabling it returns only basic search-result data (hotel name, summary rating, thumbnail price) without the full OTA breakdown. For most use cases, the default setting is correct.

Can I use custom proxies instead of Apify Residential?

Yes. Set proxy.useApifyProxy: false and provide your proxy URLs in proxy.proxyUrls. Datacenter proxies work fine for US dollar searches — Google Hotels does not block them. For any other country or currency, use a proxy that exits in that country, because Google quotes OTA prices in the exit IP's currency and mismatched rows are rejected.

Why is starRating null for some hotels?

Star rating is extracted from Google Hotels search results. Some hotels — particularly smaller or unclassified properties — do not have a star classification displayed by Google, resulting in a null value.