# Google Hotels Scraper — Prices, OTA Rates & Reviews (`crawloop/google-hotels-scraper`) Actor

Scrape Google Hotels for live nightly prices, guest ratings, amenities, GPS, and optional OTA rate ladders. Search any city or hotel. Export JSON via Python, Node.js, or Apify MCP — a Google Hotels API alternative.

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

## Pricing

from $2.59 / 1,000 hotel scrapeds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Google Hotels Scraper — Prices, OTA Rates & Reviews

> **Disclaimer:** Unofficial tool for publicly visible Google Hotels / Google Travel search results. **Google** and **Google Hotels** are trademarks of Google LLC. Not affiliated with, sponsored by, or endorsed by Google. For informational, research, rate-shopping, and market-analysis use only. Respect applicable terms of use and law.

**Google Hotels scraper** for public hotel search — a practical **Google Hotels API alternative**. Give it a **city, neighborhood, or hotel query** plus **check-in / check-out dates**. Export **lead nightly prices**, **star class**, **guest ratings**, **review counts**, **GPS**, **amenities**, photos, and optional **OTA rate ladders** (the Booking / Expedia / Hotels.com-style sources Google already shows) as a JSON dataset. Call from **Python**, **Node.js**, **cURL**, or **Apify MCP** / AI assistants.

Built for **hotel revenue managers**, **OTA / metasearch analysts**, **travel-tech builders**, and **ADR researchers**. No Google account and no official Hotel Center access required.

