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

Scrape Google Hotels for any destination and dates: live per-night prices, the full OTA price ladder (Booking.com, Agoda, Expedia, Hotels.com and more) with booking links, per-room rates, star class, guest ratings and reviews. Structured JSON/CSV - no code, no login, no Google API key.

- **URL**: https://apify.com/factden/google-hotels-scraper.md
- **Developed by:** [Factden](https://apify.com/factden) (community)
- **Categories:** Travel, Business, AI
- **Stats:** 6 total users, 5 monthly users, 100.0% runs succeeded, 3 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.0032 / hotel

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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

**Google Hotels Scraper** extracts hotels, live prices and guest reviews from [Google Hotels](https://www.google.com/travel/search)
at scale. Search any destination and dates, and get one row per hotel with the **live per-night price**, the
**full OTA price ladder** (Booking.com, Agoda, Expedia, Hotels.com, Priceline and more), each with its **booking
link**, plus **per-room rates**, **star class**, **guest rating & review count**, coordinates, and optional
**guest reviews**. Export to **CSV, JSON, Excel**, or pull it via **API**. No code, no login, **no Google API
key**, and you **pay only for what you pull** (no start fee).

> ⭐ **Found this useful?** Please **rate & bookmark** the actor; it helps other travelers and analysts find it.

> **Discovery + prices + reviews in one actor.** Paste a destination ("hotels in New York") and dates and get every
> matching hotel with its complete price comparison ladder. Or add exact hotels by **name, link, or ID** to price a
> known set across a range of dates. Prices and reviews are optional toggles, so you pay only for what you pull.

Runs on the Apify platform: **scheduling**, a **REST API**, **webhooks & integrations**, **proxy rotation**, and
**run monitoring** out of the box, plus an **LLM-ready `markdownContent`** field on every row for RAG pipelines.

![Google Hotels Scraper Prices view - the full OTA price ladder per hotel with per-night price, currency, official-site flag and booking links](https://raw.githubusercontent.com/factden/apify-actor-assets/main/google-hotels-scraper/01-prices-ota-ladder.png)

https://www.youtube.com/watch?v=5m-_lNJ8bnw

### What does Google Hotels Scraper do?

Give it one or more **destination searches** (e.g. `hotels in New York`, `Paris 5 star hotels`, `resorts in Bali`)
and/or **exact hotels** (by name, Google Maps/Hotels link, or ID), pick your **dates and occupancy**, and it returns:

- **Hotel discovery**: every hotel matching the search, paginated and de-duplicated, with name, star class, guest
  rating, review count, property type, coordinates and a Google Hotels deep link.
- **Prices** (toggle): the cheapest per-night lead price **plus the full per-source OTA ladder** (typically
  **15 to 25 booking sites**), with each source's per-night and total price and a direct booking link.
- **Per-room rates**: the room × source matrix (room name, per-night, total) for OTAs that feed room data to
  Google. Included automatically whenever prices are on (no extra request, no extra charge).
- **Guest reviews** (toggle): reviewer, rating, review text, date and owner response, into a separate `reviews`
  dataset.
- **Multi-date price windows**: set a "track prices until" date to reprice the same hotels across a range
  (added to `offers` as dated rows).

### What data can I extract from Google Hotels?

Per hotel, one row, with nested arrays so a hotel and its whole price ladder stay in a single record (no row
explosion):

| Field | Description |
|---|---|
| `name`, `entityToken` | Hotel name + Google Travel entity token (the stable de-dup key). |
| `starClass`, `rating`, `reviewCount` | Hotel-class stars, average guest rating (/5), total reviews. |
| `propertyType`, `latitude`, `longitude` | Property type + coordinates. |
| `leadPrice`, `leadPriceTotal`, `currency` | Cheapest per-night + whole-stay price for the base stay. |
| `offers[]` | **The prices table**: one self-contained row per booking source × stay-date × room-if-available: `{source, checkInDate, checkOutDate, roomName, perNight, total, currency, official, hotelUrl, bookingLink}`. Includes the base stay **and every price-window date**. The hotel's direct-booking row is labelled `Official site` (`official: true`). |
| `vendors[]` | **Booking directory**: one object per source: `{source, bookingLink, official}` (no prices; prices live in `offers`). |
| `vendorCount`, `nights` | Number of distinct booking sources selling this hotel + the length of the priced stay (nights). |
| `cid`, `cidDecimal`, `hotelUrl` | Google feature-id (hex) / decimal Maps CID + a deep link. |
| `reviewsExtracted`, `scrapedAt` | Reviews pushed to the `reviews` dataset for this hotel this run + ISO 8601 timestamp of the scrape. |
| `markdownContent` | Self-contained, **LLM-ready** hotel + price summary for RAG ingestion. |

Reviews land in a separate **`reviews`** dataset (one row per review): `reviewerName`, `rating`, `reviewText`,
`relativeDate`, `ownerResponse`, `hotelName`, `entityToken` and an LLM-ready `markdownContent`.

![Google Hotels Scraper Reviews dataset - reviewer, rating, review text, exact publish date, relative date, owner response and hotel name per row](https://raw.githubusercontent.com/factden/apify-actor-assets/main/google-hotels-scraper/03-reviews.png)

### What makes this different?

| | **Google Hotels Scraper** | Typical single-purpose scrapers |
|---|---|---|
| Coverage | Discovery **+** prices **+** reviews in one run | Prices **or** reviews, rarely both |
| Row shape | **One row per hotel** with nested price ladder | One row per price/offer (row explosion) |
| Price detail | Full **OTA ladder** + booking links + per-room matrix (always) | Single lead price |
| Dates | Single stay **or** a multi-date price window (all in `offers`) | Single date |
| AI-ready | `markdownContent` on every row (RAG) | Raw fields only |
| Billing | **Per hotel** base + opt-in prices/reviews, no start fee | Often per result/offer |

### How to scrape Google Hotels step by step

1. Open the actor and in **🔍 Search a destination** type one destination per line (e.g. `hotels in New York`). Or,
   in **🏨 …or add exact hotels**, add specific hotels by **name** (e.g. `The Manhattan at Times Square`), Google
   Maps/Hotels link, or ID. You get exactly those, one row each.
2. Set **📅 Check-in / Check-out** and **guests / rooms**. (Leave dates empty and, with prices on, the actor prices tomorrow's 1-night stay; turn off **Include prices** for hotel info + reviews only.)
3. Toggle **💵 Include prices** (OTA ladder + per-room rates) and **⭐ Include reviews** to taste.
4. Optionally set discovery filters (min/max price, minimum guest rating, stars, property type) and **max hotels**.
5. Click **Start**, then download the results as **JSON, CSV or Excel**, or fetch them from the **API**.

![Google Hotels Scraper input on Apify - search a destination or add exact hotels by name or link, set dates and guests, and toggle Include prices and Include reviews](https://raw.githubusercontent.com/factden/apify-actor-assets/main/google-hotels-scraper/02-input-form.png)

### Google Hotels API vs this scraper

Google does not offer a public Hotels API for this data. The official Hotel Center / Hotel Prices APIs are for
**hotel partners feeding their own rates in**, not for pulling the public comparison results out, and they require
partner onboarding. This actor reads the same public Google Hotels results a visitor sees, with **no API key, no
partner account, and no per-call quota**, just structured JSON/CSV out.

### Who is it for?

- **Travel & OTA analysts**: track rates and the OTA price ladder across markets and dates.
- **Revenue managers & hotels**: monitor your own and competitors' rates and guest sentiment.
- **Price-comparison & meta-search builders**: bootstrap a hotel + rates dataset.
- **Data / AI teams**: build a hotel-and-reviews corpus with ready-made `markdownContent` for RAG.

### Common use cases

#### Rate shopping & OTA rate parity
Add your competitive set by **name or link** into **exact hotels**, set a base stay, set a **Track prices until**
date, and enable prices. Each hotel's `offers` then include priced rows for every date in the window. It is a
pay-per-use alternative to enterprise rate-shopping suites for monitoring **OTA rate parity** and competitor
rates across dates, with the raw data you own.

#### Full-market discovery
Search `hotels in <city>` with a higher **max hotels** to sweep the destination, then enable prices to get the
whole OTA ladder for every hotel.

#### Guest-sentiment dataset
Turn **prices off** and **reviews on** to build a pure reviews corpus (billed $0.004 per hotel + $0.001 per review, no start fee).

### Input

| Input | Description |
|---|---|
| `searchQueries` | Destination searches, one per line (paginated + de-duplicated). |
| `hotelUrls` | Exact hotels (one row each): a **hotel name**, a Google Travel/Maps URL or short link, a `ChIJ…` place-id, or a `ChkI…` entity token. |
| `checkInDate` / `checkOutDate` | Stay dates (YYYY-MM-DD). Leave empty and, with prices on, it defaults to tomorrow's 1-night stay; turn off Include prices for info + reviews only. |
| `priceWindowEnd` | Optional "track prices until" date; reprices every check-in from check-in to this date, added to `offers` as extra dated rows. |
| `adults` / `children` / `rooms` | Occupancy. |
| `includePrices` / `currency` | Prices toggle (OTA ladder + per-room rates) and currency. |
| `includeReviews` / `maxReviews` / `reviewsSort` | Reviews toggle, cap per hotel, sort order. |
| `minPrice` / `maxPrice` / `minGuestRating` | Hard filters on lead price and guest rating. |
| `minStars` / `propertyTypes` | Search refinements (Google narrows the results). |
| `maxResults` | Max unique hotels to return (0 = no cap). |
| `countryCode` / `languageCode` | Google market + interface language. |
| `proxyConfiguration` | Proxy settings (datacenter is sufficient at typical volumes). |

At least one of `searchQueries` or `hotelUrls` is required.

### Output

**`hotels`** dataset, one row per hotel:

```json
{
  "name": "The Manhattan at Times Square Hotel",
  "entityToken": "ChkIooCAqvyy0f…",
  "starClass": 3,
  "rating": 4.9,
  "reviewCount": 12043,
  "checkInDate": "2026-11-15",
  "checkOutDate": "2026-11-16",
  "nights": 1,
  "currency": "USD",
  "leadPrice": 290,
  "leadPriceTotal": 290,
  "offers": [
    {"source": "Booking.com", "checkInDate": "2026-11-15", "checkOutDate": "2026-11-16", "roomName": "Deluxe Queen", "perNight": 290, "total": 290, "currency": "USD", "official": false, "hotelUrl": "https://www.google.com/travel/hotels/entity/ChkIooCAqvyy0f…", "bookingLink": "https://www.google.com/aclk?…"},
    {"source": "Official site", "checkInDate": "2026-11-15", "checkOutDate": "2026-11-16", "roomName": null, "perNight": 279, "total": 279, "currency": "USD", "official": true, "hotelUrl": "https://www.google.com/travel/hotels/entity/ChkIooCAqvyy0f…", "bookingLink": "https://www.google.com/aclk?…"}
  ],
  "vendors": [
    {"source": "Booking.com", "bookingLink": "https://www.google.com/aclk?…", "official": false},
    {"source": "Expedia.com", "bookingLink": "https://www.google.com/aclk?…", "official": false}
  ],
  "vendorCount": 8,
  "reviewsExtracted": 10,
  "hotelUrl": "https://www.google.com/travel/hotels/entity/ChkIooCAqvyy0f…",
  "markdownContent": "# The Manhattan at Times Square Hotel\n…",
  "scrapedAt": "2026-11-14T09:32:10Z"
}
````

**`reviews`** dataset, one row per guest review:

```json
{
  "hotelName": "The Manhattan at Times Square Hotel",
  "entityToken": "ChkIooCAqvyy0f…",
  "reviewerName": "NADIA CHIN",
  "rating": 4,
  "reviewText": "Great location, friendly staff…",
  "relativeDate": "a day ago",
  "source": "google"
}
```

You can download either dataset as **JSON, CSV, HTML or Excel**, or fetch it from the API.

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

**Discovery starts at $4 per 1,000 hotels, with no start fee, and you pay only for what you turn on.** Prices and
reviews are opt-in add-ons, so a discovery run stays cheap and you only pay more when you pull the full price ladder
or reviews. Three events:

| You pay for | When | Price |
|---|---|---|
| **Hotel** | each hotel returned (name, stars, rating, coordinates, lead price) | $0.004 |
| **Prices** (opt-in) | each hotel priced: full OTA ladder + per-room rates, per date | $0.005 |
| **Review** (opt-in) | each guest review | $0.001 |

So **discovery-only = $4 / 1,000 hotels**; a hotel **with** its complete price ladder = **$0.009**; reviews add
$0.001 each. The Apify **$5 free credit** covers **~1,250 hotels** discovery-only, or **~555 fully-priced**. See the
**Pricing** tab for current rates.

**What a real run costs:** pricing **20 hotels** once (full ladder) = 20 × $0.009 = **$0.18**; monitoring a
**50-hotel comp set across 30 check-in dates** = 50 × $0.004 + 50 × 30 × $0.005 = **~$7.70** per sweep; a
**discovery-only sweep of 500 hotels** = **$2.00**.

![Google Hotels Scraper pricing on Apify - pay-per-event: Hotel $0.004, Prices fetched $5 per 1,000, Review scraped $1 per 1,000, with lower rates on paid plans](https://raw.githubusercontent.com/factden/apify-actor-assets/main/google-hotels-scraper/04-pricing.png)

### Run it on a schedule

Use Apify **Schedules** to re-scrape your competitive set daily and diff the price ladder over time. Combine with
**webhooks** to push new results into your warehouse or a Slack alert.

### AI agents & RAG

Every row carries an LLM-ready `markdownContent` block, so you can feed the `hotels` or `reviews` dataset straight
into a vector DB. The actor is also callable from AI agents via the Apify MCP server.

### Data & compliance

This actor collects only **publicly available** Google Hotels data, the same results any visitor sees. It does not
log in or bypass access controls. You are responsible for using the data in line with applicable laws and Google's
terms. Reviews are public user-generated content; handle any personal data (reviewer names) per GDPR/CCPA.

### Other travel & review scrapers by FactDen

| Actor | What it does |
|---|---|
| [Expedia Reviews Scraper](https://apify.com/factden/expedia-hotel-reviews-scraper) | Hotel guest reviews, ratings, sub-scores & sentiment from Expedia. |
| [Hotels.com Reviews Scraper](https://apify.com/factden/hotels-com-reviews-scraper) | Hotel guest reviews & ratings from Hotels.com (all Expedia-Group brands). |
| [Trip.com & Ctrip Reviews Scraper](https://apify.com/factden/ctrip-trip-reviews-scraper) | Hotel reviews & ratings from Trip.com / Ctrip. |
| [G2 Software Reviews Scraper](https://apify.com/factden/g2-reviews-scraper) | Software product reviews, ratings & switching data from G2. |
| [Indeed Jobs Scraper](https://apify.com/factden/indeed-jobs-scraper) | Job listings, salaries, filters & company data from Indeed. |

### FAQ

#### Do I need a Google API key?

No. No key, no partner account, and no login. You paste a destination or hotel URLs and run it; the actor reads
the same public Google Hotels results a visitor sees and returns structured JSON/CSV.

#### Can I scrape a specific hotel instead of a whole city?

Yes. In **…or add exact hotels**, enter the hotel's **name** (e.g. `The Manhattan at Times Square`), its Google
Hotels/Maps URL or short link, a `ChIJ…` Maps place-id, or a `ChkI…` entity token. You get exactly that hotel,
one row, ideal for pricing a known competitive set across dates. (A hotel name resolves to the closest match, so
use the full name; a Google Maps link is CID-matched for an exact result.)

#### Can I get prices for different dates in one run?

Yes. Set a **Track prices until** date and each hotel is repriced for every check-in day from your check-in date up
to that date, added to `offers` as dated rows (up to 60 extra dates per hotel). The nights are taken from your
check-in to check-out gap. Each extra date is a separate `prices` charge per hotel, so a wide window across a whole
city adds up; it is best paired with a short list of specific hotels.

#### Why do a few hotels have no price ladder?

Almost all hotels return the full OTA ladder and reviews (in testing, prices resolved for ~17 of 18 hotels on a
results page and reviews for all 18). A property with no bookable offers on your dates/sources will still return
its name, rating, star class and coordinates (and reviews), just an empty price ladder.

#### How fresh are the prices, and how often can I run it?

Prices are pulled **live from Google at run time** for your exact dates and occupancy, the same rates a visitor
sees at that moment. Schedule the actor hourly or daily to track rate movements and **OTA rate parity** across
booking sources over time; each run appends to your dataset, so you build a price history for revenue management
and parity monitoring. It supports **20 currencies, 13 Google country markets and 9 interface languages**, and the
market setting shifts which hotels appear, the pricing, and the OTA mix.

#### Can I use Google Hotels Scraper with the Apify API?

Yes. Every actor on Apify has a full REST API: start runs, pass input, and pull the `hotels` and `reviews`
datasets as JSON, CSV or Excel. You can also schedule runs and wire webhooks to push results downstream.

#### Can I use it through an MCP server?

Yes. The actor is callable from AI agents via the Apify MCP server, so tools like Claude or a LangChain agent can
run it and read the structured result. Every row also carries an LLM-ready `markdownContent` field for RAG.

#### Can I integrate it with Make, Zapier, n8n or Google Sheets?

Yes. Apify offers native integrations and webhooks, so you can trigger runs and route the hotel and review data
into Make, Zapier, n8n, Google Sheets, Slack, or your own warehouse without writing glue code.

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

Scraping publicly available data is generally lawful, but you are responsible for how you use it. This actor
collects only public results and does not log in or bypass access controls. See Apify's overview,
[is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/), and handle any personal data (reviewer
names) in line with GDPR/CCPA.

### Support

Questions or a field you need? Open the **Issues** tab on this actor's Apify page.

### Changelog

- **2026-07, v1.0**: Initial release: discovery + OTA price ladder + per-room rates + reviews, multi-date price
  windows, LLM-ready markdown, three datasets (hotels / default / reviews).
- **2026-07, listing update**: Added worked pricing examples, source/market coverage numbers, and a price-freshness
  & rate-parity FAQ.

# Actor input Schema

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

One destination per line — e.g. `hotels in New York City`, `Paris 5 star hotels`, `resorts in Bali`. Each is paginated and de-duplicated. Provide this **or** hotel links below (at least one required). If you provide both, the results are combined and de-duplicated (a hotel found by both a search and a link appears once).

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

Add specific hotels, one per line — you get exactly those, one row each (ideal for a fixed competitor set you re-run on a schedule). Each line can be:

- **A hotel name** — e.g. `The Manhattan at Times Square` (use the full name + city so it matches the right property)
- **A Google Maps or Google Hotels link** — e.g. a `maps.app.goo.gl` share link or a `/travel/hotels/...` URL
- **Advanced:** a `ChIJ…` Maps place-id or a `ChkI…` entity token

See the README for the full list of accepted formats.

## `includePrices` (type: `boolean`):

Fetch the lead price plus the full per-source booking ladder (Booking.com, Agoda, Expedia, Hotels.com…) and the per-room rates — each with its booking link. Needs check-in/out dates below.

## `includeReviews` (type: `boolean`):

Fetch guest reviews for each hotel into the separate `reviews` dataset (reviewer, rating, text, date, and the hotel's reply when present).

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

Only keep hotels whose lead price per night is at or above this (in the selected currency). Leave empty for no lower bound.

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

Only keep hotels whose lead price per night is at or below this. Leave empty for no upper bound.

## `minGuestRating` (type: `number`):

Only keep hotels with a guest review score at or above this (0–5 scale). 0 = no filter.

## `minStars` (type: `integer`):

Refines the search toward this hotel-class star rating (1–5); Google narrows the results server-side. 0 = no refinement.

## `propertyTypes` (type: `array`):

Refines the search toward these property types (Google narrows the results). Includes vacation rentals.

## `maxResults` (type: `integer`):

Stop after this many unique hotels (across all queries and links). 0 = no cap. A small number keeps a first run fast and cheap; raise it for a full-market sweep.

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

Check-in day (YYYY-MM-DD). Prices are date-scoped — change the dates to reprice. **If you leave both dates empty and prices are on, the actor auto-uses tomorrow (run date + 1 day) for a 1-night stay, computed at run time.** For hotel info + reviews only (no prices), turn off Include prices.

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

Check-out day (YYYY-MM-DD). Must be after check-in. The gap sets the length of stay used for every priced date. Leave both dates empty → the actor defaults to a 1-night stay (check-out = tomorrow + 1 day).

## `priceWindowEnd` (type: `string`):

Track prices across a date range: we reprice the same-length stay for **every check-in day from Check-in up to this date** (up to 60 days), appended to the `offers` table (each row carries its own check-in/check-out). Leave empty to price just the single stay above. **Cost/time note:** each extra date is a separate `prices` charge **per hotel** — a wide window across a whole-city search multiplies fast (e.g. 200 hotels × 30 dates = 6,000 charges). Best paired with a short list of specific hotels.

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

Number of adult guests.

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

Number of children.

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

Number of rooms.

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

Currency for all prices.

## `maxReviews` (type: `integer`):

Cap on reviews pulled per hotel (paginated). Google caps at roughly 5,000 per sort order. Note: high values across many hotels make runs much slower — keep it modest for whole-city searches.

## `reviewsSort` (type: `string`):

Order reviews are fetched in.

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

Google country code — a global setting that shifts the whole market: which hotels appear, the pricing market and OTA mix.

## `languageCode` (type: `string`):

Google interface language for names, review text and labels.

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

Proxy settings. Datacenter proxies are sufficient for Google Hotels at typical volumes; switch to residential IPs if the empty-response rate climbs on very large runs.

## Actor input object example

```json
{
  "searchQueries": [
    "hotels in New York City"
  ],
  "includePrices": true,
  "includeReviews": false,
  "minGuestRating": 0,
  "minStars": 0,
  "propertyTypes": [],
  "maxResults": 20,
  "adults": 2,
  "children": 0,
  "rooms": 1,
  "currency": "USD",
  "maxReviews": 100,
  "reviewsSort": "newest",
  "countryCode": "us",
  "languageCode": "en",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per hotel: name, Google entity token/CID, property type, star class, guest rating, coordinates, the lead per-night price and the per-source OTA ladder (Booking.com, Agoda, Expedia, Hotels.com...) with booking links, plus optional per-room rates and an LLM-ready markdownContent block.

## `reviews` (type: `string`):

One row per guest review (hotel context merged onto each row): reviewer, rating, review text, date, owner response and an LLM-ready markdownContent block. Populated only when Include reviews is enabled.

# 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 New York City"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("factden/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 New York City"] }

# Run the Actor and wait for it to finish
run = client.actor("factden/google-hotels-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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 New York City"
  ]
}' |
apify call factden/google-hotels-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=factden/google-hotels-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Google Hotels Scraper - Prices, OTA Rates, Room Rates & Reviews",
        "description": "Scrape Google Hotels for any destination and dates: live per-night prices, the full OTA price ladder (Booking.com, Agoda, Expedia, Hotels.com and more) with booking links, per-room rates, star class, guest ratings and reviews. Structured JSON/CSV - no code, no login, no Google API key.",
        "version": "1.0",
        "x-build-id": "iojxFdIcnebbIxein"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/factden~google-hotels-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-factden-google-hotels-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/factden~google-hotels-scraper/runs": {
            "post": {
                "operationId": "runs-sync-factden-google-hotels-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/factden~google-hotels-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-factden-google-hotels-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchQueries": {
                        "title": "🔍 Search a destination",
                        "maxItems": 100,
                        "type": "array",
                        "description": "One destination per line — e.g. `hotels in New York City`, `Paris 5 star hotels`, `resorts in Bali`. Each is paginated and de-duplicated. Provide this **or** hotel links below (at least one required). If you provide both, the results are combined and de-duplicated (a hotel found by both a search and a link appears once).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "hotelUrls": {
                        "title": "🏨 …or add exact hotels (names or links)",
                        "maxItems": 1000,
                        "type": "array",
                        "description": "Add specific hotels, one per line — you get exactly those, one row each (ideal for a fixed competitor set you re-run on a schedule). Each line can be:\n\n- **A hotel name** — e.g. `The Manhattan at Times Square` (use the full name + city so it matches the right property)\n- **A Google Maps or Google Hotels link** — e.g. a `maps.app.goo.gl` share link or a `/travel/hotels/...` URL\n- **Advanced:** a `ChIJ…` Maps place-id or a `ChkI…` entity token\n\nSee the README for the full list of accepted formats.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "includePrices": {
                        "title": "💵 Include prices",
                        "type": "boolean",
                        "description": "Fetch the lead price plus the full per-source booking ladder (Booking.com, Agoda, Expedia, Hotels.com…) and the per-room rates — each with its booking link. Needs check-in/out dates below.",
                        "default": true
                    },
                    "includeReviews": {
                        "title": "⭐ Include reviews",
                        "type": "boolean",
                        "description": "Fetch guest reviews for each hotel into the separate `reviews` dataset (reviewer, rating, text, date, and the hotel's reply when present).",
                        "default": false
                    },
                    "minPrice": {
                        "title": "💲 Min price / night",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only keep hotels whose lead price per night is at or above this (in the selected currency). Leave empty for no lower bound."
                    },
                    "maxPrice": {
                        "title": "💲 Max price / night",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only keep hotels whose lead price per night is at or below this. Leave empty for no upper bound."
                    },
                    "minGuestRating": {
                        "title": "📈 Minimum guest rating",
                        "minimum": 0,
                        "maximum": 5,
                        "type": "number",
                        "description": "Only keep hotels with a guest review score at or above this (0–5 scale). 0 = no filter.",
                        "default": 0
                    },
                    "minStars": {
                        "title": "⭐ Minimum star class",
                        "minimum": 0,
                        "maximum": 5,
                        "type": "integer",
                        "description": "Refines the search toward this hotel-class star rating (1–5); Google narrows the results server-side. 0 = no refinement.",
                        "default": 0
                    },
                    "propertyTypes": {
                        "title": "🏩 Property types",
                        "type": "array",
                        "description": "Refines the search toward these property types (Google narrows the results). Includes vacation rentals.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "hotel",
                                "apartment",
                                "resort",
                                "hostel",
                                "motel",
                                "bedAndBreakfast",
                                "vacationRental",
                                "guestHouse",
                                "cabin"
                            ],
                            "enumTitles": [
                                "Hotel",
                                "Apartment",
                                "Resort",
                                "Hostel",
                                "Motel",
                                "Bed & breakfast",
                                "Vacation rental",
                                "Guest house",
                                "Cabin"
                            ]
                        },
                        "default": []
                    },
                    "maxResults": {
                        "title": "🔢 Max hotels",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Stop after this many unique hotels (across all queries and links). 0 = no cap. A small number keeps a first run fast and cheap; raise it for a full-market sweep.",
                        "default": 20
                    },
                    "checkInDate": {
                        "title": "📅 Check-in",
                        "type": "string",
                        "description": "Check-in day (YYYY-MM-DD). Prices are date-scoped — change the dates to reprice. **If you leave both dates empty and prices are on, the actor auto-uses tomorrow (run date + 1 day) for a 1-night stay, computed at run time.** For hotel info + reviews only (no prices), turn off Include prices."
                    },
                    "checkOutDate": {
                        "title": "📅 Check-out",
                        "type": "string",
                        "description": "Check-out day (YYYY-MM-DD). Must be after check-in. The gap sets the length of stay used for every priced date. Leave both dates empty → the actor defaults to a 1-night stay (check-out = tomorrow + 1 day)."
                    },
                    "priceWindowEnd": {
                        "title": "📈 Track prices until (optional)",
                        "type": "string",
                        "description": "Track prices across a date range: we reprice the same-length stay for **every check-in day from Check-in up to this date** (up to 60 days), appended to the `offers` table (each row carries its own check-in/check-out). Leave empty to price just the single stay above. **Cost/time note:** each extra date is a separate `prices` charge **per hotel** — a wide window across a whole-city search multiplies fast (e.g. 200 hotels × 30 dates = 6,000 charges). Best paired with a short list of specific hotels."
                    },
                    "adults": {
                        "title": "👤 Adults",
                        "minimum": 1,
                        "maximum": 8,
                        "type": "integer",
                        "description": "Number of adult guests.",
                        "default": 2
                    },
                    "children": {
                        "title": "🧒 Children",
                        "minimum": 0,
                        "maximum": 8,
                        "type": "integer",
                        "description": "Number of children.",
                        "default": 0
                    },
                    "rooms": {
                        "title": "🛏️ Rooms",
                        "minimum": 1,
                        "maximum": 8,
                        "type": "integer",
                        "description": "Number of rooms.",
                        "default": 1
                    },
                    "currency": {
                        "title": "💱 Currency",
                        "enum": [
                            "USD",
                            "EUR",
                            "GBP",
                            "INR",
                            "JPY",
                            "AUD",
                            "CAD",
                            "CHF",
                            "SGD",
                            "AED",
                            "BRL",
                            "CNY",
                            "HKD",
                            "MXN",
                            "ZAR",
                            "THB",
                            "KRW",
                            "SEK",
                            "NZD",
                            "PLN"
                        ],
                        "type": "string",
                        "description": "Currency for all prices.",
                        "default": "USD"
                    },
                    "maxReviews": {
                        "title": "🔢 Max reviews per hotel",
                        "minimum": 1,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Cap on reviews pulled per hotel (paginated). Google caps at roughly 5,000 per sort order. Note: high values across many hotels make runs much slower — keep it modest for whole-city searches.",
                        "default": 100
                    },
                    "reviewsSort": {
                        "title": "↕️ Sort reviews by",
                        "enum": [
                            "newest",
                            "relevant"
                        ],
                        "type": "string",
                        "description": "Order reviews are fetched in.",
                        "default": "newest"
                    },
                    "countryCode": {
                        "title": "🌍 Country (gl)",
                        "enum": [
                            "us",
                            "gb",
                            "in",
                            "au",
                            "ca",
                            "de",
                            "fr",
                            "es",
                            "it",
                            "jp",
                            "sg",
                            "ae",
                            "br"
                        ],
                        "type": "string",
                        "description": "Google country code — a global setting that shifts the whole market: which hotels appear, the pricing market and OTA mix.",
                        "default": "us"
                    },
                    "languageCode": {
                        "title": "🗣️ Language (hl)",
                        "enum": [
                            "en",
                            "es",
                            "fr",
                            "de",
                            "it",
                            "pt",
                            "ja",
                            "hi",
                            "ar"
                        ],
                        "type": "string",
                        "description": "Google interface language for names, review text and labels.",
                        "default": "en"
                    },
                    "proxyConfiguration": {
                        "title": "🌐 Proxy configuration",
                        "type": "object",
                        "description": "Proxy settings. Datacenter proxies are sufficient for Google Hotels at typical volumes; switch to residential IPs if the empty-response rate climbs on very large runs.",
                        "default": {
                            "useApifyProxy": true
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
