# Google Hotels Rate Shopper — Compare OTA Prices & Rate Parity (`cleancut/google-hotels-price-comparator`) Actor

Compare a hotel's price on every booking site Google Hotels shows (Booking.com, Expedia, Hotels.com, Trip.com, official site…) for your dates. Cheapest seller, taxes & fees, free cancellation and rate-parity gaps.

- **URL**: https://apify.com/cleancut/google-hotels-price-comparator.md
- **Developed by:** [Cleancut Data](https://apify.com/cleancut) (community)
- **Categories:** Travel, Business, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.69 / 1,000 hotel rate comparisons

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

## Google Hotels Rate Shopper — Compare OTA Prices & Rate Parity

See **what every booking site charges for the same hotel and dates** — Booking.com, Expedia, Hotels.com, Trip.com, Priceline, Agoda, the hotel's **official website** and dozens more — exactly as Google Hotels shows them. Get the **cheapest seller**, totals with **taxes & fees**, **free-cancellation** deadlines and **rate-parity gaps** for any list of hotels and dates.

### Who is it for?

- 🏨 **Hotel revenue managers** — rate shopping for your property and your comp set, daily or for key dates (holidays, events).
- 🔍 **Rate-parity monitoring** — catch OTAs selling below your official rate (`cheapestVsOfficialSitePercent`).
- 🧳 **Travel agencies, TMCs & travel apps** — find the cheapest place to book a specific hotel.
- 📊 **Analysts & researchers** — price dynamics across sellers, nights ahead and seasons.

### Features

- **Every seller in one row**: name, price per night and total, with and without taxes, all-in flag and free cancellation (with deadline when Google's date is consistent with your stay; the raw text is kept in `freeCancellationRaw`).
- **Summary metrics**: cheapest seller & total, most expensive seller, price spread %, official-site price and whether it's the cheapest.
- **Stay breakdown**: base, taxes, fees and total for Google's lead rate.
- **Date scanning**: give one date and `scanDays: 30` to get a month of daily prices per hotel.
- **Guests & currency**: adults, children's ages, any currency, point-of-sale country.
- **Hotel profile included**: stars, rating, reviews, address, phone, website, coordinates, check-in/out times, amenities, photo, place ID.
- **Date validation built-in**: Google silently falls back to default dates when it can't price a stay; this Actor checks Google's echo and reports `DATES_NOT_PRICED` instead of giving you a wrong price.

### How to add hotels

Any of these work in **Hotels**:

| Input | Example |
|---|---|
| Google Hotels link | `https://www.google.com/travel/hotels/entity/ChoIt63CuaSrqoq0ARoNL2cvMTFmMXN3NzY5dxAB` |
| Google Maps link of the hotel | `https://www.google.com/maps/place/…/data=…!1s0x5370ca3b2e2fb8bf:0x99e9a92cf4f6ce…` |
| Google place ID | `ChIJv7gvLjvKcFMRzvb0LKnpmQA` |
| Maps CID | `43322584249726670` or `https://maps.google.com/?cid=43322584249726670` |

Need a whole city? Run a Google Maps scraper for “hotels in <city>”, then paste the place IDs here.

### Input example

```json
{
  "hotels": [
    "https://www.google.com/travel/hotels/entity/ChoIt63CuaSrqoq0ARoNL2cvMTFmMXN3NzY5dxAB",
    "ChIJv7gvLjvKcFMRzvb0LKnpmQA"
  ],
  "checkInDates": ["2026-12-31"],
  "nights": 2,
  "scanDays": 0,
  "adults": 2,
  "currency": "USD",
  "country": "us",
  "includeOffers": true
}
```

### Output example

```json
{
  "status": "ok",
  "hotelName": "Fairmont Banff Springs",
  "checkIn": "2026-12-31",
  "checkOut": "2027-01-02",
  "nights": 2,
  "currency": "USD",
  "cheapestSeller": "Fairmont Banff Springs",
  "cheapestTotal": 3344.33,
  "mostExpensiveSeller": "Qantas Hotels",
  "priceSpreadPercent": 189.44,
  "officialSiteTotal": 3344.33,
  "officialSiteIsCheapest": true,
  "cheapestVsOfficialSitePercent": 0,
  "freeCancellationSellers": ["Closest Hotel", "Luxury Escapes", "Expedia.com", "Orbitz.com", "Travelocity.com", "CheapTickets.com", "eDreams", "Tripadvisor.com", "Bluepillow.com", "Priceline", "Booking.com"],
  "offersCount": 15,
  "offers": [
    {
      "seller": "Expedia.com",
      "partnerId": "89",
      "isOfficialSite": false,
      "priceBasis": "split",
      "pricePerNight": 4352.5,
      "pricePerNightWithTaxes": 4825.5,
      "totalPrice": 8705,
      "totalPriceWithTaxes": 9651,
      "freeCancellation": true,
      "freeCancellationUntil": null,
      "freeCancellationRaw": "Jun 14 6:00 PM"
    }
  ],
  "hotelClass": 5,
  "rating": 4.7,
  "reviewsCount": 17766,
  "address": "405 Spray Ave, Banff, AB T1L 1J4, Canada",
  "googleHotelsUrl": "https://www.google.com/travel/hotels/entity/CgkIzu3T55K1-kwQAQ?hl=en&gl=us&ts=…"
}
```

`priceBasis: "all-in"` marks sellers that only publish one figure (taxes and fees included); they are compared on the with-taxes basis.

#### Output views

The Output tab (and the API, with `?view=`) offers ready-made tables:

| View | What you get |
|---|---|
| **Rate comparison** | One row per hotel and date: cheapest seller, official site, parity gap, spread |
| **Offers by seller** | One row per booking site, cheapest first: the rate-parity table |
| **Rate parity** | Official website against the cheapest seller, with free-cancellation sellers |
| **Stay price breakdown** | Base, taxes, fees and total for the stay |
| **Hotel details** | Stars, rating, reviews, contact, location, check-in times, amenities |
| **Errors (free)** | Why a hotel or date could not be priced |

Every field is documented in the dataset schema (type, description and example). A run summary is saved as `SUMMARY` in the key-value store.

### Errors (free)

| errorCode | Meaning |
|---|---|
| `DATES_NOT_PRICED` | Google could not price those dates (past, > ~330 days, > 30 nights) and fell back to other dates |
| `UNKNOWN_HOTEL` | The link/ID is not a hotel Google Hotels knows |
| `INVALID_HOTEL_REFERENCE` | The input could not be understood |
| `CONSENT_REQUIRED` | Google showed an EU cookie page — use a US proxy |
| `BLOCKED` / `RATE_LIMITED` | Google throttled the requests — lower parallelism or use RESIDENTIAL proxy |

### Pricing

Pay per event — **one charge per hotel × check-in date**, with **every seller included** (no extra charge per offer). Errors are free.

| Your Apify plan | Price per 1,000 hotel × date results |
|---|---:|
| Free | $0.99 |
| Starter (Bronze) | $0.89 |
| Scale (Silver) | $0.79 |
| Business (Gold) and above | $0.69 |

Plus Apify's standard start fee of $0.00005 per run. Example: your hotel + 9 competitors, every day for the next 30 days = 300 results ≈ **$0.21–$0.30**. Cap spending with **Max results in total** or the run's maximum cost.

### Responsible scraping

This Actor only reads Google Hotels **hotel pages** (`/travel/hotels/entity/…`), which `google.com/robots.txt` allows. It never requests the disallowed search (`/travel/search`) or click-out (`/travel/clk`) paths, and it never follows redirects to them.

### FAQ

**Can I search a whole city?** Not directly (Google's hotel search pages are disallowed by robots.txt). Use a Google Maps scraper to get the hotels' place IDs and paste them here.

**Why is the official site sometimes much cheaper or pricier?** Sellers can quote different room types or rate plans (e.g. non-refundable). Use the offer list to inspect each seller.

**How many rooms?** One room per query (Google Hotels' default).

### Changelog

- **0.2** — Cleaner input with sections, children's ages as a simple list, 6 output views (offers by seller, rate parity, stay breakdown, hotel details, errors) and a fully documented output schema.
- **0.1** — First release: OTA price comparison, rate-parity metrics, date scanning, guests & currency, hotel profile.

### More from Cleancut Data

- 🎬 **[YouTube Transcript Scraper](https://apify.com/cleancut/youtube-transcript-scraper)**: transcripts in bulk from videos, channels, playlists and search, with SRT/VTT, AI-ready chunks, likes and publish dates.
- ✈️ **[Google Flights Cheapest Fares](https://apify.com/cleancut/google-flights-cheapest-fares)**: the cheapest Google Flights fare per route and date, the cheapest day of the month and price-drop alerts. Pair it with this Actor for flight + hotel quotes.

# Actor input Schema

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

Google Hotels links (…/travel/hotels/entity/…), Google Maps links of the hotel, Google place IDs (ChIJ…) or Maps CIDs. Tip: get place IDs in bulk with a Google Maps scraper.

## `checkInDates` (type: `array`):

Dates in YYYY-MM-DD format. Google Hotels prices stays up to ~330 days ahead. Leave empty to check tomorrow.

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

Length of stay for every check-in date (1–30).

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

Also check every day for N days starting from the first check-in date (or tomorrow). Example: 30 = a full month of daily prices per hotel. 0 = off.

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

Number of adults (one room).

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

One age per line (0–17), e.g. 5 and 10 for two children. Leave empty for no children.

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

ISO currency code for prices (USD, EUR, GBP, MXN, BRL…).

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

Two-letter country code used as Google's point of sale (gl), e.g. us, gb, es, mx.

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

Add the full list of sellers with nightly and total prices, taxes basis and free-cancellation deadline. Turn off to keep only the summary (cheapest, spread, official site).

## `maxTotalResults` (type: `integer`):

Stop after this many hotel × date results (0 = no limit). Useful to cap the cost of a run.

## `maxConcurrency` (type: `integer`):

Hotel × date pages fetched at the same time. Keep it low to avoid rate limits.

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

Use a US proxy to avoid Google's EU cookie-consent page. Switch to RESIDENTIAL only if you see BLOCKED errors.

## Actor input object example

```json
{
  "hotels": [
    "https://www.google.com/travel/hotels/entity/ChoIt63CuaSrqoq0ARoNL2cvMTFmMXN3NzY5dxAB"
  ],
  "checkInDates": [
    "2026-12-31"
  ],
  "nights": 1,
  "scanDays": 0,
  "adults": 2,
  "childrenAges": [],
  "currency": "USD",
  "country": "us",
  "includeOffers": true,
  "maxTotalResults": 0,
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `rates` (type: `string`):

All dataset items: cheapest and most expensive seller, official site price, parity gap, spread, offers and free error rows.

## `offers` (type: `string`):

One row per booking site for each hotel and date (rate-parity view), cheapest first.

## `summary` (type: `string`):

JSON record with the number of hotel × date queries, priced results and errors by code.

# 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": [
        "https://www.google.com/travel/hotels/entity/ChoIt63CuaSrqoq0ARoNL2cvMTFmMXN3NzY5dxAB"
    ],
    "checkInDates": [
        "2026-12-31"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("cleancut/google-hotels-price-comparator").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": ["https://www.google.com/travel/hotels/entity/ChoIt63CuaSrqoq0ARoNL2cvMTFmMXN3NzY5dxAB"],
    "checkInDates": ["2026-12-31"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("cleancut/google-hotels-price-comparator").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": [
    "https://www.google.com/travel/hotels/entity/ChoIt63CuaSrqoq0ARoNL2cvMTFmMXN3NzY5dxAB"
  ],
  "checkInDates": [
    "2026-12-31"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyCountry": "US"
  }
}' |
apify call cleancut/google-hotels-price-comparator --silent --output-dataset

```

## MCP server setup

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

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/18BfXH2MTE5rWWhRb/builds/oLvv5eCLqflc11pGN/openapi.json
