Google Hotels Scraper - Hotel Prices Across Every Booking Site avatar

Google Hotels Scraper - Hotel Prices Across Every Booking Site

Pricing

$0.99 / 1,000 hotels

Go to Apify Store
Google Hotels Scraper - Hotel Prices Across Every Booking Site

Google Hotels Scraper - Hotel Prices Across Every Booking Site

Search Google Hotels by destination and dates: hotel listings plus the price every booking site quoted for the same stay.

Pricing

$0.99 / 1,000 hotels

Rating

0.0

(0)

Developer

Lantern Lab

Lantern Lab

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

Google Hotels Scraper

Give it a destination and your dates and get Google Hotels' public results back: the hotel, its class, rating, review count, coordinates, address, amenities, photos, the cheapest nightly price and stay total - and prices, the quote every booking site gave for that same stay, with Google's own outbound link for each. Your dates, guest count and currency are honoured, not approximated. No Google login, no cookies, no account of your own. $0.99 per 1,000 hotels, no start fee; every booking site's price is included. See Pricing.

Input:

{
"queries": ["hotels in Paris", "hotels in Tokyo"],
"checkIn": "2026-11-10",
"checkOut": "2026-11-12",
"adults": 2,
"currency": "USD",
"maxItems": 40
}

Output - one row per hotel (recordType: "hotel"); per-destination status rows and the run summary are free. Sample from a real run, photo and link URLs shortened:

{
"recordType": "hotel",
"hotelId": "ChgI9LOche-i1LjzARoLL2cvMXRkM2t4YjMQAQ",
"featureId": "0x47e66d84b6c685f7:0xf3715116f0a719f4",
"name": "Hôtel Belgrand",
"url": "https://www.google.com/travel/hotels/entity/ChgI9LOche-i1LjzARoLL2cvMXRkM2t4YjMQAQ",
"starClass": 3,
"starClassText": "3-star tourist hotel",
"rating": 3.4,
"reviewCount": 440,
"address": "35 Rue Belgrand, 75020 Paris, France",
"lat": 48.8644845,
"lng": 2.4062453,
"countryCode": "FR",
"lowestPrice": 86.2708,
"lowestPriceText": "$86",
"totalPrice": 173,
"totalPriceText": "$173",
"currency": "USD",
"prices": [
{ "provider": "Booking.com", "price": 86.27, "priceText": "$86", "totalPrice": 173, "totalPriceText": "$173", "link": "https://www.google.com/travel/lodging/clk?pc=AA80Osw6…" },
{ "provider": "Expedia.com", "price": 92.5, "priceText": "$93", "totalPrice": 185, "totalPriceText": "$185", "link": "https://www.google.com/travel/lodging/clk?pc=AA80OsyR…" }
],
"pricesStatus": "ok",
"amenities": ["Breakfast ($)", "Free Wi-Fi", "Parking", "Restaurant", "Accessible", "Kid-friendly", "Smoke-free property"],
"imageUrls": ["https://lh3.googleusercontent.com/grass-cs/AABkmLcNHAM7…"],
"description": "Unassuming rooms with flat-screens in a straightforward budget hotel offering complimentary Wi-Fi.",
"website": "https://hotel-belgrand-paris.example-hotel-site.fr/",
"checkIn": "2026-11-10",
"checkOut": "2026-11-12",
"nights": 2,
"adults": 2,
"pricedCheckIn": "2026-11-10",
"pricedCheckOut": "2026-11-12",
"pricedAdults": 2,
"query": "hotels in Paris",
"destination": "Paris",
"destinationId": "0x47e66e1f06e2b70f:0x40b82c3688c9460",
"hl": "en",
"gl": "us",
"rank": 1,
"partial": false,
"partialReason": null,
"publishedAt": null,
"collectedAt": "2026-10-24T10:41:22.318Z"
}

Limits:

  • About 20 hotels per destination. That is one Google Hotels results page, and Google loads the rest only through an in-page call that needs a signed browser session. Use several narrower destinations ("hotels in Montmartre, Paris", "hotels near Gare du Nord") to cover a big city. Every destination row says how many Google listed (hotelsAvailable) and whether its page was full (pageLimitReached).
  • Prices move, and lowestPrice is not the cheapest row in prices. lowestPrice / totalPrice are what Google printed on the results page - its featured rate for that hotel. prices[] comes from the hotel's own page a moment later and regularly contains a cheaper quote, which is the point of fetching it. Both are kept as read; neither is recomputed from the other. A row is a quote at collectedAt for the stay in checkIn/checkOut, not a reservation - re-run for current prices, and expect different prices from a different gl.
  • How many booking sites appear is Google's choice, not a completeness guarantee. Measured 2026-10-24: 13-31 offers per hotel for Paris, Tokyo, Bangkok, Dubai and Singapore, exactly 1 (the hotel's own site) for Moscow hotels, and occasionally a short list where a repeat of the same request returned the full one. prices[] is what the hotel page carried when it was read; pricesStatus tells you whether it could be read at all.
  • Public data only. The public Google Hotels result page and hotel page; no login, no reviews text, no room-level inventory, no guest names or contact details.
  • Every destination gets a status row saying what happened. A destination Google answered with nothing is an empty result; one cut short by a limit, refusal or error is partial with the reason - the two are never confused.
  • Your limits stop collection and appear in the row: maxItems, the maxUpstreamRequests request ceiling and the maximum charge per run (see Pricing).

