# Google Hotels Scraper - Prices by Date, Ratings & Review Topics (`zet46/google-hotels-scraper`) Actor

Scrape Google Hotels for any city and dates: nightly price, total with taxes, OTA rates (Booking.com, Agoda, Expedia), per-room pricing, named amenities, hotel class, ratings, review topics, coordinates, website, photos. Any currency, no API key. $2 per 1,000 hotels.

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

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 Scraper: Hotel Prices by Date, Ratings & Review Topics

Get **hotel prices from Google Hotels for any destination and any dates**, in any currency. For every hotel you get the nightly price, the **total stay price with taxes and fees**, the star rating, the guest rating and review count, **what guests praise or complain about** (review topics), **the amenities** (Wi-Fi, breakfast, parking, pool, fitness, pets...), coordinates, nearby places, the hotel website and photos.

No API key, no browser, no login. Each search page loads in about 2 seconds, so **100 hotels take well under a minute**.

### What you can use it for

- **Rate shopping and revenue management**: check what competing hotels charge for the same nights.
- **Price monitoring**: schedule a run daily and track how prices change toward the stay date.
- **Travel apps, AI agents and chatbots**: real, current hotel prices and ratings for any city.
- **Market research**: hotel supply, price levels and guest sentiment per city or neighbourhood.
- **Lead lists for the hospitality industry**: hotel names, websites, class and location.

### Input