| Google Hotels (OTA rate shop) | Airbnb occupancy (STR calendars) | Idealista (long-term rentals) |
| :--- | :--- | :--- |
| **Google Hotels Scraper** ◄── you are here | [Airbnb Occupancy Scraper](https://apify.com/crawloop/airbnb-occupancy-monitor) | [Idealista Scraper](https://apify.com/crawloop/idealista-scraper) |

### When to use this Actor

- You need a **Google Hotels scraper** / **Google Travel hotel scraper** that returns structured JSON
- You want **live prices for a destination and stay dates**, not a static hotel directory
- You compare **OTA prices** Google already aggregates, without Booking.com or Expedia partner APIs
- You want to **scrape Google Hotels with Python**, **Node.js**, or **MCP** and export a dataset

### When not to use this Actor

- **Official Google Hotel Ads / Travel Partner APIs** — those are for approved chains and OTAs submitting their own rate feeds
- **Guaranteed last-room inventory** — Google shows public comparison prices; checkout on the OTA can still differ
- **Full city dumps of thousands of hotels in one run** — cap with `maxItems` and split queries (neighborhood, star class)
- **Short-term rental occupancy calendars** — use [Airbnb Occupancy Scraper](https://apify.com/crawloop/airbnb-occupancy-monitor)

### Key Features

- **Destination search** — `hotels in Paris`, `Tokyo 4-star hotels`, or a city in `location`
- **Stay dates** — check-in / check-out encoded the same way Google Travel's own URLs encode them
- **Lead price + rating** — nightly rate, currency, deal badge, overall rating, review count, star class
- **GPS, photos, amenities, nearby places** from the public search card
- **Optional OTA ladder** — `includeDetails` fetches the property page for per-vendor prices and room names when Google exposes them
- **Exact property tokens** — paste a Google Hotels entity token or entity URL
- **Vacation rentals toggle** — search holiday rentals on the same Google Hotels index
- **Price monitor** — scheduled runs attach `monitor.priceChange` vs the previous run
- **HTTP path** — Chrome TLS impersonation, no Playwright
- **MCP / AI ready** — call from assistants via Apify MCP

### Use Cases

| Use case | What you get |
| :--- | :--- |
| **Comp-set rate shop** | Lead nightly prices for hotels in a city on chosen dates |
| **OTA ladder** | Per-source prices Google shows (Booking, Expedia, Hotels.com, …) |
| **ADR / market snapshot** | Ratings, stars, GPS, amenities for a destination |
| **Travel-tech MVP** | JSON hotel inventory without a Hotel Center partnership |
| **Scheduled monitor** | Price deltas on the same query and dates vs last run |
| **STR vs hotel mix** | Hotels here, then Airbnb occupancy on the sibling Actor |

### Quick Start

```json
{
  "searchQueries": ["hotels in Paris"],
  "checkInDate": "2026-09-11",
  "checkOutDate": "2026-09-12",
  "adults": 2,
  "currency": "EUR",
  "country": "fr",
  "maxItems": 20,
  "includeDetails": false
}
```

**OTA ladder (extra request per hotel):**

```json
{
  "searchQueries": ["hotels in Prague"],
  "checkInDate": "2026-10-01",
  "checkOutDate": "2026-10-03",
  "includeDetails": true,
  "maxItems": 10
}
```

### Input

| Field | Description |
| :--- | :--- |
| `searchQueries` | Destinations or hotel keywords (or entity tokens) |
| `location` | City used when queries are empty (`hotels in {location}`) |
| `startUrls` | Google Hotels search or entity URLs |
| `checkInDate` / `checkOutDate` | `YYYY-MM-DD` stay window |
| `adults` / `children` | Occupancy (Google default is 2 adults) |
| `currency` / `language` / `country` | `curr`, `hl`, `gl` — set `country` to match the currency market |
| `maxItems` | Row cap (first search page is typically ~20 organic hotels) |
| `sortBy` | Empty = relevance; `3` lowest price; `8` highest rating; `13` most reviewed |
| `minPrice` / `maxPrice` / `minRating` / `hotelClass` | Post-filters on scraped rows |
| `vacationRentals` | Search vacation rentals instead of hotels |
| `includeDetails` | Fetch OTA ladder + rooms on the entity page |
| `includeAds` | Keep sponsored hotels (`isAd=true`) |
| `monitorMode` | Attach price-change vs previous run |
| `proxyConfiguration` | Optional; residential if consent/empty results |

### Output

One dataset row per hotel.

| Field | Description |
| :--- | :--- |
| `name` | Property name |
| `starRating` / `hotelClass` | Official stars and label when Google shows them |
| `overallRating` / `reviewCount` | Guest rating and volume |
| `pricePerNight` / `pricePerNightDisplay` / `currency` | Lead nightly rate |
| `checkInDate` / `checkOutDate` / `nights` | Stay window used for the price |
| `gpsLatitude` / `gpsLongitude` | Coordinates |
| `amenities` / `images` / `nearbyPlaces` | Search-card extras |
| `propertyToken` / `entityUrl` / `cid` | Google identity |
| `bookingSources` | Per-OTA prices (when `includeDetails`) |
| `rooms` | Per-room rates when the mobile entity page includes them |
| `vendorCount` | How many booking sources Google listed |
| `monitor` | Previous price + delta when `monitorMode` is on |

```json
{
  "type": "hotel",
  "name": "Hôtel Mercure Paris Porte d'Orléans",
  "starRating": 4,
  "overallRating": 4,
  "reviewCount": 1710,
  "pricePerNight": 85.06,
  "pricePerNightDisplay": "$85",
  "currency": "USD",
  "checkInDate": "2026-09-11",
  "checkOutDate": "2026-09-12",
  "nights": 1,
  "gpsLatitude": 48.81763,
  "gpsLongitude": 2.3292313,
  "propertyToken": "ChgIk_yPrdu8xKuuARoLL2cvMXY4Z2JiOTIQAQ",
  "vendorCount": 12,
  "searchQuery": "hotels in Paris"
}
```

With `includeDetails: true`, `bookingSources` looks like:

```json
{
  "bookingSources": [
    { "vendorName": "Booking.com", "ratePerNight": 85, "ratePerNightDisplay": "$85" },
    { "vendorName": "Expedia", "ratePerNight": 89, "ratePerNightDisplay": "$89" }
  ]
}
```

### Integration examples

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('crawloop/google-hotels-scraper').call({
  searchQueries: ['hotels in Paris'],
  checkInDate: '2026-09-11',
  checkOutDate: '2026-09-12',
  currency: 'EUR',
  country: 'fr',
  maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("crawloop/google-hotels-scraper").call(run_input={
    "searchQueries": ["hotels in Paris"],
    "checkInDate": "2026-09-11",
    "checkOutDate": "2026-09-12",
    "currency": "EUR",
    "country": "fr",
    "maxItems": 20,
})
for hotel in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(hotel["name"], hotel.get("pricePerNight"), hotel.get("currency"))
```

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/crawloop~google-hotels-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchQueries":["hotels in Paris"],"checkInDate":"2026-09-11","checkOutDate":"2026-09-12","currency":"EUR","country":"fr","maxItems":20}'
```

### MCP and AI assistants

Use this Actor from AI tools via [Apify MCP](https://docs.apify.com/platform/integrations/mcp). Connect your Apify account, then call this Actor by its Store ID / name (`crawloop/google-hotels-scraper`).

Example prompts:

- "Run Google Hotels Scraper for hotels in Paris, check-in 2026-09-11, check-out 2026-09-12, EUR, country fr, max 20 rows, and return JSON"
- "Scrape 4-star hotels in Lisbon for next Friday–Sunday and summarize lead prices, ratings, and GPS"
- "Chain Google Hotels Scraper then Airbnb Occupancy Scraper for the same city to compare hotel ADR vs STR occupancy"

### Suite next step

After hotel rates, pull short-term rental occupancy for the same destination with [Airbnb Occupancy Scraper](https://apify.com/crawloop/airbnb-occupancy-monitor). For long-term listings in Spain, Italy, or Portugal, use [Idealista Scraper](https://apify.com/crawloop/idealista-scraper).

### FAQ

**Does Google Hotels have a public API?**\
No self-serve API returns the public comparison results visitors see. Hotel Ads / Travel Partner APIs are for approved partners submitting their own feeds. This Actor is a **Google Hotels API alternative** that reads the public Travel search page.

**Do I need a Google login or API key?**\
No. You can scrape Google Hotels from **Python**, **Node.js**, **cURL**, or **MCP** with an Apify token only.

**How many hotels per search?**\
The first results page is typically about 20 organic properties. Raise `maxItems` only after you add more queries (neighborhoods, star class). Pagination beyond the first page is not guaranteed.

**Why are prices in USD when I asked for EUR?**\
Displayed currency follows Google's market: set both `currency` and `country` (`gl`) to the same region (for example `EUR` + `fr`), and use a matching proxy country when you enable Apify Proxy.

**Why enable a residential proxy?**\
Direct datacenter IPs often work. If you hit a consent interstitial or zero cards, switch the proxy to Apify RESIDENTIAL.

**Are OTA prices the final checkout price?**\
They are the public rates Google shows for your dates. The booking site can still change taxes, packages, or availability at checkout.

**Can I monitor the same hotels over time?**\
Yes. Turn on `monitorMode` and schedule the Actor. Each row gets a `monitor` object with the previous lead price and the delta.

### Related Actors

- [Airbnb Occupancy Scraper](https://apify.com/crawloop/airbnb-occupancy-monitor) — STR calendars, occupancy %, booking pace
- [Idealista Scraper](https://apify.com/crawloop/idealista-scraper) — long-term listings ES/IT/PT
- [ImmobilienScout24 Scraper](https://apify.com/crawloop/immobilienscout24-scraper) — DE long-term listings

# Actor input Schema

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

Destinations or hotel keywords, one per line. Examples: hotels in Paris, Tokyo 4-star hotels, Bali resorts. You can also paste a Google Hotels entity token.

## `location` (type: `string`):

Optional city or area used when searchQueries is empty. Becomes a 'hotels in {location}' query.

## `startUrls` (type: `array`):

Google Hotels / Travel search URLs or /travel/hotels/entity/… property URLs.

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

Stay start in YYYY-MM-DD. Defaults to about two weeks from today, one night.

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

Stay end in YYYY-MM-DD. Must be after check-in.

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

Adult guests (1–9). Google's default is 2.

## `children` (type: `integer`):

Child guests (0–8).

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

ISO currency for displayed prices (USD, EUR, GBP, …).

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

Interface language, e.g. en, fr, de, es, ja.

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

Two-letter market code that also influences results, e.g. us, gb, fr, de.

## `maxItems` (type: `integer`):

Cap on hotel rows for the whole run (max 200). Google's first search page is typically ~20 organic properties.

## `sortBy` (type: `string`):

Leave empty for Google's default relevance. 3 = lowest price, 8 = highest rating, 13 = most reviewed.

## `minPrice` (type: `integer`):

Drop hotels cheaper than this (in the selected currency). Applied after scrape.

## `maxPrice` (type: `integer`):

Drop hotels more expensive than this. Applied after scrape.

## `minRating` (type: `number`):

Keep hotels with overallRating at least this value (e.g. 4.0).

## `hotelClass` (type: `integer`):

Keep hotels with official star rating at least this (2–5). Hostels without a class still pass.

## `vacationRentals` (type: `boolean`):

Search vacation rentals instead of hotels.

## `includeDetails` (type: `boolean`):

Fetch each hotel's entity page (mobile SSR) for per-vendor prices (Booking, Expedia, Hotels.com, …) and room names when Google exposes them. Extra request per hotel.

## `includeAds` (type: `boolean`):

Keep Google's paid hotel ads in the dataset (marked isAd=true).

## `monitorMode` (type: `boolean`):

Compare lead nightly price to the previous run on this Actor (same default key-value store) and attach monitor.priceChange.

## `detailConcurrency` (type: `integer`):

Parallel entity-page fetches when Include OTA rate ladder is on (1–8).

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

Residential proxy recommended on Apify if datacenter IPs hit a consent wall or empty results. Direct connection often works for Google Travel.

## Actor input object example

```json
{
  "searchQueries": [
    "hotels in Paris"
  ],
  "checkInDate": "2026-09-11",
  "checkOutDate": "2026-09-12",
  "adults": 2,
  "children": 0,
  "currency": "EUR",
  "language": "en",
  "country": "us",
  "maxItems": 20,
  "sortBy": "",
  "vacationRentals": false,
  "includeDetails": false,
  "includeAds": false,
  "monitorMode": false,
  "detailConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Default dataset items.

# 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 Paris"
    ],
    "checkInDate": "2026-09-11",
    "checkOutDate": "2026-09-12",
    "currency": "EUR",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawloop/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 Paris"],
    "checkInDate": "2026-09-11",
    "checkOutDate": "2026-09-12",
    "currency": "EUR",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("crawloop/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 Paris"
  ],
  "checkInDate": "2026-09-11",
  "checkOutDate": "2026-09-12",
  "currency": "EUR",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call crawloop/google-hotels-scraper --silent --output-dataset

```

## MCP server setup

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