What it does

  • Searches each destination separately and labels every row with the destination that produced it, so one run can cover many cities or districts.
  • Sends your stay exactly as Google's own date picker does, so the prices are for your dates, your guest count and your currency - not for Google's defaults. Google ignores the checkin=/checkout=/curr= parameters people usually try; this Actor does not use them.
  • Checks Google's answer against what was asked. Every row carries pricedCheckIn / pricedCheckOut / pricedAdults - the stay Google says it priced. If it ever differs from yours, the rows are marked partial with partialReason: "stay_not_applied" and not charged, instead of being handed to you as prices for the wrong dates.
  • Fetches each hotel's own page for the street address and the full prices list - one row per booking site, as Google ordered them, each with its nightly price, its stay total and Google's outbound link.
  • Deduplicates by hotelId across the whole run, so a hotel that matches two of your destinations is written and charged once.
  • Says which place Google decided your search term meant, in destination. Google answers a term it cannot place with hotels somewhere else entirely rather than with nothing, and this is the field that shows it.
  • Writes RUN_SUMMARY as the last dataset row and as a key-value store record: totals, empty destinations, incomplete destinations by reason, provider offers read, requests sent and why collection stopped.

Input

FieldTypeDefaultWhat it does
queriesstring[]requiredOne destination per line: a city, a district, a region, or a hotel name.
checkInstringtomorrowCheck-in day, YYYY-MM-DD. Must be today or later, at most 330 days ahead.
checkOutstringday after check-inCheck-out day, YYYY-MM-DD. After check-in, at most 30 nights later.
adultsinteger2Guests the rooms are priced for, 1-6.
currencystringUSDThree-letter code the prices come back in, e.g. EUR, GBP, RUB, JPY.
glstringusTwo-letter country code of the Google edition; changes which booking sites are listed.
hlstringenInterface language; the language of amenity names, the class sentence and the description.
maxItemsinteger100Upper bound on hotel rows for the whole run.
includeProviderPricesbooleantrueOff: no prices list, no address, one request per destination instead of one per hotel.
maxUpstreamRequestsintegerderivedHard ceiling on requests to Google. Left empty it is worked out from your input, so a run is never unbounded.
proxyConfigurationobjectApify ProxyWhere the requests come from. The default datacenter proxy is what this Actor is measured on.

The 330-day and 30-night bounds are Google's own, taken from its date picker; an input outside them fails before any request is sent, so it costs nothing.

Output

Three record types in one dataset, told apart by recordType:

hotel - one per hotel, the only charged row. prices[] holds { provider, price, priceText, totalPrice, totalPriceText, link } per booking site. A field Google did not provide is null, never guessed: starClass is absent for apartments and some vacation rentals, rating and reviewCount for places with no reviews yet, address on runs with includeProviderPrices off. price/totalPrice are numbers; priceText/totalPriceText are what Google displayed, kept verbatim.

pricesStatus says why prices is empty:

pricesStatusMeaning
okOffers were read.
no_offersGoogle showed no bookable offer for this hotel and stay. A real answer.
not_requestedincludeProviderPrices was off.
upstream_request_capThe run's request ceiling was reached before this hotel's page.
blockedGoogle refused the hotel page.
request_failed / unreadableThe hotel page failed, or carried no readable payload.

query_status - one per destination, never charged. hotelsReturned, hotelsCharged, duplicatesSkipped, hotelsAvailable, pageLimitReached, partial, partialReason, statusText, and destination (the place Google resolved the term to).

partialReasonMeaning
nullComplete. hotelsReturned: 0 with partial: false means Google really listed no hotel.
page_limit_reachedYou had room for more rows and Google's one page ran out first.
max_items_reachedmaxItems was reached here.
upstream_request_capThe request ceiling was reached here.
charge_limit_reachedThe run's maximum charge was reached here.
blockedGoogle refused our requests for this destination. Not an empty result.
upstream_errorA request failed in a way a retry inside the run would not fix.
unreadable_pageGoogle answered with a page holding no readable hotel list.
stay_not_appliedGoogle priced a stay other than yours. The rows are kept, marked, and not charged.
not_collectedThe run stopped earlier and never reached this destination.

RUN_SUMMARY - the last row, and the RUN_SUMMARY key-value store record.

Pricing

$0.99 per 1,000 hotel rows. No start fee, no per-page fee, no charge for the booking-site prices.

  • Only hotel rows are charged. Destination status rows and RUN_SUMMARY are free, so a destination that returned nothing, was blocked or was cut short costs nothing.
  • Rows marked partial are not charged. In practice that means a stay Google did not apply: you can see what came back without paying for prices that are not for your dates.
  • A hotel matching several of your destinations is charged once.
  • Set Maximum cost per run in the run options to cap a run. Collection stops at the cap and the destination it stopped on is marked charge_limit_reached - it is never reported as empty.

Notes

  • includeProviderPrices is the one setting that changes the cost of a run for us as well as the time: it is one extra request and roughly 25 times more traffic per hotel. The price above covers it either way; turning it off just makes runs faster.
  • Measured on Apify Proxy datacenter IPs. Google Hotels serves these public pages over them without a bot check, so no residential proxy is needed; you can still point proxyConfiguration at one if you want a specific country's exit.
  • hotelId is Google Travel's own identifier and is stable across runs; featureId is the Google Maps feature id for the same place, for joining to other Google data.