| Field | Example | Notes |
|---|---|---|
| `queries` | `["Paris", "resorts in Bali", "hotels near Times Square"]` | A plain city name becomes "hotels in Paris" |
| `hotelUrls` | `["https://www.google.com/travel/hotels/entity/..."]` | Track specific hotels by URL (see below). Use with or instead of `queries`. |
| `checkIn` | `2026-11-20` | Default: 14 days from today |
| `checkOut` | `2026-11-22` | Default: one night after check-in |
| `adults`, `children`, `rooms` | `4`, `2`, `2` | Party size. Google only shows hotels that fit (6 adults won't see the 2-person rooms) |
| `childrenAges` | `[5, 10]` | Optional ages for per-age pricing; its length overrides `children` |
| `currency` | `USD`, `EUR`, `GBP`, `JPY`, `VND` | Any ISO code Google supports |
| `maxHotelsPerQuery` | `40` | Up to 1000; about 18 new hotels per page |
| `onlyWithPrice` | `false` | Skip, and don't pay for, hotels without a price for your dates |
| `maxPricePerNight`, `minPricePerNight` | `150`, `50` | Price band; hotels outside the band are skipped and not charged |
| `minHotelClass` | `4` | Keep only hotels with at least this many stars (1-5) |
| `minRating` | `4.0` | Keep only hotels whose Google guest rating is at least this high |
| `includeProviderPrices` | `true` | Add the price from every booking site and the official website (see below) |
| `includeOtaReviews` | `true` | Add per-site review aggregates (Tripadvisor, Trip.com) and Google's typical nightly price band (see below) |
| `language`, `country` | `en`, `us` | Google interface language and country |

```json
{
  "queries": ["Paris", "Da Nang"],
  "checkIn": "2026-11-20",
  "checkOut": "2026-11-22",
  "adults": 2,
  "children": 1,
  "childrenAges": [8],
  "rooms": 1,
  "currency": "USD",
  "minHotelClass": 4,
  "minRating": 4.2,
  "maxHotelsPerQuery": 40
}
```

### Provider prices: Booking.com, Agoda, Expedia, Trip.com, the official site...

Turn on `includeProviderPrices` to get, for every hotel, the full list of booking sites Google compares, cheapest first, with direct booking links:

```json
"providers": [
  {"provider": "Generator Paris", "pricePerNight": 68.96, "pricePerNightText": "$69", "totalPrice": 137.92, "sponsored": false, "bookingUrl": "https://..."},
  {"provider": "Booking.com", "pricePerNight": 80.09, "pricePerNightText": "$80", "totalPrice": 160.18, "sponsored": false, "bookingUrl": "https://..."},
  {"provider": "Agoda", "pricePerNight": 159.3, "pricePerNightText": "$159", "totalPrice": 318.59, "sponsored": false, "bookingUrl": "https://..."},
  {"provider": "Trip.com", "pricePerNight": 218.5, "pricePerNightText": "$219", "totalPrice": 437.01, "sponsored": false, "bookingUrl": "https://..."}
],
"cheapestProvider": "Generator Paris"
```

This is what you need for **rate parity checks**: is the hotel cheaper on its own website or on an OTA?

### OTA review aggregates and the typical price band

Turn on `includeOtaReviews` to pull extra signal from each hotel's Google page:

- **Reviews from every travel site Google tracks** — Tripadvisor, Trip.com and other OTAs — with the aggregate rating, total review count, a direct link to the full review page, and one recent sample review (author, time, stars, full text and a shorter snippet). Combine with the Google rating already in `rating` / `reviewsCount` to see where guests land across platforms.
- **Google's typical nightly price** for the dates and party you queried: a `priceRange` with `minText`, `typicalText` and `maxText` (strings with the currency symbol). This is the band Google shows under *"this hotel typically costs between X–Y per night"* and tells you where the current price sits — a bargain, typical, or expensive.

```json
"otaReviews": [
  {"provider": "Tripadvisor", "rating": 4.5, "maxRating": 5, "reviewsCount": 1073,
   "hotelUrl": "https://www.tripadvisor.com/Hotel_Review-...",
   "sampleReview": {"author": "Eliz-K_1988", "time": "3 weeks ago", "stars": 1, "maxStars": 5,
                    "text": "As a loyal and regular guest of the hotel Ritz Paris, I am deeply shocked...",
                    "snippet": "As a loyal and regular guest of the hotel Ritz Paris, I am deeply...",
                    "link": "https://www.tripadvisor.com/ShowUserReviews-..."}},
  {"provider": "Trip.com", "rating": 4.3, "maxRating": 5, "reviewsCount": 45,
   "sampleReview": {"author": "Trip.com Member", "time": "10 months ago", "stars": 5, "maxStars": 5,
                    "text": "Excellent service and good experience during the days that passed...",
                    "link": "https://www.trip.com/hotels/detail?hotelid=4968739..."}}
],
"priceRange": {"minText": "€1,776", "typicalText": "€2,000", "maxText": "€2,404"}
```

The entity page is already fetched when `includeProviderPrices` is on, so turning this on at the same time costs nothing extra. Standalone, it adds about one second per hotel for the extra fetch.

### Track specific hotels every day

For daily price monitoring of a known set of hotels, use `hotelUrls`. Open the hotel on Google Travel, copy the URL (it looks like `https://www.google.com/travel/hotels/entity/...`) and paste it in. The actor fetches each hotel for your dates and returns the same row shape as a search, with `providers` when `includeProviderPrices` is on. Combine it with the Apify scheduler to build a price history for your competitors or your own hotels.

```json
{
  "hotelUrls": [
    "https://www.google.com/travel/hotels/entity/ChkIjozRxbD1k88WGg0vZy8xMWY4czFyNnJiEAE",
    "https://www.google.com/travel/hotels/entity/ChgIy_jSysWK04kvGgwvZy8xMWczNzJoMW0QAQ"
  ],
  "checkIn": "2026-11-20",
  "checkOut": "2026-11-22",
  "currency": "EUR",
  "includeProviderPrices": true
}
```

### Output

One row per hotel:

```json
{
  "position": 3,
  "name": "Crowne Plaza Paris - Republique by IHG",
  "hotelClass": 4,
  "rating": 4.1,
  "reviewsCount": 2995,
  "pricePerNight": 182,
  "pricePerNightText": "$182",
  "totalPrice": 437.91,
  "totalBeforeTaxes": 364.98,
  "totalTaxesAndFees": 0,
  "currency": "USD",
  "checkIn": "2026-11-20",
  "checkOut": "2026-11-22",
  "nights": 2,
  "latitude": 48.8674,
  "longitude": 2.3653,
  "checkInTime": "3:00 PM",
  "checkOutTime": "12:00 PM",
  "website": "https://www.ihg.com/crowneplaza/hotels/gb/en/paris/pardl/hoteldetail",
  "description": "Bright rooms in a modern lodging with a stylish restaurant, a bar & a furnished terrace.",
  "nearbyPlaces": [{"name": "The Centre Pompidou", "travelTime": "7 min"}],
  "reviewTopics": [
    {"topic": "Location", "mentions": 342, "positive": 301, "negative": 16, "positiveShare": 0.95},
    {"topic": "Service", "mentions": 341, "positive": 266, "negative": 61, "positiveShare": 0.813}
  ],
  "ratingDistribution": {"5": 1506, "4": 877, "3": 314, "2": 141, "1": 157},
  "images": ["https://lh3.googleusercontent.com/..."],
  "amenities": ["Wi-Fi (free)", "Air conditioning", "Breakfast (extra charge)", "Parking (extra charge)", "Restaurant", "Bar", "Pet-friendly (extra charge)", "Business center"],
  "amenitiesUnavailable": ["Pools", "Hot tub", "Fitness center", "Spa"],
  "searchQuery": "Paris",
  "googleHotelsUrl": "https://www.google.com/travel/hotels/entity/...",
  "mapsUrl": "https://www.google.com/maps?cid=...",
  "cid": "...",
  "scrapedAt": "2026-10-15T09:04:17+00:00"
}
```

Export as JSON, CSV, Excel or HTML, or read it through the Apify API and integrations (Make, Zapier, n8n, Google Sheets, webhooks).

### Pricing

**$2.00 per 1,000 hotels** ($0.002 per hotel), with no monthly fee. Provider prices add **$2.00 per 1,000 hotels**, charged only when you turn them on and a price list is found. You pay only for hotels that end up in your dataset. With `onlyWithPrice` turned on, hotels without a price are skipped and not charged. On the Apify free plan you can scrape about 2,500 hotels a month at no cost.

Need **one hotel's price for every date** (cheapest dates, price calendar, rate parity over time)? Use [Google Hotels Price Calendar](https://apify.com/zet46/google-hotels-price-calendar).

Looking for apartments, villas and houses instead of hotels? Use [Google Vacation Rentals Scraper](https://apify.com/zet46/google-vacation-rentals-scraper).

**Room rates:** for booking sites that list them (usually the hotel's own website and Booking.com), each provider also has a `rooms` list: room name, price per night and total. Use it to compare the same room type across sites.

### Use it from Python, JavaScript or any HTTP client

```python
from apify_client import ApifyClient  # pip install "apify-client>=3"

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("zet46/google-hotels-scraper").call(run_input={"queries": ["Paris"], "checkIn": "2026-12-10", "checkOut": "2026-12-12", "currency": "EUR", "maxHotelsPerQuery": 50})
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item["name"], item["pricePerNight"], item["currency"], item["rating"])
```

The same works with the JavaScript client (`apify-client` on npm) or a single HTTP call to `https://api.apify.com/v2/acts/zet46~google-hotels-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>` with the input as the JSON body. You can also schedule runs and send results to Google Sheets, Slack, Zapier, Make or n8n.

More ready-to-run examples (Python and Node.js): [github.com/huynhtanan/google-hotels-api](https://github.com/huynhtanan/google-hotels-api). Step-by-step tutorial: [Google Hotels prices with Python on dev.to](https://dev.to/huynhtanan/how-to-get-google-hotels-prices-for-any-dates-with-python-and-see-which-booking-site-is-cheapest-1aod).

### Daily price tracking (competitor monitoring)

Track your competitors' prices over time: run the actor on a daily schedule, store each snapshot, and alert when a price drops.

1. In Apify Console open the actor, click **Schedule actor**, pick a cron (e.g. daily at 09:00) and lock in the input (your competitor list in `hotelUrls` or `queries`, `checkIn`, `checkOut`, `currency`).
2. Pull the dataset into your own database with a few lines of Python:

```python
import os, sqlite3
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
## Get the dataset from the latest finished run and append it to SQLite
run = client.actor("zet46/google-hotels-scraper").last_run().get()
with sqlite3.connect("prices.sqlite3") as con:
    con.execute("CREATE TABLE IF NOT EXISTS prices (run_at TEXT, hotel TEXT, check_in TEXT, nightly REAL, PRIMARY KEY (run_at, hotel, check_in))")
    for h in client.dataset(run["defaultDatasetId"]).iterate_items():
        con.execute("INSERT OR REPLACE INTO prices VALUES (?,?,?,?)",
                    (run["startedAt"], h["name"], h["checkIn"], h.get("pricePerNight")))
```

A complete, ready-to-run version (prints how each hotel moved vs the previous observation) is here:
[github.com/huynhtanan/google-hotels-api/blob/main/python/track_prices.py](https://github.com/huynhtanan/google-hotels-api/blob/main/python/track_prices.py).
Full walkthrough with the SQL for drop alerts: [Daily price tracking for competitor hotels on dev.to](https://dev.to/huynhtanan/daily-price-tracking-for-competitor-hotels-with-python-and-sqlite-2nda).

You can also skip code and let Apify push each result to Google Sheets, Slack, Make, Zapier or n8n directly, via **Integrations** on the actor page.

### Use it from AI agents (MCP)

Add this to Claude Desktop, Cursor or any MCP client:

```json
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=zet46/google-hotels-scraper"}}}
```

Then just ask, for example: *"Find 4-star hotels in Lisbon under 150 EUR a night for 12-14 December"*

### FAQ

**Are the prices for my dates?** Yes. Prices come from Google Hotels for the exact check-in and check-out dates you set. `pricePerNight` is the nightly price Google shows. `totalPrice` is the whole stay including taxes and fees.

**Which currency?** Any currency Google supports. Set `currency` to `EUR`, `GBP`, `JPY` and so on.

**How many hotels can I get?** Large cities return hundreds of hotels per search. To cover a city more completely, add searches by area, for example `hotels in Le Marais, Paris`.

**Do I need proxies?** No setup needed. The actor uses Apify Proxy (datacenter) by default, which gives more complete results than direct requests, and the cost is included in the price.

**Is scraping Google Hotels legal?** The actor collects only publicly visible hotel listings and prices, with no personal data. You are responsible for how you use the data and for complying with the laws and terms that apply to you.

**Something missing or broken?** Open an issue on the Issues tab. Fixes usually ship within a day.

# Actor input Schema

## `queries` (type: `array`):

City, area or free-text Google Hotels search. 'Paris' becomes 'hotels in Paris'. You can also write 'resorts in Bali' or 'hotels near Times Square'. Leave empty if you only use hotelUrls.

## `hotelUrls` (type: `array`):

Paste one or more Google Hotels URLs (https://www.google.com/travel/hotels/entity/...) to scrape only those hotels for your dates. Perfect for daily price tracking of a known set of hotels. You can use this instead of 'queries', or alongside it.

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

YYYY-MM-DD. Default: 14 days from today.

## `checkOut` (type: `string`):

YYYY-MM-DD. Default: one night after check-in.

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

Number of adult guests. Google Hotels only shows hotels that fit your party, so a value of 6 skips rooms that cap at 4.

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

Number of children. For age-aware pricing, use childrenAges instead (that field also sets this count).

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

List of child ages (0 to 17). Overrides 'children' with its length; some booking partners price per age.

## `rooms` (type: `integer`):

Number of rooms needed. Rooms + adults together drive the Google Hotels capacity filter.

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

ISO currency code, e.g. USD, EUR, GBP, JPY, VND.

## `maxHotelsPerQuery` (type: `integer`):

Google shows about 18 new hotels per page. Up to 1000.

## `onlyWithPrice` (type: `boolean`):

Skip hotels that show no price for your dates (sold out or no partner offers). Skipped hotels are not charged.

## `maxPricePerNight` (type: `integer`):

Skip (and don't charge for) hotels above this nightly price, in the chosen currency.

## `minPricePerNight` (type: `integer`):

Skip (and don't charge for) hotels below this nightly price. Pair with maxPricePerNight for a price band.

## `minHotelClass` (type: `integer`):

Keep only hotels with at least this star rating (1-5). Hotels with no class (hostels, apartments) are dropped when set.

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

Keep only hotels whose Google guest rating is at least this value (0-5). Hotels with no rating are dropped when set.

## `includeProviderPrices` (type: `boolean`):

Also open each hotel's price list and return the price from every booking site and the hotel's own website, cheapest first, with direct booking links. Adds $0.002 per hotel and about 1 second per hotel.

## `includeOtaReviews` (type: `boolean`):

Also return the per-site review summary from the hotel's Google page: Tripadvisor / Trip.com rating and review count, one sample review, plus Google's 'typical nightly price' band (min / typical / max) for your dates. Fetches the entity page too; free if includeProviderPrices is already on, otherwise adds about 1 second per hotel.

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

Google interface language (hl), e.g. en, de, fr, ja.

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

Google country (gl), e.g. us, gb, de. Affects which booking partners and prices Google shows.

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

Apify Proxy (datacenter) is used by default: it returns more complete data than direct requests. You normally don't need to change this.

## Actor input object example

```json
{
  "queries": [
    "Paris",
    "hotels near Times Square, New York"
  ],
  "adults": 2,
  "children": 0,
  "rooms": 1,
  "currency": "USD",
  "maxHotelsPerQuery": 40,
  "onlyWithPrice": false,
  "includeProviderPrices": false,
  "includeOtaReviews": false,
  "language": "en",
  "country": "us",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All scraped hotels as JSON items (one item per hotel).

## `hotelsCsv` (type: `string`):

The same hotels as a CSV file.

# 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 = {
    "queries": [
        "Paris",
        "hotels near Times Square, New York"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

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

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

```

## MCP server setup

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