# Google Hotels Scraper | Prices, Rate Parity & Alerts (`alexmorain/google-hotels-scraper`) Actor

Scrape Google Hotels prices: every booking site's rate for many hotels and dates per run, Google's low/typical/high verdict and usual price range, rate parity against the official site. Area searches too. Monitor mode returns only price drops. Plain HTTP.

- **URL**: https://apify.com/alexmorain/google-hotels-scraper.md
- **Developed by:** [Alexis Morain](https://apify.com/alexmorain) (community)
- **Categories:** Travel, E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 hotel prices

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

### What does Google Hotels Scraper do?

Google Hotels Scraper reads [Google Hotels](https://www.google.com/travel/hotels) and returns **hotel prices as structured data**: for each hotel and each check-in date, **every booking site's nightly rate** (Booking.com, Expedia, Agoda, Hotels.com, Trip.com, the hotel's official site and 20 to 30 more), the stay total with taxes and fees, **Google's own low / typical / high verdict** with the usual price range for those dates, and a **rate parity check** against the official site. **Area searches** such as `hotels in Lisbon` list the hotels of a place with their lowest price. A **monitor mode** turns a scheduled run into a **hotel price alert**: only the stays whose price dropped are returned and charged.

One row covers one hotel and one stay, with all its booking sites inside. Price 50 hotels over a 30-night calendar in a single run. It works as a **Google Hotels API** alternative over plain HTTP: no browser, no account, no API key, and the included datacenter proxy is enough.

### Why use Google Hotels Scraper?

Four things decide whether a Google Hotels scraper gives you the truth. We measured each of them on 26 October 2026.

**Google answers dates it cannot price with prices for other dates.** Ask for a stay outside its booking window and Google does not refuse: it returns a normal page (HTTP 200) priced for a default date. We asked the New York Marriott Marquis for 10 January 2028 and got the prices of 2 November 2026. This Actor checks the dates and the number of adults Google says it priced against the ones you asked for. A mismatch gives a free `dates-not-available` row, never a price labelled with the wrong night.

**A hotel name Google does not recognize returns somebody else's hotels.** The search `zzqxv qwplk hotel` returns 18 American hotels, starting with the Best Western View of Lake Powell. A scraper that takes "the first result" prices one of them. This Actor only accepts a name when Google resolves it to a single hotel; otherwise you get a free `hotel-not-found` row.

**Google's result pages overlap.** The 12 pages of `hotels in Lisbon` hold 240 rows for 228 distinct hotels, and the third page brings only 10 new hotels out of 20. Every hotel comes once and is charged once: on a 3-date run of 60 Lisbon hotels per date, the Actor skipped 53 repeats.

**One read in twelve misses a booking site.** We read the same three hotels 12 times each from fresh IPs. 33 reads out of 36 gave the same lowest price; 3 came back higher because a site was missing (Marriott Marquis: $684 on 10 reads, $788 and $929 on two). A price tracker that stores such a read raises a false price drop on its next run. In monitor mode, this Actor reads every new or changed hotel price a second time on a fresh IP and keeps the lower one (search listings are read once).

What you can do with it:

- **Rate shopping and rate parity** for hotels and revenue managers: what every channel charges for your property and your competitive set, and which sites undercut your official rate (`providersBelowOfficialSite`, `officialSiteGapPercent`).
- **Hotel price tracking and alerts**: schedule a run every morning, get only the drops, or a ping when a stay falls under your target price, by webhook to Slack or Discord.
- **Price calendars**: the lowest price and Google's verdict for each of the next 30, 90 or 180 check-in dates.
- **Travel apps and market research**: hotel lists of a city with stars, rating, reviews, coordinates and prices; "is this a good price" widgets built on Google's usual range.

Every Apify feature applies: scheduling, API access, webhooks, integrations with Make, Zapier, n8n or Google Sheets, proxy rotation and run monitoring.

### What data can Google Hotels Scraper extract?

The dataset has three kinds of rows. A **hotel-price** row is one hotel for one stay, with every booking site. A **hotel-listing** row is one hotel found by an area search, with its lowest price. A **status** row, free, says why a hotel or a date has no price.

| Field | Row | Description |
|---|---|---|
| `name`, `entityId`, `stars`, `rating`, `reviewCount` | both | Hotel, its Google Hotels ID, star class, guest rating and review count |
| `address`, `phone`, `latitude`, `longitude`, `placeId` | both | Location and contact (address and phone on hotel-price rows) |
| `checkIn`, `checkOut`, `nights`, `adults`, `currency` | both | The stay, as Google confirmed it |
| `lowestNightlyPrice` | both | Lowest nightly price Google shows |
| `stayBasePrice`, `stayTaxes`, `stayFees`, `stayTotalPrice` | both | Stay total split into base, taxes and fees |
| `priceLevel`, `typicalPriceLow`, `typicalPriceHigh` | hotel-price | Google's verdict (`low`, `typical`, `high`) and the usual nightly range for these dates |
| `dealNote`, `cheaperDates` | hotel-price | "27% less than usual", and nearby dates Google finds cheaper |
| `offers` | hotel-price | Every booking site: name, official or not, nightly price, stay total, link |
| `cheapestProvider`, `officialSitePrice`, `providersBelowOfficialSite`, `officialSiteGapPercent` | hotel-price | Rate parity against the hotel's own site |
| `previousPrice`, `priceChangePercent`, `alert`, `lowestPriceSeen` | hotel-price | Monitor mode: what changed since the last run |

The Console shows three views: hotel prices, every booking site (one line per hotel, stay and site) and price alerts.

### How to scrape Google Hotels

1. Open the Actor and put one hotel per line in **Hotels**: a Google Hotels URL (`https://www.google.com/travel/hotels/entity/Ch...`), a hotel ID, or a name with its city (`Hotel Excelsior Lisboa`).
2. Or put an area search in **Area searches** (`hotels in Lisbon`, `hotels near Times Square`) and choose **Hotels per search**. Turn on **Every booking site's rate for search results** to price each hotel found in full.
3. Set the stay: a **Check-in date**, or leave it empty and use **Check in in N days** for scheduled runs; **Nights**; **Check-in dates** for a calendar; adults and children.
4. Pick the currency and the market (**Country**), which changes the booking sites listed.
5. Click **Start**, then download the results as JSON, CSV, Excel or HTML, or read them through the API.
6. For price alerts, save the input as a task, set **Monitor mode** to `drops` and schedule the task daily.

### How much does it cost to scrape Google Hotels?

Pay per result, prices for the Apify Free plan (larger plans pay less, down to $0.0015 a hotel price and $0.0005 a hotel listing):

| Event | Price |
|---|---|
| Run start | $0.002 |
| Hotel price (one hotel, one stay, every booking site) | $0.003 |
| Hotel listing (one hotel of an area search) | $0.001 |

Status rows are free: hotel not found, unknown hotel ID, dates outside Google's window, no price for the dates, request failed. In monitor mode, unchanged stays are neither returned nor charged, and the second read of a changed price is on us.

Examples: one hotel with its 30 booking sites costs **$0.005** with the run start. A 30-night calendar for one hotel costs **$0.092**. The 100 first hotels of a city with their lowest price cost **$0.102**. Watching 20 hotels over the next 30 nights every morning in `drops` mode costs $0.002 a day plus $0.003 per alert.

### Input

See the input tab for every option. Example: three hotels, every booking site, a 14-night calendar starting 30 days from the run date, in euros from the French market:

```json
{
  "hotels": [
    "https://www.google.com/travel/hotels/entity/ChUIexampleexampleexampleexAQ",
    "Hotel Excelsior Lisboa",
    "New York Marriott Marquis"
  ],
  "checkInInDays": 30,
  "nights": 2,
  "dateCount": 14,
  "adults": 2,
  "currency": "EUR",
  "country": "FR"
}
```

Example: the 60 first hotels of two cities, lowest price only:

```json
{
  "searches": ["hotels in Lisbon", "hotels in Porto"],
  "maxHotelsPerSearch": 60,
  "checkIn": "2026-12-10",
  "nights": 3
}
```

### Output

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. A hotel-price row, shortened:

```json
{
  "type": "hotel-price",
  "entityId": "ChUIexampleexampleexampleexAQ",
  "name": "Example Grand Hotel",
  "stars": 5,
  "rating": 4.4,
  "reviewCount": 16392,
  "checkIn": "2026-12-10",
  "checkOut": "2026-12-13",
  "nights": 3,
  "adults": 2,
  "currency": "USD",
  "lowestNightlyPrice": 1306.29,
  "stayBasePrice": 3270.88,
  "stayTaxes": 513,
  "stayFees": 135,
  "stayTotalPrice": 3918.88,
  "priceLevel": "high",
  "typicalPriceLow": 1012,
  "typicalPriceHigh": 1287,
  "cheaperDates": {"checkIn": "2026-12-10", "checkOut": "2026-12-14", "nights": 4, "nightlyPrice": 1240},
  "cheapestProvider": "Example Travel",
  "officialSitePrice": 1403.83,
  "officialSiteGapPercent": 6.95,
  "providersBelowOfficialSite": ["Example Travel"],
  "offerCount": 21,
  "offers": [
    {"provider": "Example Travel", "isOfficialSite": false, "nightlyPrice": 1306.29, "totalPrice": 3918.88, "bookingUrl": "https://www.google.com/travel/lodging/clk?pc=..."},
    {"provider": "Example Grand Hotel", "isOfficialSite": true, "nightlyPrice": 1403.83, "totalPrice": 4211.5, "bookingUrl": "https://www.google.com/travel/lodging/clk?pc=..."}
  ],
  "googleHotelsUrl": "https://www.google.com/travel/hotels/entity/ChUIexampleexampleexampleexAQ?hl=en-US&gl=US&ts=..."
}
```

### Tips and advanced options

- **Taxes depend on the market.** From the default US market, Google shows nightly prices before tax (fees included), as on google.com in the US. `stayTotalPrice` always includes taxes and fees. From most other markets (`country: "FR"`, `"GB"`…), nightly prices include taxes.
- **Listings are the cheap setting.** For a city overview, keep **Every booking site's rate for search results** off: 20 hotels come from one page. Turn it on for rate shopping.
- **Reuse hotel IDs.** Every row carries `entityId`. Put it in **Hotels** for the next runs: one page per hotel and date, no name lookup.
- **Rolling dates in monitor mode**: with **Check in in N days**, the memory follows "N days ahead" from one run to the next. **Minimum drop (%)** ignores small moves; one booking site often shifts by 1 or 2 % from hour to hour.
- **Booking links** (`bookingUrl`) are Google's click-through links: they open the site with your dates, but they expire after a while.
- **Calling it from code** (Python):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("alexmorain/google-hotels-scraper").call(run_input={
    "hotels": ["New York Marriott Marquis", "Hotel Excelsior Lisboa"],
    "checkInInDays": 30,
    "dateCount": 7,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["type"] == "hotel-price":
        print(row["name"], row["checkIn"], row["lowestNightlyPrice"], row["priceLevel"])
```

### FAQ, disclaimers and support

#### Does it need a Google account, an API key or residential proxies?

No. It reads the public Google Hotels pages over HTTP through Apify's datacenter proxy: 100 pages out of 100 answered from Apify servers in our tests. If Google ever refuses a page, the Actor retries it on a fresh IP, then through residential proxies, at no extra charge to you.

#### How far ahead can I search?

Up to 365 days ahead in the input. Google's own window is shorter for many hotels: a date it cannot price gives a free `dates-not-available` row.

#### Why does a hotel have fewer booking sites than on the website?

The sites listed depend on the market (**Country**) and on Google's own selection. From the US market we usually see 20 to 35 sites for a large hotel and 10 to 20 for a smaller one.

#### Is it legal to scrape Google Hotels?

Our Actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our Actors, when used for ethical purposes by Apify users, are safe. However, you should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers. Google Hotels prices contain no personal data.

#### Something is wrong or missing

Open an issue in the Issues tab: it gets read and answered. For programmatic access, see the API tab.

# Actor input Schema

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

One hotel per line: its Google Hotels URL (<code>https://www.google.com/travel/hotels/entity/Ch...</code>), its hotel ID (the <code>Ch...</code> part, also in the <code>entityId</code> field of earlier results) or its name with the city (<code>Hotel Excelsior Lisboa</code>).<br><br>A name Google does not recognize as one hotel gives a free <code>hotel-not-found</code> row, never the price of some other hotel.

## `searches` (type: `array`):

Free text as typed on Google Hotels: <code>hotels in Lisbon</code>, <code>hotels near Times Square</code>, <code>5-star hotels in Bangkok</code>. Each search returns up to <b>Hotels per search</b> hotels with their lowest price, as <code>hotel-listing</code> rows. Google's pages overlap; every hotel comes once and is charged once.

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

Maximum distinct hotels per area search and check-in date. Google shows 20 per page.

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

Off: each search result is a <code>hotel-listing</code> row (lowest price only). On: each hotel found is priced like the hotels above (<code>hotel-price</code> rows with every booking site, Google's verdict and parity), one extra page per hotel.

## `checkIn` (type: `string`):

First check-in date, <code>YYYY-MM-DD</code>. Leave empty to use <b>Check in in N days</b>, which keeps a scheduled run valid forever.

## `checkInInDays` (type: `integer`):

Used when <b>Check-in date</b> is empty: check-in is today plus N days. Monitor mode then compares "30 days ahead" from one run to the next.

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

Length of the stay.

## `dateCount` (type: `integer`):

Number of consecutive check-in dates, starting from the first one: <code>30</code> gives a 30-day price calendar for every hotel, one row per hotel and date.

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

Guests per room. Google Hotels prices up to 6 adults.

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

One age per child (0 to 17), for example <code>\[5, 9]</code>.

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

ISO code, e.g. <code>USD</code>, <code>EUR</code>, <code>GBP</code>.

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

Two-letter code of the searcher's market (<code>gl</code>), not the hotel's country. It changes which booking sites are listed. Prices from the default US market are shown before tax; <code>stayTotalPrice</code> always includes taxes and fees.

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

Google interface language (<code>hl</code>): <code>en-US</code>, <code>fr</code>, <code>de</code>, <code>ja</code>…

## `monitorMode` (type: `string`):

For scheduled runs. The Actor remembers the lowest nightly price of each hotel stay between runs.<br>• <b>off</b>: no memory.<br>• <b>changes</b>: only stays seen for the first time or whose price moved.<br>• <b>drops</b>: only price drops (and stays under the target price). Unchanged stays are neither returned nor charged.

## `dropThresholdPercent` (type: `number`):

In <b>drops</b> mode, ignore drops smaller than this percentage.

## `targetPrice` (type: `number`):

Optional. A stay whose lowest nightly price falls to or under this amount (in the chosen currency) is returned as a <code>target-price</code> alert.

## `monitorKey` (type: `string`):

Optional. Runs with the same name share one price memory. Empty: the memory is tied to this exact list of hotels, searches and dates.

## `webhookUrl` (type: `string`):

Optional. At the end of a run that returned something, the Actor POSTs a JSON summary with the alerts. It carries <code>text</code> and <code>content</code> fields, so a Slack or Discord incoming webhook URL works as is.

## `proxyConfiguration` (type: `object`):

Apify Proxy (datacenter) is enough. A page Google refuses is retried on a fresh IP, then through residential proxies at no extra charge to you.

## Actor input object example

```json
{
  "hotels": [
    "New York Marriott Marquis"
  ],
  "maxHotelsPerSearch": 20,
  "includeOffers": false,
  "checkInInDays": 30,
  "nights": 1,
  "dateCount": 1,
  "adults": 2,
  "childrenAges": [],
  "currency": "USD",
  "country": "US",
  "language": "en-US",
  "monitorMode": "off",
  "dropThresholdPercent": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with hotel-price, hotel-listing and status rows.

# 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 = {
    "hotels": [
        "New York Marriott Marquis"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("alexmorain/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 = {
    "hotels": ["New York Marriott Marquis"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("alexmorain/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 '{
  "hotels": [
    "New York Marriott Marquis"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call alexmorain/google-hotels-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alexmorain/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/waZyJhQa2m7LRTC9Q/builds/rTDOfjKOefvaYwhTW/openapi.json
