# Google Hotels Scraper: OTA Prices & Calendar (`aleksandrbooking/google-hotels-scraper`) Actor

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.

- **URL**: https://apify.com/aleksandrbooking/google-hotels-scraper.md
- **Developed by:** [Aleksandr Kobtsev](https://apify.com/aleksandrbooking) (community)
- **Categories:** Travel, Marketing, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.70 / 1,000 hotels

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

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: false` and 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.

```json
{
  "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.

```json
{
  "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?

1. 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.
2. 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**.
3. 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:

```json
{
  "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: `officialPrice` is the price of the hotel's own site as Google shows it, `officialUndercutBy` lists the booking sites that charge at least one percent less, and `parityStatus` says `undercut`, `parity` or `no_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's `originalPrice`.
- 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](https://blog.apify.com/is-web-scraping-legal/).

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.

# Changelog

This Actor's version history is a separate document: https://apify.com/aleksandrbooking/google-hotels-scraper/changelog.md

# Actor input Schema

## `searchQueries` (type: `array`):

What you would type into Google Hotels: "hotels in Batumi", "5 star hotels in Lisbon", "hostels near Shinjuku". Each search returns up to the number of hotels set below. Google lists about twenty hotels per request in a changing order, so the Actor asks a few times and keeps what is new; a big city gives about fifty to sixty hotels per text at most, and a more specific text ("beach hotels in Batumi") reaches others.

## `hotels` (type: `array`):

Hotels to price by name, with the city: "Hilton Batumi", "Hotel Adlon Kempinski Berlin". Or paste a Google Hotels link of a hotel (the address that has /entity/ in it): it is exact and needs no lookup. A name that matches no hotel well enough is listed in FAILED_HOTELS with what Google offered, and is not charged.

## `checkInDate` (type: `string`):

YYYY-MM-DD. Leave empty to use "Days ahead" instead. Google prices stays up to about eleven months ahead.

## `checkOutDate` (type: `string`):

YYYY-MM-DD. Leave empty to use "Nights" after the check-in date.

## `daysAhead` (type: `integer`):

Check-in this many days from today, when no check-in date is given. A scheduled run with this set always prices a stay the same distance away.

## `nights` (type: `integer`):

How many nights, when no check-out date is given.

## `scanDays` (type: `integer`):

A price calendar: how many check-in dates to price, starting with the check-in date (or Days ahead). Each date is a stay of "Nights" nights and gets its own row for every hotel, charged as one cheaper "hotel date" event (see the pricing of the Actor). 1 is a single stay. Up to 120. A calendar of 30 dates for 10 hotels is 300 rows. It needs every hotel page, so "Price on every booking site" is on for it whatever it is set to.

## `scanStep` (type: `integer`):

The gap between the check-in dates of a calendar: 1 for every day, 7 for the same weekday every week.

## `adults` (type: `integer`):

Adults in the room. Prices are for the whole party, not per person.

## `childrenAges` (type: `array`):

One entry per child, the age in years: 4, 11. Up to five children.

## `currency` (type: `string`):

The currency prices are given in. Google converts for booking sites that charge in another currency.

## `country` (type: `string`):

The two-letter country code Google sells the stay in: us, gb, de, ge. It decides which booking sites Google lists and what they charge, which is why the same hotel shows different offers in different countries. It is not the country of the hotel.

## `language` (type: `string`):

The language of the texts Google returns: descriptions, labels, amenities.

## `maxHotelsPerSearch` (type: `integer`):

How many hotels to collect for each search. Twenty is one page from Google; more takes more requests, and a text with fewer hotels than this simply returns them all. Hotels named under "Hotels" do not count against it.

## `includeOffers` (type: `boolean`):

On: one request per hotel to its Google page, which lists every booking site with its price, free-cancellation deadline and link. Off: only the lowest price each search card shows, which is much faster.

## `trackChanges` (type: `boolean`):

Remember each hotel and check-in date in a store of your own account (google-hotels-price-memory) and, on the next run of the same kind of stay (same nights, guests, currency and country), say what changed: previousPrice, priceChange and priceChangePercent on every row, and a PRICE_CHANGES record with the moves, biggest drops first. Put the run on a schedule and read that record. Off by default: nothing is stored unless you turn it on.

## `offerPasses` (type: `integer`):

Google leaves booking sites out of some answers, and a small hotel loses one now and then (Booking.com was missing from one answer in ten in a measured case). A hotel with fewer than twelve offers is read again, from another address, and the offers are merged; a read that adds nothing ends it. 1 reads every hotel once; 2 or 3 is slower and more complete for small hotels. Hotels with twelve or more offers are always read once.

## `concurrency` (type: `integer`):

How many requests run at the same time, across the whole run. The default is gentle on Google and quick enough.

## `proxy` (type: `object`):

Apify datacenter proxies are the default and what this Actor is priced on. Apify residential groups are not available here; a run that asks for one is refused in the first seconds, before any hotel is charged. For your own proxies choose Custom proxies and supply them.

## `dryRun` (type: `boolean`):

Produce data without charging events. Honored only for runs started by the Actor owner; ignored for everyone else.

## Actor input object example

```json
{
  "searchQueries": [
    "hotels in Batumi"
  ],
  "hotels": [],
  "daysAhead": 14,
  "nights": 2,
  "scanDays": 1,
  "scanStep": 1,
  "adults": 2,
  "childrenAges": [],
  "currency": "USD",
  "country": "us",
  "language": "en",
  "maxHotelsPerSearch": 20,
  "includeOffers": true,
  "trackChanges": false,
  "offerPasses": 2,
  "concurrency": 5,
  "proxy": {
    "useApifyProxy": true
  },
  "dryRun": false
}
```

# Actor output Schema

## `hotels` (type: `string`):

No description

## `hotelsRead` (type: `string`):

No description

## `failedHotels` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQueries": [
        "hotels in Batumi"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("aleksandrbooking/google-hotels-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "searchQueries": ["hotels in Batumi"] }

# Run the Actor and wait for it to finish
run = client.actor("aleksandrbooking/google-hotels-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "hotels in Batumi"
  ]
}' |
apify call aleksandrbooking/google-hotels-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,aleksandrbooking/google-hotels-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/D5FRci6UE63aiqUwq/builds/Fcuok1eK07GN1rhb1/openapi.json
