# Google Hotels Scraper — Prices by Date, All Booking Sites (`dottti/google-hotels-prices`) Actor

Google Hotels prices for any city or hotel and your dates, guests and currency. Every booking site's offer with total, taxes and free cancellation, plus stars, rating, amenities, address and map point. Price-watch mode returns only changed prices.

- **URL**: https://apify.com/dottti/google-hotels-prices.md
- **Developed by:** [Dottti](https://apify.com/dottti) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 hotels

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

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Google Hotels Scraper: Prices by Date, All Booking Sites

Get hotel prices from Google Hotels for your dates, guests and currency. Search a city or area, or give a list of hotels. Each hotel row lists every booking site Google shows, with the nightly price, the stay total with taxes and fees, and free cancellation.

It works for any city. It is tested on Dubai, Abu Dhabi, Riyadh, Jeddah, Makkah, Doha and London.

### Who uses it

- **Travel agencies**: compare what each booking site charges for the same stay.
- **Hotel revenue managers**: track your hotel and your competitors every day. See when a rival drops its price, and on which site.
- **Price comparison sites**: fill a database of hotels, prices and booking sites for chosen dates.
- **Analysts**: study prices by city, star class, season or event dates.

### What you get per hotel

- Name, Google hotel id and Google Hotels link
- Star class, guest rating and number of reviews
- Price for your stay: nightly, total, before taxes, taxes, fees, currency
- Google's deal label when shown, for example "22% less than usual"
- Every booking site offer: site name, the hotel's own site flag, nightly price, stay total, free cancellation and its deadline, member-rate note, booking link
- Address, phone, coordinates, country, website, Google place id
- Amenities (Free Wi-Fi, Outdoor pool, Spa, Free parking and more), check-in and check-out times, short description, photo

Each search also gives one free status row. It says how many hotels Google returned and whether anything failed.

### Input examples

#### A city for fixed dates

```json
{
    "searches": ["Dubai"],
    "checkIn": "2026-10-30",
    "checkOut": "2026-11-01",
    "adults": 2,
    "currency": "AED",
    "maxHotelsPerSearch": 100
}
```

#### Several GCC cities in Saudi riyal, two weeks ahead

```json
{
    "searches": ["Riyadh", "Jeddah", "Makkah"],
    "checkInDaysFromNow": 14,
    "nights": 2,
    "adults": 2,
    "childrenAges": [6],
    "currency": "SAR",
    "country": "sa",
    "maxHotelsPerSearch": 50
}
```

#### A fixed list of hotels

Open the hotel on Google Hotels and copy the address bar. Paste one link per line.

```json
{
    "hotelUrls": [
        "https://www.google.com/travel/hotels/entity/ChUIrOmZudHNsKo4GgkvbS8wYnk3dDgQAQ",
        "https://www.google.com/travel/hotels/entity/ChYIxZWB1JjIlsoFGgovbS8wMnI5aDBqEAE"
    ],
    "checkInDaysFromNow": 7,
    "nights": 1,
    "currency": "USD"
}
```

#### Search tips

- Any place name works: a city, an area ("Downtown Dubai"), or a landmark ("hotels near Kingdom Centre Riyadh").
- Arabic queries work, for example "فنادق مكة".
- Filters: minimum star class, minimum guest rating and maximum nightly price.

### Output example

This row comes from a real run on 2026-10-21: Riyadh, 2 nights, 2 adults, SAR. The offers list is cut to 3 of 4 here, and the booking links are left out to keep it short.

```json
{
  "type": "hotel",
  "searchQuery": "Riyadh",
  "position": 2,
  "name": "Ramada by Wyndham Riyadh King Fahd Road",
  "hotelId": "ChkI4__x66_Dv7EhGg0vZy8xMXQ2bDBiZzJ2EAE",
  "googleHotelsUrl": "https://www.google.com/travel/hotels/entity/ChkI4__x66_Dv7EhGg0vZy8xMXQ2bDBiZzJ2EAE?hl=en&gl=sa&ts=CAESCgoCCAMKAggDEAEaGgoAEhYSFAoHCOoPEAoYHxIHCOoPEAsYAhgCKgcKBToDU0FS",
  "hotelClass": 5,
  "hotelClassText": "5-star hotel",
  "rating": 4.4,
  "reviewCount": 2059,
  "checkIn": "2026-10-31",
  "checkOut": "2026-11-02",
  "nights": 2,
  "adults": 2,
  "childrenAges": [],
  "currency": "SAR",
  "price": {
    "currency": "SAR",
    "nightly": 400.28,
    "nightlyText": "SAR 400",
    "total": 800.56,
    "totalText": "SAR 801",
    "beforeTaxes": 663,
    "taxes": 137.56,
    "fees": 0,
    "includesTaxesAndFees": true
  },
  "deal": "22% less than usual",
  "lowestOffer": { "provider": "Agoda", "nightly": 400.28, "total": 800.56, "freeCancellation": false },
  "offersCount": 4,
  "offersStatus": "ok",
  "offers": [
    {
      "provider": "Agoda",
      "providerId": 100337601,
      "isOfficialSite": false,
      "nightly": 400.28,
      "nightlyText": "SAR 400",
      "total": 800.56,
      "totalText": "SAR 801",
      "freeCancellation": false,
      "freeCancellationUntil": null,
      "guests": 2,
      "memberRateNote": null
    },
    {
      "provider": "Ramada by Wyndham Riyadh King Fahd Road",
      "providerId": 1195673994,
      "isOfficialSite": true,
      "nightly": 447.38,
      "nightlyText": "SAR 447",
      "total": 894.75,
      "totalText": "SAR 895",
      "freeCancellation": false,
      "freeCancellationUntil": null,
      "guests": 2,
      "memberRateNote": "Get 5% off with free enrollment"
    },
    {
      "provider": "Booking.com",
      "providerId": 184,
      "isOfficialSite": false,
      "nightly": 447.38,
      "nightlyText": "SAR 447",
      "total": 894.75,
      "totalText": "SAR 895",
      "freeCancellation": false,
      "freeCancellationUntil": null,
      "guests": 2,
      "memberRateNote": null
    }
  ],
  "freeCancellationAvailable": null,
  "address": "King Fahd Rd, An Namudhajiyah, Riyadh 12734",
  "phone": "011 506 0111",
  "coordinates": { "lat": 24.660253599999997, "lng": 46.700370299999996 },
  "countryCode": "SA",
  "amenities": ["Breakfast ($)", "Free Wi-Fi", "Free parking", "Indoor pool", "Hot tub", "Air conditioning", "Fitness center", "Bar", "Restaurant", "Room service", "Airport shuttle", "Full-service laundry", "Accessible"],
  "amenityCodesUnknown": [7],
  "checkInTime": "2:00 PM",
  "checkOutTime": "12:00 PM",
  "description": "Skyscraper hotel with polished rooms, casual restaurants & a rooftop lounge, plus an indoor pool.",
  "placeId": "ChIJj4qPtTYDLz4R4398_Rr-YiE",
  "language": "en",
  "country": "sa",
  "scrapedAt": "2026-10-21T14:25:52.654Z"
}
```

Field notes:

- `nightly` is the average nightly price with taxes and fees. `total` is the whole stay.
- `freeCancellation` is `true`, `false`, or `null` when Google shows nothing about it for that site. `freeCancellationUntil` gives the deadline, for example "Oct 30 6:00 PM".
- `freeCancellationAvailable` is `true` when at least one site offers it, `false` when every site says no, and `null` otherwise.
- `amenityCodesUnknown` holds Google amenity codes this actor has no name for yet.

The status row for the same search:

```json
{
  "type": "search_status",
  "query": "Riyadh",
  "googleQuery": "hotels in Riyadh",
  "resolvedPlace": "Riyadh",
  "status": "ok",
  "checkIn": "2026-10-31",
  "checkOut": "2026-11-02",
  "hotelsFound": 20,
  "hotelsDelivered": 20,
  "hotelsWithoutPrice": 0,
  "hotelsFilteredOut": 0,
  "offerLookupsFailed": 0,
  "pages": 1,
  "error": null,
  "seconds": 14.4,
  "charged": false
}
```

`status` is `ok`, `partial` (some pages or offer lookups failed), `no_results` or `failed`. One failed search never stops the other searches in the run.

Turn on **Also output one row per booking-site offer** to get flat offer rows. Each has the hotel id, hotel name, stay dates and one site's price. The dataset also has an "Offers per booking site" view that unwinds the offers from the hotel rows.

### Daily price tracking

1. Fill in your searches or hotel URLs.
2. Leave **Check-in date** empty. Set **Check-in in N days**, for example 7, and **Nights**.
3. Turn on **Price watch: only output changed prices** and give a **Watch list name**, for example `riyadh-competitors`.
4. Save the input as a task. Add a schedule in Apify, for example every day at 06:00 Riyadh time.

The first run outputs every hotel with `priceWatch.status` = `new`. Later runs output only hotels whose stay total or any booking-site price changed, plus hotels seen for the first time. Each changed row lists the old value, the new value and the difference per site:

```json
"priceWatch": {
  "status": "changed",
  "previousCheckAt": "<time of the previous run>",
  "changes": [
    { "field": "total", "previous": "<old total>", "current": "<new total>", "difference": "<new - old>", "percent": "<change in %>" },
    { "field": "offer", "provider": "Booking.com", "previous": "<old>", "current": "<new>", "difference": "<new - old>" }
  ]
}
```

Unchanged hotels are skipped and not charged. The saved state lives in the key-value store `google-hotels-price-watch`. Runs compare the same hotel, the same stay dates, guests and currency. Stays whose check-in date has passed are removed from the state.

Google reorders search results between runs. For a stable list, track hotels by URL.

### Pricing

Pay per result:

- **$2.00 per 1,000 hotels** (event `hotel`). A hotel is charged only when it has a price for your dates.
- **$0.25 per 1,000 offer rows** (event `offer`), only when you turn on flat offer rows. Offers inside the hotel row are included in the hotel price.
- Free: status rows, unpriced hotels, hotels removed by your filters, unchanged hotels in price-watch mode, failed searches.

Example: 3 cities with 100 hotels each, every booking site included, costs $0.60.

You can set a maximum cost per run in Apify. The actor stops fetching when the next hotel would go over it.

### Speed and limits

- About 0.7 seconds per hotel with every booking site, measured on 200 Dubai hotels (141 seconds). About 0.2 seconds per hotel with **Include prices from every booking site** off.
- Google shows about 18 new hotels per page. Up to 500 hotels per search.
- The input accepts stays of 1 to 30 nights, check-in up to 330 days ahead, and up to 12 adults and 8 children in one room. Google may show fewer prices for dates far ahead.
- Prices depend on the country the request comes from. To see the price a guest in Saudi Arabia sees, set **Country** to `sa` and pick an Apify residential proxy in Saudi Arabia.
- Google sometimes shows member prices or prices for a different room type on different sites. The actor reports what Google shows.
- Room-by-room rates and reviews are out of scope for now.

### Reliability

- Requests start at least 400 ms apart. Hotel lookups run 4 at a time by default.
- When Google answers with errors or a consent page, the actor waits longer, starts a new session, and then moves up the proxy ladder: no proxy, Apify datacenter, Apify residential.
- The run summary (key-value store record `RUN_SUMMARY`) shows requests, HTTP status codes, retries, the proxy tier used and bytes per hotel.

### Data and privacy

The actor reads public Google Hotels pages. It does not log in, and it does not solve captchas. Hotel rows hold business information only. Check the rules that apply to your use of the data, such as Google's terms and data protection law in your country.

# Actor input Schema

## `searches` (type: `array`):

Places to search, the same as typing into Google Hotels. Examples: Dubai, Riyadh, Makkah, Downtown Dubai, London, hotels near Kingdom Centre Riyadh. Each entry becomes its own search with its own status row.

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

Google Hotels pages of single hotels, for example https://www.google.com/travel/hotels/entity/ChYIxZWB1JjIlsoFGgovbS8wMnI5aDBqEAE . A bare hotel id (starts with Ch) also works. Use this to track a fixed list of hotels.

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

Format YYYY-MM-DD. Leave empty to use 'Check-in in N days' below, which is best for daily schedules.

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

Format YYYY-MM-DD. Leave empty to use the number of nights below.

## `checkInDaysFromNow` (type: `integer`):

Used when Check-in date is empty. 14 means two weeks from the day the run starts. A daily schedule then always tracks the same distance ahead.

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

Length of stay, used when Check-out date is empty.

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

Adults in one room.

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

One age per child, 0 to 17. Example: \[5, 9] for two children. Prices change with children because sites price per guest.

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

3-letter code. Examples: USD, SAR, AED, QAR, KWD, BHD, OMR, EUR, GBP.

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

Google interface language, for example en or ar. It changes hotel names and descriptions where Google has a translation. Amenity names are in English.

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

2-letter Google region code, for example us, sa, ae, gb. Booking sites can show different prices by country. The proxy location also affects this.

## `maxHotelsPerSearch` (type: `integer`):

Google shows about 18 new hotels per page. Large cities have several hundred.

## `includeOffers` (type: `boolean`):

On: each hotel row lists every booking site Google shows (the hotel's own site, Booking.com, Agoda, Expedia and others) with nightly price, stay total with taxes and fees, and free cancellation. Also adds address and phone. Off: faster, only the lowest price per hotel.

## `offerRows` (type: `boolean`):

Adds a separate row per hotel and booking site, easy to load into a spreadsheet. These rows are charged as 'offer' events. Offers stay inside the hotel row either way.

## `includeBookingLinks` (type: `boolean`):

Google redirect links to each booking site. They are long. Turn off to keep files small.

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

0 = any. 4 keeps 4- and 5-star hotels.

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

0 = any. Google ratings run from 1 to 5.

## `maxNightlyPrice` (type: `number`):

0 = any. In the currency above, taxes and fees included.

## `includeUnpriced` (type: `boolean`):

Sold-out or unpriced hotels are skipped by default. On: they are output free of charge with priceStatus set.

## `onlyChanged` (type: `boolean`):

Compares each hotel and stay with the previous run of the same watch list. Only new hotels and changed prices are output and charged. Each row carries priceWatch with the old and new values.

## `watchListName` (type: `string`):

Name for the saved price state, for example dubai-weekend. Runs with the same name compare against each other. Empty: a name is made from your searches, hotels, guests and currency. Setting a name also adds priceWatch to every row.

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

Leave empty for the automatic ladder: no proxy first, then Apify datacenter, then Apify residential only if Google keeps refusing. Pick a residential country to see prices for that market.

## `autoProxyFallback` (type: `boolean`):

Move to the next proxy tier when Google keeps refusing.

## `allowResidentialFallback` (type: `boolean`):

Residential proxy is the most reliable tier.

## `concurrency` (type: `integer`):

Hotel price lookups in flight at once. Requests still start at least the delay below apart.

## `requestDelayMs` (type: `integer`):

Minimum gap between request starts.

## `maxRetries` (type: `integer`):

Attempts per request before a search or hotel is marked failed. Each retry waits longer and may switch session or proxy tier.

## Actor input object example

```json
{
  "searches": [
    "Dubai"
  ],
  "checkInDaysFromNow": 14,
  "nights": 1,
  "adults": 2,
  "childrenAges": [],
  "currency": "USD",
  "language": "en",
  "country": "us",
  "maxHotelsPerSearch": 10,
  "includeOffers": true,
  "offerRows": false,
  "includeBookingLinks": true,
  "minHotelClass": 0,
  "minRating": 0,
  "maxNightlyPrice": 0,
  "includeUnpriced": false,
  "onlyChanged": false,
  "autoProxyFallback": true,
  "allowResidentialFallback": true,
  "concurrency": 4,
  "requestDelayMs": 400,
  "maxRetries": 5
}
```

# Actor output Schema

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

Hotel rows with price, offers per booking site, stars, rating, amenities, address and coordinates, plus status rows.

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

Status per search, price-watch counts, requests, HTTP status codes, retries, proxy tier and bytes per hotel.

# 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 = {
    "searches": [
        "Dubai"
    ],
    "checkInDaysFromNow": 14,
    "nights": 1,
    "adults": 2,
    "currency": "USD",
    "maxHotelsPerSearch": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("dottti/google-hotels-prices").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 = {
    "searches": ["Dubai"],
    "checkInDaysFromNow": 14,
    "nights": 1,
    "adults": 2,
    "currency": "USD",
    "maxHotelsPerSearch": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("dottti/google-hotels-prices").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 '{
  "searches": [
    "Dubai"
  ],
  "checkInDaysFromNow": 14,
  "nights": 1,
  "adults": 2,
  "currency": "USD",
  "maxHotelsPerSearch": 10
}' |
apify call dottti/google-hotels-prices --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dottti/google-hotels-prices"
        }
    }
}
```

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/RpKIeF8f5GYwuFw60/builds/i15IPe6kVkAlUxKoJ/openapi.json
