# Google Hotels API & Scraper — Prices, Ratings, Reviews (`westerly_breaker/google-hotels-scraper`) Actor

Google Hotels prices for your dates, guests and currency, plus star class, rating breakdown, review topics, coordinates, nearby places and links. Up to 1000 properties per location, no browser, automatic retries.

- **URL**: https://apify.com/westerly_breaker/google-hotels-scraper.md
- **Developed by:** [Daniel Posztos](https://apify.com/westerly_breaker) (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 $0.01 / 1,000 dataset items

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 API & Scraper — Prices, Ratings & Reviews

**SEO title:** Google Hotels API — hotel prices, ratings & reviews
**SEO description:** Google Hotels API, no Google API key needed: price per night and total stay for your dates, guests and currency, plus star class, ratings, review topics and links. Up to 1000 hotels per city.

A Google Hotels API you can call from Python, JavaScript, any HTTP client or an AI agent. Give it one or more places and your stay dates, and get every property Google Hotels lists, one row each:

- **Price for your stay**: per night and total, in the currency you choose, for your number of guests
- **Quality signals**: star class, guest rating, review count, the full 1-5 star breakdown, and what guests talk about (service, location, cleanliness, breakfast...)
- **Where it is**: coordinates, country, nearby landmarks, transit and airports with travel times
- **Links**: Google Maps, the property's Google Hotels page, its own website, photos

Up to 1000 properties per location, no browser.

### Why this exists

Google Hotels compares prices from dozens of booking sites, but it has no API, and the existing scrapers fail a lot (the most-used one failed on ~47% of its runs over the last 30 days). This actor reads the same data the Google Hotels page is built from:

- **Your dates, guests and currency actually apply.** Google ignores the usual `checkin=` / `curr=` URL parameters and quietly falls back to "tonight, in the currency of the server's IP". This actor encodes the stay the way the Google Hotels web app does, so you get the prices you asked for.
- **Deep pagination, no duplicates.** It follows Google's own page tokens and drops properties that repeat across pages.
- **Fast and resilient:** the first attempt goes out directly, and when Google answers with an error, a consent wall or a captcha, the retry goes through a fresh proxy session.

Cloud test (Budapest, New York, Tokyo; 2 nights; EUR; 100 per city): 300 properties from 18 requests, no retries needed, under 2 minutes, all prices in EUR, no duplicates. Deep test: 1000 Budapest properties from 54 pages in 2.5 minutes.

### Input

| Field | What it does | Default |
|---|---|---|
| `locations` | Places to search, e.g. `["Budapest"]`, `["Times Square, New York"]` | — |
| `checkInDate` / `checkOutDate` | `YYYY-MM-DD`, max 30 nights | 14 days from today, 1 night |
| `adults` | 1-10 guests | `2` |
| `currency` | ISO code: `USD`, `EUR`, `GBP`, `HUF`... | `USD` |
| `maxResultsPerLocation` | 1-1000 | `50` |
| `onlyAvailable` | Skip properties without a price for your dates (not charged) | `false` |
| `language` | e.g. `en-US`, `de`, `hu` | `en-US` |
| `countryCode` | Country the search comes from (`gl`), e.g. `us`, `de` | `us` |
| `proxyConfiguration` | Proxy used for retries (the first attempt goes out directly) | Apify Proxy |

#### Worked example — input

```json
{
  "locations": ["Budapest"],
  "checkInDate": "2026-11-20",
  "checkOutDate": "2026-11-22",
  "currency": "USD",
  "maxResultsPerLocation": 100
}
```

#### Worked example — output (one row, real data, lists shortened)

```json
{
  "name": "Eurostars Ambassador",
  "location": "Budapest",
  "available": true,
  "hotelClass": "4-star hotel",
  "starRating": 4,
  "rating": 4.7,
  "reviewCount": 820,
  "ratingDistribution": {"5": 661, "4": 104, "3": 29, "2": 4, "1": 22},
  "price": {
    "nightly": "$139",
    "nightlyValue": 138.88,
    "total": "$278",
    "totalValue": 277.76,
    "currency": "USD",
    "cheapestProvider": null,
    "dealBadge": null
  },
  "latitude": 47.5052944,
  "longitude": 19.0648532,
  "countryCode": "HU",
  "checkInTime": "3:00 PM",
  "checkOutTime": "12:00 PM",
  "description": "Chic quarters in a polished hotel featuring a restaurant, a bar & a 24/7 gym, plus a sauna.",
  "reviewTopics": [{"topic": "Service", "mentions": 118}, {"topic": "Breakfast", "mentions": 56}, "..."],
  "nearby": [{"name": "Oktogon", "travelTimes": ["3 min"]}, {"name": "Budapest Ferenc Liszt International Airport", "travelTimes": ["32 min", "47 min"]}, "..."],
  "website": "https://www.eurostarsambassador.com/...",
  "thumbnail": "https://lh3.googleusercontent.com/...",
  "images": ["https://lh3.googleusercontent.com/...", "..."],
  "googleMapsUrl": "https://www.google.com/maps?cid=...",
  "googleHotelsUrl": "https://www.google.com/travel/hotels/entity/...",
  "propertyToken": "...",
  "placeId": "0x...:0x...",
  "checkInDate": "2026-11-20",
  "checkOutDate": "2026-11-22",
  "nights": 2,
  "adults": 2,
  "position": 4,
  "hasData": true,
  "scrapedAt": "2026-10-12T14:45:53Z"
}
```

### Output notes

- **`price.nightly` / `nightlyValue`** is the lowest price per night Google shows. **`total` / `totalValue`** is for the whole stay, including taxes and fees where Google includes them.
- **`available: false`, `price: null`** means Google shows the property but has no price for your dates (sold out, or no booking partner). Set `onlyAvailable: true` to skip these.
- **`cheapestProvider`** and **`dealBadge`** (e.g. `GREAT PRICE`) are filled only when Google shows them on the results page. That's mostly for vacation rentals.
- **`position`** is the rank within the location's results, after duplicates are removed.
- Results mix hotels and vacation rentals, the same as on Google Hotels. `hotelClass` is null for rentals.
- A location that fails or finds nothing appears as one row with `hasData: false` and an `error`. That row is not charged.

### Use it from code or an AI agent

```bash
curl -X POST "https://api.apify.com/v2/acts/westerly_breaker~google-hotels-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"locations": ["Lisbon"], "checkInDate": "2026-12-04", "checkOutDate": "2026-12-06", "currency": "EUR", "maxResultsPerLocation": 30, "onlyAvailable": true}'
```

From Python (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("westerly_breaker/google-hotels-scraper").call(
    run_input={"locations": ["Lisbon"], "checkInDate": "2026-12-04", "checkOutDate": "2026-12-06", "currency": "EUR"}
)
for hotel in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(hotel["name"], hotel["price"] and hotel["price"]["total"], hotel["rating"])
```

Useful for rate-shopping and price monitoring (schedule a run per day and compare `totalValue`), market research on a city's supply (classes, ratings, review volume), travel apps and agents that need real prices for real dates.

### Pricing (pay-per-event)

**$0.002 per property delivered**, platform usage included.

- 3 cities × 100 properties = 300 × $0.002 = **$0.60**
- Properties skipped by `onlyAvailable` and locations that fail are **not charged**.
- If you set a maximum cost per run, the actor stops cleanly at that limit. Every row you paid for is delivered, and you are never billed for a row you didn't get.

### Error messages

Bad input stops the run before any request, naming the field and the fix, for example:

- `'checkInDate' 2026-10-01 is in the past. Use today (2026-10-12) or a later date.`
- `'currency' must be a 3-letter ISO code like 'USD', 'EUR' or 'HUF', got 'euro'.`

### Known limitations

- **Per-site offers (Booking.com vs Expedia vs the hotel's own site) are not included.** The results page only carries the lowest price. Per-provider prices would need one extra request per property; that is planned as an option.
- **Prices change constantly** and can differ by `countryCode`, the same as on google.com.
- Small places have fewer properties than your limit. The actor stops when Google has no further pages, and the log shows Google's own estimate of the total.

### Data source

Public Google Hotels search results (google.com/travel), the same data the web page shows. No login, no API key.

# Actor input Schema

## `locations` (type: `array`):

Places to search, e.g. \["Budapest"], \["Paris 8th arrondissement"] or \["Times Square, New York"]. Each is searched as 'hotels in <location>'. Max 100 per run.

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

YYYY-MM-DD. Defaults to 14 days from today. Must not be in the past, and at most ~11 months ahead.

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

YYYY-MM-DD, after the check-in date, max 30 nights. Defaults to one night after check-in.

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

Number of adult guests (1-10). Prices are for this group.

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

3-letter ISO currency code for all prices, e.g. USD, EUR, GBP, HUF.

## `maxResultsPerLocation` (type: `integer`):

Stop after this many properties for each location (1-1000). The actor pages through Google's results and skips duplicates. You pay per property delivered.

## `onlyAvailable` (type: `boolean`):

Skip properties that have no price for your dates (sold out, or no booking partner). Skipped properties are not charged. Off: they are included with available=false and price=null.

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

Language of descriptions and labels, e.g. 'en-US', 'de', 'hu'.

## `countryCode` (type: `string`):

2-letter country code Google treats the search as coming from (gl parameter), e.g. 'us', 'gb', 'de'. It can change which offers are shown.

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

The first attempt for each page goes out directly (fastest). If it fails, retries go through a fresh Apify Proxy session.

## Actor input object example

```json
{
  "locations": [
    "Budapest",
    "Lisbon"
  ],
  "checkInDate": "2026-11-20",
  "checkOutDate": "2026-11-22",
  "adults": 2,
  "currency": "USD",
  "maxResultsPerLocation": 50,
  "onlyAvailable": false,
  "language": "en-US",
  "countryCode": "us",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `properties` (type: `string`):

One row per property: price for the stay, rating, class, location, review topics, nearby places and links, stored in the run's default dataset.

# 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 = {
    "locations": [
        "Budapest"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

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

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

```

## MCP server setup

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