# Google Hotels Scraper | $4.99 per 1,000 hotels (`webdata_labs/google-hotels-scraper`) Actor

\[$4.99 / 1K] Google Hotels with the full per-vendor price ladder: every booking site quoting each hotel for your dates, with nightly rate, stay total and a bookable deep link. Plus rating, review breakdown by OTA, address, phone and check-in times. No start fee.

- **URL**: https://apify.com/webdata\_labs/google-hotels-scraper.md
- **Developed by:** [WebData Labs](https://apify.com/webdata_labs) (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 $3.49 / 1,000 hotel scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

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

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

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

# README

## Google Hotels Scraper - Every Booking Site's Price, Not Just One

**Scrape Google Hotels and get the full per-vendor price ladder for your dates: Booking.com, Expedia, Hotels.com, Trip.com, Agoda, the hotel's own site and everyone else quoting that stay, each with its nightly rate, stay total and a bookable link.**

Most Google Hotels scrapers hand you one headline number per hotel - the same "from" price the search page shows. That number is whichever site happened to be cheapest at that second, and it tells you nothing about the spread. This Actor opens each hotel and reads **every vendor quoting it**, so you can see that the same room is 63 EUR on one site and 209 EUR on another, on the same night.

Give it a city, a set of dates and a currency. Get back one row per hotel with the ladder, the rating, the review breakdown per booking site, the address, the phone and the official website.

### ✅ What you get / ❌ What this isn't

**✅ What you get**

- The **complete price ladder** per hotel - typically 10 to 30 vendors, and up to 37, organic and sponsored, each tagged
- **Nightly rate and stay total** from each vendor, all converted to one currency so they are directly comparable
- A **bookable deep link** per vendor, with your dates already in the URL - the vendor's own link, not a Google redirect
- **Cheapest vendor, dearest vendor and the spread** already computed
- **Real dates**: check-in, check-out, nights, adults, children's ages and rooms all change what the vendors quote
- **Relative dates** (`checkInDaysAhead`) so a scheduled run keeps asking about the same stay shape instead of drifting into the past
- Rating, star breakdown, **each booking site's own review score**, and what guests keep mentioning
- Address, phone, official website, check-in and check-out times, coordinates, Google Place ID
- Photos and the hotel's description

**❌ What this isn't**

- Not a booking engine. It reads public prices; it does not hold, reserve or pay for anything.
- **Not room-by-room rates.** Google quotes one rate per vendor for the stay you asked about, and that is what you get. There is no per-room-type table.
- Not a Google account scraper. Everything here is what a signed-out visitor sees.
- Not a review dump. You get the score, the star histogram and per-site scores, not the individual review texts.
- Not real-time. Prices are correct as of the moment the run fetched them, which is why the monitoring pattern below exists.

### 🔎 Why use this Actor

- **The spread is the product.** Across 120 Lisbon hotels priced for the same two nights, the median gap between the cheapest and dearest vendor was 39 EUR, and the widest was 546 EUR. A one-price scrape cannot see any of that.
- **Every hotel is addressable.** Each row carries the Google Hotels entity URL, so you can feed the same properties back in tomorrow and get a clean time series.
- **Dates and occupancy really work.** Two adults and six adults are genuinely different prices, and this Actor sends both correctly.
- **Vacation rentals are separated, not silently mixed in.** Google blends single-room rental listings into hotel results; they are tagged and excluded by default so you are not charged for the same address five times.
- **No proxy setup, no captcha, no start fee.** Google Hotels serves this data over plain HTTP and the Actor keeps it that way, which is why the price is what it is.

### 📊 What data you get

| Field | Type | Description |
|---|---|---|
| `name` | string | Hotel name |
| `propertyType` | string | `hotel` or `vacation_rental` |
| `priceDisplay` / `price` | string / number | The headline nightly rate Google shows in the results list |
| `lowestPrice` | number | The lowest rate any vendor quotes on the detail view |
| `priceLadder` | array | One entry per vendor: `vendor`, `nightlyPrice`, `stayTotal`, `sponsored`, `bookingUrl`, `googleClickUrl`, `partnerId` |
| `vendorCount` | number | How many vendors quoted this hotel for these dates |
| `cheapestVendor` / `cheapestVendorPrice` / `cheapestVendorUrl` | string / number / string | The best organic quote and where to book it |
| `highestVendorPrice` / `priceSpread` | number | The dearest organic quote and the gap to the cheapest |
| `checkInDate` / `checkOutDate` / `nights` | string / number | The stay these prices are for |
| `currency` | string | Currency every price in the row is quoted in |
| `rating` / `reviewCount` / `ratingHistogram` | number / number / object | Google's guest rating, review count and star breakdown |
| `reviewsBySource` | array | Each booking site's own score and review count for the hotel |
| `reviewTopics` | array | What guests keep mentioning, with mention counts and sentiment |
| `hotelClass` / `stars` | string / number | `4-star hotel` and the numeric class |
| `address` / `phone` / `website` | string | Property contact details |
| `checkInTime` / `checkOutTime` | string | When you can arrive and must leave |
| `latitude` / `longitude` / `googlePlaceId` / `ftid` | number / string | Location and the ids that tie this row to Google Maps |
| `amenities` | array | Named amenities, where Google publishes them |
| `description` / `photoUrls` / `thumbnailUrl` | string / array | Editorial description and photos |
| `url` / `entityToken` | string | The hotel's Google Hotels page, and the token to re-price it later |
| `searchQuery` / `resultPage` / `position` | string / number | Where in your search this hotel came from |
| `priceLadderStatus` | string | `ok`, or why the ladder could not be read for this row |

### 👥 Who it's for

- **Revenue managers and hotel owners** watching what OTAs charge for their own rooms and their comp set, night by night.
- **Travel affiliates and metasearch builders** who need a price feed across every OTA from one source instead of integrating each one.
- **Rate parity and distribution teams** checking that no channel is undercutting the direct rate.
- **Market analysts** measuring what a city costs on a given date, and how that moves as the date approaches.
- **Anyone building a "book on the cheapest site" tool** - the bookable deep link per vendor is already in the row.

### ⚙️ How to monitor hotel prices for a date

1. Put your destination in **Searches**, for example `hotels in Lisbon`. A bare city name works too.
2. Set the stay. For a one-off, fill in **Check-in date** and **Check-out date**. For a monitor, leave those empty and set **Or check in this many days from today** to something like `21`, with **Nights** at `2`.
3. Set **Adults**, **Rooms** and any **Children's ages** - occupancy changes every quote.
4. Pick your **Currency**. Every vendor in the ladder is converted to it, so the numbers compare directly.
5. Leave **Include the per-vendor price ladder** on. That second fetch per hotel is the whole point.
6. Set **Max hotels** to how many properties you want. Start at the default 25.
7. Run it, then open the **Cheapest vendor per hotel** view in the results to see the spread at a glance.
8. To track the same properties over time, copy the `url` values from your first run into **Specific hotels**, then schedule the Actor daily. With a relative check-in, every run asks about the same stay shape.

### 📥 Input

```json
{
  "searchQueries": ["hotels in Lisbon"],
  "checkInDaysAhead": 21,
  "nights": 2,
  "adults": 2,
  "rooms": 1,
  "currency": "EUR",
  "includePriceLadder": true,
  "maxItems": 25,
  "minRating": 4
}
```

| Field | Type | Default | Description |
|---|---|---|---|
| `searchQueries` | array | - | Destinations, place names, or pasted Google Hotels search URLs |
| `hotelUrls` | array | - | Specific `google.com/travel/hotels/entity/...` URLs or bare entity tokens |
| `checkInDate` / `checkOutDate` | string | - | Absolute stay, as `2026-11-10`. Wins over the relative offset |
| `checkInDaysAhead` | integer | - | Relative check-in for scheduled runs |
| `nights` | integer | `1` | Used when no check-out date is given |
| `adults` | integer | `2` | Guests in the booking |
| `childrenAges` | array | - | One age per child; Google prices children by age |
| `rooms` | integer | `1` | Rooms the party needs |
| `currency` | string | `USD` | Three-letter code every price is converted to |
| `includePriceLadder` | boolean | `true` | Off = one headline price per hotel, one fetch, faster |
| `includeVacationRentals` | boolean | `false` | Keep the rental listings Google mixes into hotel results |
| `maxItems` | integer | `25` | Hotels to return across all searches. `0` = no cap |
| `minRating` / `minStars` / `maxNightlyPrice` | integer | - | Filters applied to the search card, before the paid detail fetch |

### 📤 Output

```json
{
  "name": "easyHotel Lisbon",
  "propertyType": "hotel",
  "checkInDate": "2026-11-10",
  "checkOutDate": "2026-11-12",
  "nights": 2,
  "currency": "EUR",
  "priceDisplay": "€70",
  "lowestPrice": 70.0,
  "vendorCount": 19,
  "cheapestVendor": "Amimir.com",
  "cheapestVendorPrice": 70.0,
  "highestVendorPrice": 84.0,
  "priceSpread": 14.0,
  "priceLadder": [
    {
      "vendor": "Booking.com",
      "nightlyPrice": 84.0,
      "stayTotal": 168.0,
      "sponsored": false,
      "bookingUrl": "https://www.booking.com/searchresults.en.html?checkin=2026-11-10..."
    },
    {
      "vendor": "easyHotel.com",
      "nightlyPrice": 76.0,
      "stayTotal": 153.0,
      "sponsored": false,
      "bookingUrl": "https://www.easyhotel.com/hotels/portugal/lisbon/lisbon?startDate=2026-11-10..."
    }
  ],
  "rating": 4.1,
  "reviewCount": 1963,
  "reviewsBySource": [
    { "source": "Tripadvisor", "rating": 3.5, "ratingMax": 5, "reviewCount": 236 }
  ],
  "address": "R. de Santa Marta 60, 1150-006 Lisboa",
  "phone": "21 052 0600",
  "website": "https://www.easyhotel.com/hotels/portugal/lisbon/lisbon",
  "checkInTime": "3:00 PM",
  "checkOutTime": "12:00 PM",
  "url": "https://www.google.com/travel/hotels/entity/ChkIy6arwemv3I1AGg0vZy8xMWcxaGY4YndtEAE"
}
```

Five ready-made dataset views: **Hotels**, **Cheapest vendor per hotel**, **Full price ladder**, **Ratings and reviews**, and **Property details**. Export any of them to CSV, JSON or Excel.

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

**$4.99 per 1,000 hotels.** No start fee, no monthly rental, and you are only charged for rows that reach your dataset - a hotel excluded by `minRating`, `minStars`, `maxNightlyPrice` or the vacation-rental filter costs you nothing, because those filters run before the paid fetch.

| Job | Hotels | Cost |
|---|---|---|
| Default first run, one city | 25 | $0.12 |
| A city's full hotel list for one date | 200 | $1.00 |
| Twenty tracked properties, daily for a month | 600 | $3.00 |
| Four cities, four dates | 1,600 | $7.98 |

The levers: `maxItems` caps the row count directly, and turning `includePriceLadder` off halves the work per hotel if you only need a list with one price each.

### 🚀 Ready-made examples

Each of these is a saved configuration you can open, tweak and run:

- [Compare Lisbon hotel prices across every booking site](https://apify.com/webdata_labs/google-hotels-scraper/examples/lisbon-hotel-prices-across-booking-sites)
- [Find the cheapest booking site for one specific hotel](https://apify.com/webdata_labs/google-hotels-scraper/examples/cheapest-booking-site-for-a-specific-hotel)
- [4-star hotel prices in New York for your dates](https://apify.com/webdata_labs/google-hotels-scraper/examples/new-york-4-star-hotel-prices-by-date)
- [London hotel rate parity check across OTAs](https://apify.com/webdata_labs/google-hotels-scraper/examples/london-hotel-rate-parity-check)
- [Cheap hotels under 100 for a weekend stay](https://apify.com/webdata_labs/google-hotels-scraper/examples/cheap-hotels-under-100-for-a-weekend)

### 🔁 Run it on the Apify platform

Schedule it daily to build a price history, call it from the API, or wire the dataset into Make, Zapier, Google Sheets, a webhook or your own database. Runs, logs and failures are monitored on the platform.

### ⚠️ Limits and caveats

- **A price is a snapshot.** Hotel rates move hourly. Two runs an hour apart can legitimately disagree.
- **The headline price and the ladder can differ by a few percent.** The results list and the detail view are two Google surfaces refreshed on different clocks. Both numbers are Google's; the ladder is the one priced for your exact dates.
- **Google's result count is not a hotel count.** A city search claims 15,000 matches, but the pages start repeating after a few hundred properties. The Actor stops when a page brings nothing new rather than chasing that number.
- **Some properties have no ladder.** Small guest houses are often quoted by a single site, or by none for your dates. `priceLadderStatus` says which case you hit.
- **Sponsored slots are included but tagged.** They quote different rates to the organic listings, so `cheapestVendor` and `priceSpread` are computed from the organic ones only.
- **No per-room-type breakdown.** See the ❌ list above.
- Prices are converted by Google, so a currency you pick is a conversion of the vendor's own currency, not necessarily the amount that will be charged at booking.

### 🧩 Related Actors

- **Booking.com Scraper** - when you want one OTA in depth rather than every OTA at once.
- **Google Maps Business Scraper** - the same properties as local businesses, with contact data.
- **Airbnb Market Intelligence** - the short-let side of the same market.

### ❓ FAQ

**Is scraping Google Hotels legal?** This Actor reads publicly visible pages that any signed-out visitor can load, and collects no personal data. You are responsible for how you use the output, including any terms that apply to the booking sites you link on to.

**Can I get prices for a specific date range?** Yes - that is the core feature. Set `checkInDate` and `checkOutDate`, or use `checkInDaysAhead` plus `nights` for a monitor that never goes stale.

**Does it return Booking.com and Expedia prices?** Yes, along with Hotels.com, Trip.com, Agoda, Priceline, Skyscanner, the hotel's own site and whoever else is live for your dates. Across 120 Lisbon hotels we measured a median of 12 vendors each, and up to 30.

**Can I track one hotel over time?** Put its Google Hotels URL in `hotelUrls` and schedule the Actor. Each run adds one row per day.

**Why do some hotels show only one vendor?** Because only one site is quoting them for your dates. Small properties and rental listings are usually in this group.

**Do I need a proxy?** No. There is no proxy input because proxying is handled internally when it is needed at all.

### 🛠️ Support

Something wrong with a run? Send the run URL, the input you used, and what you expected instead. Issues with a specific hotel are easiest to fix when you include its `url` from the dataset.

# Actor input Schema

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

What to search Google Hotels for: `hotels in Lisbon`, a bare place name, a neighbourhood, or a pasted `google.com/travel/search?q=...` URL. Google resolves the place itself, so a plain city name works. Results are deduplicated across searches, so overlapping queries never bill you twice for the same hotel.

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

Google Hotels property URLs such as `https://www.google.com/travel/hotels/entity/ChkIy6arwemv3I1AGg0vZy8xMWcxaGY4YndtEAE`, or the bare entity token from one. Use this to re-price a fixed set of properties on a schedule instead of re-running a whole city search. Every URL here is priced in full, price ladder included.

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

The first night of the stay, as `2026-11-10`. Leave empty to price tonight, or use the relative offset below instead — a fixed date goes stale on a schedule.

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

The morning the stay ends, as `2026-11-12`. If you set a check-in and leave this empty, the number of nights below is used.

## `checkInDaysAhead` (type: `integer`):

A relative check-in, used only when no check-in date is set. `21` prices a stay starting three weeks out. This is what makes a scheduled run a price monitor: it asks about the same stay shape every time it fires instead of drifting into the past.

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

Length of the stay, used with either date mode when no check-out date is set.

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

Guests in the booking. Occupancy changes what the vendors quote, so a two-adult and a four-adult search of the same hotel are genuinely different prices.

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

One entry per child, each their age at check-in. Many properties price children differently or not at all, which is why Google asks for ages rather than a count.

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

How many rooms the party needs.

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

Three-letter code the prices come back in, such as `USD`, `EUR` or `GBP`. Google converts on its side, so every vendor in the ladder is quoted in the same currency and the numbers are directly comparable.

## `includePriceLadder` (type: `boolean`):

On by default, and the reason to use this Actor. Each hotel gets a second fetch that returns every booking site quoting it for your dates — Booking.com, Expedia, Hotels.com, Trip.com, the hotel's own site and whoever else is live — with each one's nightly rate, stay total and a bookable deep link that already carries your dates. It also brings the address, phone, official website, check-in and check-out times, each OTA's own review score, and what guests keep mentioning. Turn it off for a fast, cheap list of hotels with a single headline price each.

## `includeVacationRentals` (type: `boolean`):

Google mixes whole-apartment and single-room rental listings into its hotel results. They are off by default because they are usually quoted by one booking site rather than a ladder of them, and because a rental listed room by room shows up several times for the same address. Turn this on to keep them, each tagged `vacation_rental` in `propertyType`.

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

Stop after this many hotels across every search. Set 0 for no cap. The default keeps a first run cheap and quick; a whole city is a few hundred hotels, not the 15,000 Google claims in its result count.

## `minRating` (type: `integer`):

Keep only hotels rated at or above this score out of 5. Hotels with no rating yet are excluded when this is set.

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

Keep only properties of at least this star class. Guest houses and hostels usually carry no class at all and are excluded when this is set.

## `maxNightlyPrice` (type: `integer`):

Keep only hotels whose headline nightly rate is at or below this number, in the currency above. Hotels Google shows no price for are excluded when this is set.

## Actor input object example

```json
{
  "searchQueries": [
    "hotels in Lisbon",
    "boutique hotels Porto"
  ],
  "hotelUrls": [
    "https://www.google.com/travel/hotels/entity/ChkIy6arwemv3I1AGg0vZy8xMWcxaGY4YndtEAE"
  ],
  "checkInDate": "2026-11-10",
  "checkOutDate": "2026-11-12",
  "checkInDaysAhead": 21,
  "nights": 1,
  "adults": 2,
  "childrenAges": [
    "7",
    "12"
  ],
  "rooms": 1,
  "currency": "EUR",
  "includePriceLadder": true,
  "includeVacationRentals": false,
  "maxItems": 25,
  "minRating": 4,
  "minStars": 4,
  "maxNightlyPrice": 200
}
```

# Actor output Schema

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

No description

## `bestDeals` (type: `string`):

No description

## `priceLadder` (type: `string`):

No description

## `reputation` (type: `string`):

No description

## `contacts` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

# 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 Lisbon"
    ],
    "checkInDaysAhead": 21,
    "nights": 1,
    "adults": 2,
    "rooms": 1,
    "currency": "USD",
    "includePriceLadder": true,
    "maxItems": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("webdata_labs/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 Lisbon"],
    "checkInDaysAhead": 21,
    "nights": 1,
    "adults": 2,
    "rooms": 1,
    "currency": "USD",
    "includePriceLadder": True,
    "maxItems": 25,
}

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

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "hotels in Lisbon"
  ],
  "checkInDaysAhead": 21,
  "nights": 1,
  "adults": 2,
  "rooms": 1,
  "currency": "USD",
  "includePriceLadder": true,
  "maxItems": 25
}' |
apify call webdata_labs/google-hotels-scraper --silent --output-dataset

```

## MCP server setup

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