Google Hotels Scraper: OTA Prices & Calendar
Pricing
from $2.70 / 1,000 hotels
Google Hotels Scraper: OTA Prices & Calendar
Search a city or name hotels and get every booking site's price from Google Hotels: Booking.com, Expedia, Agoda, the hotel's own site and more, with cancellation terms, rating and address. Any currency, guests and country. Plain HTTP. Not affiliated with Google.
Pricing
from $2.70 / 1,000 hotels
Rating
0.0
(0)
Developer
Aleksandr Kobtsev
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Share
Search a city or name your hotels and get what every booking site charges for the same stay, or for a calendar of many check-in dates, as Google Hotels lists it: Booking.com, Expedia, Agoda, Hotels.com, Trip.com, the hotel's own site and the other twenty or so, each with its price per night, the total, the price before taxes and fees, the free-cancellation deadline and the link to its page. One dataset row per hotel, with the rating, address, phone, website, coordinates and photos beside the prices.
There is no login, no browser and no partner API. The Actor reads the pages Google Hotels serves to anyone, over plain HTTP, which is why it runs in 512 MB to 1 GB, finishes a few hundred hotels in minutes and can be priced low. It reads only the pages Google's robots.txt leaves open to crawlers (see the last section). Run it once, put it on a schedule, or call it from the API, and forward the result to Google Sheets, a database, Slack, Make, Zapier or an MCP client.
Who is this Google Hotels scraper for?
| You are | What you run | What you get |
|---|---|---|
| A hotel revenue manager | your hotel and its competitive set, every morning | which booking site undercuts your own site and by how much, a parity check in one table |
| A travel agency or metasearch builder | a destination for the next weekends | the cheapest site per hotel and the spread between sites |
| An analyst | a city, a month of check-in dates | prices, ratings and review counts for the whole market, ready for a model |
| An AI workflow or a deal alert | hotels through the API, a currency and a country | clean rows with prices and cancellation terms to compare and forward |
What makes this different from other Google Hotels scrapers?
- Every booking site's price, not one. A row carries the list of offers: provider, price per night with taxes and fees, price before taxes where Google splits them, the total for the stay, the struck-through price and member-rate label, the free-cancellation deadline and the booking site's own link. A hotel in a big city has 15 to 30 of them.
- It asks Google the right question, and checks the answer. Currency, dates, adults and children are put in the address the way the web page puts them. A page that comes back for other dates, another currency or other guests is refused, not delivered as the stay you asked for. Early in development a wrong parameter returned prices for default dates with no error; that is the failure this check exists for.
- The country of sale is a setting. Google lists different booking sites at different prices depending on the country the stay is sold in. Choose it with
country, and the same hotel shows what a guest in Germany, Georgia or the United States would see. - It stays inside robots.txt. Only
/travel/hotels/addresses are requested, and the Actor reads Google's robots.txt at the start of every run and refuses any address it closes. The redirect links Google uses for clicks (/travel/lodging/clk, which robots.txt closes) are never opened: the booking site's address is read out of the page's data. - Honest about what it could not read. A hotel name that matches nothing well enough is listed in FAILED_HOTELS with what Google offered instead, and is not charged. A hotel with no price for your dates is delivered with
available: falseand is not charged either.
What data does it return?
One row per hotel.
| Field | What it is |
|---|---|
| name, url | The hotel and its Google Hotels page for your stay. |
| entityToken, googleMid, googleCid, googlePlaceId | Google's own identifiers of the hotel: the token in its address, the map feature id, the customer id and the Maps place id. Stable, so they are the keys to join runs on. Vacation rentals have no googleMid. |
| address, city, region, district, locationPath, countryCode | Where it is. locationPath is every place Google names above the hotel, outermost first; city, region and district are the usual reading of it. |
| latitude, longitude, phone, website | Coordinates, phone and the hotel's own site. |
| hotelClass, propertyType | Stars, and Google's wording ("4-star hotel"). null for properties Google does not class. |
| rating, reviewsCount, ratingDistribution | Google's guest rating of 5, the number of reviews and the count per star. |
| checkInTime, checkOutTime, description | As the search card shows them; not every hotel has them. |
| amenities, propertyDetails | What the search card lists (Free Wi-Fi, Outdoor pool) and, for rentals, what the rental is (Sleeps 4, 2 bedrooms). Only hotels that came from a search have them, and Google puts four to ten on a card, not the whole facility list. |
| images, thumbnail | Photo links, Google's own sizes. |
| checkIn, checkOut, nights, adults, childrenAges, currency, country | The stay and the country of sale the prices are for. |
| available | false when Google has no price for the hotel for this stay. |
| price, priceBeforeTaxes, total, totalBeforeTaxes, cheapestProvider | The lowest offer: per night as Google shows it (with taxes and fees where it splits them), per night before taxes, the stay, the stay before taxes, and who offers it. |
| offersCount, offers | Every booking site, cheapest first (below). |
| officialPrice, officialUndercutBy, parityStatus | Rate parity, worked out from the offers: the price of the hotel's own site, the booking sites that charge at least one percent less (provider, price, percent below, biggest gap first), and undercut, parity or no_official_offer. null where there are no offers. |
| query, source | The search text or name the row came from, and whether it came from a search, a name or a link. |
| scrapedAt | When it was collected, ISO-8601 UTC. |
| previousPrice, priceChange, priceChangePercent, previousScrapedAt | With Track price changes: the price of this hotel and check-in date in the previous run of the same kind of stay, the difference (negative is cheaper), the difference in percent and when that run was. null when not tracking, on a first run, and where either price is missing. |
Each entry of offers:
| Field | What it is |
|---|---|
| provider, providerId, official | The booking site, Google's number for it, and whether it is the hotel's own site. |
| price, priceBeforeTaxes | Per night. price is what Google shows: with taxes and fees where it splits them out. priceBeforeTaxes is null when Google gives one figure. |
| total, totalBeforeTaxes | For the whole stay. |
| originalPrice, promotion | The struck-through price and its label ("Member rate, save 10%") where the booking site shows one. |
| freeCancellation, freeCancellationUntil, freeCancellationUntilText | Free cancellation, the date it ends (ISO), and the text as Google prints it ("Nov 4, 7:59 PM"). A deadline that has already passed is not a free cancellation. |
| bookingUrl | The booking site's own page for this hotel and stay, where Google's data has one. |
An example row, as a run returned it on 11 October 2026: New Wave Hotel, Batumi, 10 to 12 November 2026, two adults, Georgian lari, sold in the United States. A small hotel; that read had three offers. The photo links and the long booking-site addresses are cut.
{"name": "New Wave Hotel","entityToken": "ChkI1K7Zid6e2LRxGg0vZy8xMWpsMzZoZnk5EAE","googleMid": "0x404407becab7bb23:0x716960f5e1365754","googleCid": "13629929695352738208","googlePlaceId": "ChIJI7u3yr4HREARVFc24fVgaXE","address": "10 Juli Shartava Avenue, Batumi 6010, Georgia","city": "Batumi","region": "Adjara","district": null,"locationPath": ["Adjara", "Batumi"],"countryCode": "GE","latitude": 41.6386518,"longitude": 41.6177257,"phone": "+995 422 27 07 07","website": "http://www.newwavehotels.com/","hotelClass": 5,"propertyType": "5-star hotel","rating": 4.2,"reviewsCount": 1146,"ratingDistribution": [{ "stars": 5, "count": 706 }, { "stars": 4, "count": 203 }, { "stars": 3, "count": 96 }, { "stars": 2, "count": 42 }, { "stars": 1, "count": 99 }],"checkInTime": null,"checkOutTime": null,"description": null,"amenities": [],"propertyDetails": [],"images": ["https://lh3.googleusercontent.com/…", "…"],"thumbnail": "https://lh3.googleusercontent.com/…","url": "https://www.google.com/travel/hotels/entity/ChkI1K7Zid6e2LRxGg0vZy8xMWpsMzZoZnk5EAE/prices?hl=en&gl=us&ts=CAESCgoCCAMKAggDEAAaGBIWEhQKBwjqDxALGAoSBwjqDxALGAwYAioHCgU6A0dFTA","checkIn": "2026-11-10","checkOut": "2026-11-12","nights": 2,"adults": 2,"childrenAges": [],"currency": "GEL","country": "us","available": true,"price": 114.25,"priceBeforeTaxes": null,"total": 228.5,"totalBeforeTaxes": null,"cheapestProvider": "Traveloka.com","offersCount": 3,"offers": [{ "provider": "Traveloka.com", "providerId": 101091618, "official": false, "price": 114.25, "priceBeforeTaxes": null, "total": 228.5, "totalBeforeTaxes": null, "currency": "GEL", "originalPrice": null, "promotion": null, "freeCancellation": true, "freeCancellationUntil": "2026-11-05", "freeCancellationUntilText": "Nov 5, 1:59 PM", "bookingUrl": "https://www.traveloka.com/en-en/hotel/search?spec=10-11-2026.12-11-2026.2.1.HOTEL_GEO.30069930.Ajaria.2&hotelI…" },{ "provider": "New Wave Hotel", "providerId": 1564565717, "official": true, "price": 118.8, "priceBeforeTaxes": null, "total": 237.59, "totalBeforeTaxes": null, "currency": "GEL", "originalPrice": 132, "promotion": "Member rate, save 10%", "freeCancellation": false, "freeCancellationUntil": null, "freeCancellationUntilText": null, "bookingUrl": "https://gha.hopenapi.com/GoogleHotelAds/pos?hotel-id=507759&googlesource=localuniversal&userdevice=desktop&be-…" },{ "provider": "HomeToGo", "providerId": 1302339008, "official": false, "price": 123.5, "priceBeforeTaxes": 104.67, "total": 247, "totalBeforeTaxes": 209.35, "currency": "GEL", "originalPrice": null, "promotion": null, "freeCancellation": false, "freeCancellationUntil": null, "freeCancellationUntilText": null, "bookingUrl": null }],"officialPrice": 118.8,"officialUndercutBy": [{ "provider": "Traveloka.com", "price": 114.25, "percentBelow": 3.83 }],"parityStatus": "undercut","query": "New Wave Hotel Batumi","source": "name","scrapedAt": "2026-10-11T16:21:29.762Z","previousPrice": null,"priceChange": null,"priceChangePercent": null,"previousScrapedAt": null}
A price calendar: one hotel, many dates
Set Check-in dates to price to a number above 1 and the Actor prices a stay of Nights nights from each of that many check-in dates, Days between check-ins apart, for every hotel of the run. One row per hotel and date, each with every booking site's offer, so a month of one hotel is 30 rows and the cheapest site on each date is in the data. Each row of a calendar is one hotel-date event, $0.0012 on the free plan and $0.0008 on Gold (see "What does it cost?"): a month of one hotel is about four cents.
{"hotels": ["Hilton Batumi"],"daysAhead": 1,"nights": 1,"scanDays": 30,"currency": "EUR"}
The HOTELS record of the run lists each hotel with how many of its dates had a price and the cheapest date. A hotel is read once per date, so 10 hotels for 30 dates is 300 pages. Measured on the platform on 11 October 2026: 8 hotels for 30 dates, 240 rows with 271 requests, took 2 minutes 13 seconds at eight requests in parallel (five is the default), used $0.013 of platform usage and met no challenge. One run delivers at most 20,000 rows.
Price changes since the last run
Turn on Track price changes and put the run on a schedule. The Actor keeps the price of each hotel and check-in date in a key-value store of your own account, google-hotels-price-memory, one record for each kind of stay (nights, guests, currency, country of sale). On the next run every row says what the price was, how much it moved and when it was last seen, and the PRICE_CHANGES record of the run lists the rows that moved, the biggest drops first, which is what an alert or a Slack message wants. A check-in date that has passed is forgotten. Nothing is stored unless you turn it on.
How steady the figure is: six hotels for ten dates were read three times on 11 October 2026 (165 pairs of reads of the same hotel and date). The cheapest price differed by more than half a percent in 4 pairs (2%), because a booking site Google lists in one answer was missing from the other; the Booking.com price and the hotel's own price did not differ in any of the 148 and 136 pairs. If you alert on moves, a threshold of a few percent, or the offers entry of the booking site you care about, keeps the noise out.
How do I use it?
- Under Searches type what you would type into Google Hotels:
hotels in Batumi,5 star hotels in Lisbon,hostels near Shinjuku. Or under Hotels put hotel names with the city (Hilton Batumi,Hotel Adlon Kempinski Berlin), or paste a Google Hotels link of a hotel. - Choose the stay: check-in and check-out dates, or Days ahead and Nights for a schedule that always prices the same distance ahead. Choose adults, children's ages, Currency and Country of sale.
- Press Start. A search of 20 hotels with every booking site's price takes under a minute; 190 hotels took four minutes.
From the API:
{"searchQueries": ["hotels in Batumi"],"hotels": ["Hilton Batumi", "Radisson Blu Batumi"],"checkInDate": "2026-11-10","checkOutDate": "2026-11-12","adults": 2,"currency": "EUR","country": "de","maxHotelsPerSearch": 40}
What can I set?
| Setting | What it does |
|---|---|
| Searches | Texts to search on Google Hotels. Each returns up to Hotels per search hotels. |
| Hotels | Hotels by name with the city, or by Google Hotels link. |
| Check-in date, Check-out date | The stay, as YYYY-MM-DD. |
| Days ahead, Nights | The stay, relative to the day of the run, when no dates are given. |
| Check-in dates to price, Days between check-ins | A price calendar: how many check-in dates, and how many days apart (1 to 120 dates, 1 to 30 days). |
| Adults, Children (ages) | Guests. Prices are for the whole party in one room. |
| Currency | The currency prices are given in: any of the 72 Google Hotels offers. |
| Country of sale | Two-letter country code (us, gb, de, ge): which booking sites Google lists and what they charge there. |
| Language | The language of descriptions, amenities and place names. |
| Hotels per search | How many hotels to collect per search, 1 to 200. |
| Price on every booking site | On: the offers of every booking site. Off: only the lowest price on each search card, which is much faster. |
| Track price changes | On: the run remembers the prices it saw (in a store of your account) and the next run says what moved; see below. Off by default. |
| Reads of a hotel with few offers | How often a hotel with fewer than twelve offers is read (1 to 3); see the limits below. |
| Requests in parallel | 1 to 10, five by default. |
| Proxy | Apify datacenter proxies by default; your own proxies if you choose Custom proxies. |
How many hotels does a search return?
Google lists about twenty hotels per page and fills a page from the sixty or so it has for a text, in an order that changes from one request to the next. The Actor asks again a few times and keeps what is new: 20 hotels take one request, 45 take ten or so. In cities measured on 11 October 2026 a text gave 46 to 50 hotels before no new ones turned up. To go further, search for something narrower (beach hotels in Batumi, hotels near the airport in Lisbon); texts overlap, and the Actor reads each hotel once however many searches name it.
How are the prices defined?
- price is what Google shows on its hotel page in the "Nightly total" mode: the price per night with taxes and fees where Google can split them out. priceBeforeTaxes is the same night before them, when Google gives both.
- total is the whole stay. It is the nightly figure times the nights, which is how Google itself builds it.
- Rate parity is worked out for you:
officialPriceis the price of the hotel's own site as Google shows it,officialUndercutBylists the booking sites that charge at least one percent less, andparityStatussaysundercut,parityorno_official_offer. Where the hotel's own site shows a member rate, that is the price compared, and the public price is in the offer'soriginalPrice. - Google shows offers as they are at the moment of the request. A booking site may charge a different figure at checkout, and the same hotel shows different sites and prices in different countries: that is what country is for.
- Prices are for the whole party in one room. Children are priced by the age you give.
What does it cost?
Pay per event. A run of one stay: one hotel event for every hotel delivered with a price, $0.0045 on the free plan, $0.0039 Bronze, $0.0033 Silver, $0.0027 Gold and above. A price calendar (more than one check-in date): one hotel-date event for every hotel and date delivered with a price, $0.0012 on the free plan, $0.00105 Bronze, $0.0009 Silver, $0.0008 Gold and above, the level of the Google Hotels Price Tracker for the same row. A hotel Google has no price for is delivered and not charged, and so is a repeated read of the same hotel. The platform's own events are the start of the run ($0.00005) and the dataset item ($0.00001).
Measured on the platform on 11 October 2026: 187 hotels with 3,369 offers took 4 minutes 4 seconds and used $0.0165 of platform usage.
Limits
- One stay length and one party per run. A calendar prices that stay from many check-in dates; different lengths or parties are separate runs. Schedule a run with Days ahead set to price the same distance ahead every day.
- Google leaves booking sites out of some answers, and the smaller the hotel the more often: in ten reads of one small hotel Booking.com was missing from one, and a sponsored site from seven or eight. A hotel with fewer than twelve offers is therefore read a second time from another address (and a third if the second added something) and the offers are merged; Reads of a hotel with few offers sets it. A second read is not charged again. The one big hotel measured (22 offers) gave the same set in ten reads out of ten, which is why hotels with twelve or more offers are read once.
- Amenities are the ones Google puts on a search card, only for hotels that came from a search, and in the language of the run. The full facility list is not in the pages the Actor reads.
- Free-cancellation dates are converted to ISO dates for English (
language: en); in other languages the text is given as Google prints it. - Google changes the layout of its pages from time to time. The Actor finds hotels and offers by their shape rather than their position and checks every page answers for the stay asked, so a change shows as a clear error rather than as wrong rows; if it ever does, open an issue with the run link.
Is it legal to scrape Google Hotels?
This is an unofficial tool, not affiliated with, endorsed by or connected to Google LLC. It reads publicly visible pages and collects no personal data. Google's terms restrict automated access, and you are responsible for making sure your use complies with those terms and with the law in your jurisdiction. See Apify's stance on web scraping legality.
What the Actor does about robots.txt, since that is the line most scrapers of this site cross: Google's robots.txt closes /travel/search, /travel/entity and /travel/lodging/clk to crawlers and leaves /travel/hotels/ open. The Actor requests only /travel/hotels/ pages (the search page and the hotel page), reads Google's robots.txt at the start of each run and refuses any address it closes, and never opens the click-through redirect links. That does not change what the terms say; it means the Actor does not go where robots.txt asks crawlers not to.
Found a problem?
Open an issue on the Issues tab with the run link and the hotel. Breakages in Google's pages are the expected failure mode of any scraper, and this one is built to say so rather than to deliver wrong prices. Reports get read.