# Google Hotels API > Source: https://scrape.do/documentation/google-scraper-api/hotels/ Scrape Google Hotels listings and per-vendor pricing as structured JSON ![Google Hotels API](/uploads/google-hotels-api.svg) The Google Hotels API returns structured property data from Google Hotels in two steps: 1. **Listing** — search hotels and get property metadata (name, photos, GPS, ratings, amenities, per-night price) plus a `detail_token` for each property. 2. **Detail** — pass that `detail_token` to fetch the full per-vendor offer shelf (`Booking.com`, `Hotels.com`, `Agoda`, …) with live `rate_per_night` and `total_rate`. > [!NOTE] > **Credit Usage:** Each successful request costs **10 credits**. For bulk processing, use the [Async API with plugins](/documentation/async-api/plugins/). ## Key Features - **Two-step flow** — listing call returns properties + `detail_token`; detail call returns the vendor pricing shelf. - **Structured JSON** — each property has name, description, GPS, hotel class, rating, reviews, amenities, images, per-night price, total rate, check-in/check-out times, nearby places, and a star-by-star ratings histogram. - **Per-vendor pricing** — the detail endpoint returns `booking_sources[]` with sponsored ("Featured options") and organic ("All options") entries unified into one ranked list. - **Currency localization** — per-request `currency` (`USD`, `EUR`, `GBP`, `TRY`, …). Combine with `hl` and `gl` for full regional search. - **Sort & filter** — lowest price / highest rating / most reviewed; price range, minimum rating, hotel class, amenities, free cancellation, eco-certified, special offers. - **Vacation rentals mode** — `property_types=12` switches to vacation rentals where available. - **Pagination** — token-based with `next_page_token`. - **No blocks or CAPTCHAs** — handled automatically. --- ## Listing Endpoint ``` GET https://api.scrape.do/plugin/google/hotels ``` ### Basic Example **cURL (API mode)** ```bash curl --location --request GET 'https://api.scrape.do/plugin/google/hotels?token=&q=Bali+hotels&check_in_date=2026-05-01&check_out_date=2026-05-03' ``` **Python (API mode)** ```python import requests import json token = "" url = f"https://api.scrape.do/plugin/google/hotels?token={token}&q=Bali+hotels&check_in_date=2026-05-01&check_out_date=2026-05-03" response = requests.request("GET", url) print(json.dumps(response.json(), indent=2)) ``` **Node.js (API mode)** ```javascript const axios = require('axios'); const token = ""; const url = `https://api.scrape.do/plugin/google/hotels?token=${token}&q=Bali+hotels&check_in_date=2026-05-01&check_out_date=2026-05-03`; axios.get(url) .then(response => { console.log(JSON.stringify(response.data, null, 2)); }) .catch(error => { console.error(error); }); ``` *(Go, Ruby, Java, C#, PHP examples are also available on the HTML version.)* ```bash curl "https://api.scrape.do/plugin/google/hotels?token=$TOKEN&q=Bali+hotels&check_in_date=2026-05-01&check_out_date=2026-05-03" ``` > [!WARNING] > **Occupancy parameters are not supported.** Results always reflect the default occupancy of **2 adults, 0 children**. ### Query Guidelines Use simple location-based queries for best results: | Recommended | Avoid | |---|---| | `Paris hotels` | `Paris luxury hotels near Eiffel Tower` | | `Tokyo hotels` | `Tokyo traditional ryokan hotels` | | `Edinburgh hotels` | `Edinburgh Royal Mile hotels` | Overly specific queries can return empty results. Simple `" hotels"` queries have the highest success rate. ### Request Parameters #### Required | Parameter | Type | Description | |-----------|------|-------------| | `token` | string | Your Scrape.do API authentication token | | `q` | string | Hotel search query. Use simple `" hotels"` form for best results | | `check_in_date` | string | Check-in date in `YYYY-MM-DD` | | `check_out_date` | string | Check-out date in `YYYY-MM-DD`. Must be after `check_in_date` | #### Localization | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `hl` | string | `en` | Language code | | `gl` | string | `us` | Country code | | `currency` | string | `USD` | Currency code (`EUR`, `GBP`, `TRY`, …) | #### Sorting | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `sort_by` | integer | `0` (relevance) | `3` = lowest price, `8` = highest rating, `13` = most reviewed | #### Filters | Parameter | Type | Description | |-----------|------|-------------| | `min_price` | integer | Minimum nightly price (≥ 0) in the requested currency | | `max_price` | integer | Maximum nightly price (≥ 0 and ≥ `min_price`) in the requested currency | | `rating` | integer | Minimum rating: `7` (3.5+), `8` (4.0+), `9` (4.5+) | | `hotel_class` | string | Comma-separated star ratings (`4,5` for 4★ and 5★). Each value 2–5 | | `amenities` | string | Comma-separated amenity codes (see [Amenity Codes](#amenity-codes)) | | `property_types` | string | Comma-separated property type codes. `12` = vacation rentals (switches mode) | | `free_cancellation` | boolean | Only properties with free cancellation. Accepts `true` or `1` | | `eco_certified` | boolean | Only eco-certified properties | | `special_offers` | boolean | Only properties with special offers | #### Pagination & Page Size | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `next_page_token` | string | — | From the previous response's `pagination.next_page_token`. Pass back unchanged | | `limit` | integer | `20` | Maximum properties to return on the page. Range: 1–20 | ### More Examples ```bash # Turkish locale + TRY currency curl "https://api.scrape.do/plugin/google/hotels?q=Istanbul+hotels&check_in_date=2026-05-01&check_out_date=2026-05-03&hl=tr&gl=tr¤cy=TRY&token=$TOKEN" # Cheapest first within £100–£300 curl "https://api.scrape.do/plugin/google/hotels?q=London+hotels&check_in_date=2026-05-01&check_out_date=2026-05-03&sort_by=3&min_price=100&max_price=300¤cy=GBP&token=$TOKEN" # 4–5 star, free cancellation curl "https://api.scrape.do/plugin/google/hotels?q=Dubai+hotels&check_in_date=2026-05-01&check_out_date=2026-05-03&hotel_class=4,5&free_cancellation=true&token=$TOKEN" # Eco-certified, 4.5+ rating, with pool curl "https://api.scrape.do/plugin/google/hotels?q=Maldives+hotels&check_in_date=2026-05-01&check_out_date=2026-05-03&rating=9&eco_certified=true&amenities=22&token=$TOKEN" # Vacation rentals curl "https://api.scrape.do/plugin/google/hotels?q=Santorini+hotels&check_in_date=2026-05-01&check_out_date=2026-05-03&property_types=12&token=$TOKEN" # Page 2 (token from a previous response) curl "https://api.scrape.do/plugin/google/hotels?q=Paris+hotels&check_in_date=2026-05-01&check_out_date=2026-05-03&next_page_token=CgsI...&token=$TOKEN" ``` ### Response #### Top-Level Structure ```json { "search_parameters": { ... }, "search_information": { "total_results": 18 }, "properties": [ ... ], "ads": [ ... ], "brands": [ ... ], "pagination": { ... } } ``` #### `properties[]` ```json { "type": "hotel", "name": "The Anvaya Beach Resort Bali", "description": "Sophisticated resort offering 8 pools, 2 restaurants & a spa, plus a private beach & a kids' club.", "gps_coordinates": { "latitude": -8.7322535, "longitude": 115.1659877 }, "hotel_class": "5-star hotel", "extracted_hotel_class": 5, "overall_rating": 4.7, "reviews": 14342, "amenities": [6, 29, 16, 22, 2, 8, 26, 5, 4, 23, 24, 14, 1, 31, 27, 7, 11], "images": [ { "thumbnail": "https://lh3.googleusercontent.com/...", "original_image": "https://lh3.googleusercontent.com/..." } ], "detail_token": "Q2hrSXZfSHlpTktIcGY2eUFSb01MMmN2TVhvemRHSm5aM0J6RUFFfDB4MTRiZTZkN2IxYjkwM2VjMTowYzZkMjFhMzRiMDgwNGNkZQ", "check_in_time": "3:00 PM", "check_out_time": "12:00 PM", "ratings": [ { "stars": 5, "percent": 91, "count": 4546 }, { "stars": 4, "percent": 7, "count": 363 }, { "stars": 3, "percent": 1, "count": 96 } ], "reviews_breakdown": [ { "name": "Cleanliness", "sentiment": 0.42, "total_mentioned": 88, "positive": 71, "negative": 8, "neutral": 9 } ], "price": { "display": "USD 187", "amount": 187.42, "currency": "USD" }, "total_rate": { "display": "USD 374", "amount": 374, "currency": "USD" }, "nearby_places": [ { "name": "Beach", "transportations": [{ "type": 0, "duration": "10 min" }] } ] } ``` | Field | Type | Always present | Description | |-------|------|:-:|-------------| | `type` | string | yes | `"hotel"` or `"vacation rental"` | | `name` | string | yes | Property name | | `description` | string | | Short description | | `gps_coordinates` | object | yes | `{ latitude, longitude }` | | `hotel_class` | string | | Star rating label (e.g. `"5-star hotel"`) | | `extracted_hotel_class` | int | | Numeric star rating | | `overall_rating` | float | | Guest rating out of 5 | | `reviews` | int | | Number of guest reviews | | `amenities` | int[] | yes | Amenity codes (see [Amenity Codes](#amenity-codes)). Empty array when none | | `images` | object[] | yes | `[{ thumbnail, original_image }]`. Empty array when none | | `detail_token` | string | yes | Opaque token. Pass to the [detail endpoint](#detail-endpoint) to fetch per-vendor pricing | | `check_in_time` | string | | Property check-in clock time (e.g. `"3:00 PM"`) | | `check_out_time` | string | | Property check-out clock time | | `ratings` | object[] | | 5→1 star histogram entries: `{ stars, percent, count }` | | `reviews_breakdown` | object[] | | Guest sentiment by category (`Cleanliness`, `Service`, …) | | `price` | object | | Per-night rate in the requested currency. See [Price](#price) | | `total_rate` | object | | Total stay cost across the date range. See [Price](#price) | | `nearby_places` | object[] | | Points of interest with transit-mode durations | ##### Price | Field | Type | Description | |-------|------|-------------| | `display` | string | Formatted price as returned (e.g., `"USD 187"`, `"TRY 1,895"`) | | `amount` | float | Numeric value (e.g., `187.42`) | | `currency` | string | ISO 4217 code reflecting the request's `currency` | #### `ads[]` Sponsored hotel results attached to the listing, when present. Each entry is flagged with `"sponsored": true`. ```json { "sponsored": true, "name": "The LINQ - A Caesars Rewards Destination", "source": "Booking.com", "source_icon": "//www.gstatic.com/travel-hotels/branding/icon_184.png", "click": "/aclk?sa=l&ai=...", "gps_coordinates": { "latitude": 36.1206, "longitude": -115.1717 }, "hotel_class": 4, "thumbnail": "//lh3.googleusercontent.com/proxy/...", "reviews": 42322, "amenities": [11, 23, 4, 24, 8, 29, 2], "price": { "display": "$291", "amount": 290.81, "currency": "USD" }, "total_rate": { "display": "$582", "amount": 582, "currency": "USD" } } ``` #### `brands[]` Hotel chain / brand index attached to the listing, when present. ```json [ { "id": 21, "name": "Ibis" }, { "id": 61, "name": "Marriott Hotels & Resorts" } ] ``` #### `pagination` Included when more pages exist. Omitted on the last page. ```json { "current_from": 1, "current_to": 20, "next_page_token": "CgsI..." } ``` Pages 2+ may overlap by up to 2 entries — dedupe across pages by `name` + `gps_coordinates`. The `detail_token` is **not** stable across pages, so the same property may receive a different `detail_token` on each page. --- ## Detail Endpoint ``` GET https://api.scrape.do/plugin/google/hotels/detail ``` Returns the **per-vendor offer shelf** for a single property — each booking source's `rate_per_night`, `total_rate`, and quoted occupancy in the requested currency, with sponsored ("Featured options") and organic ("All options") entries unified into one ranked list. Property metadata (name, photos, GPS, ratings, amenities) is **not** repeated in the detail response — it was already returned by the listing call. Merge client-side using the `detail_token` as the join key. ### Two-Step Example ```bash # Step 1 — listing curl "https://api.scrape.do/plugin/google/hotels?token=$TOKEN&q=Bali+hotels&check_in_date=2026-05-01&check_out_date=2026-05-03¤cy=USD" # → response.properties[i].detail_token # Step 2 — detail (per-vendor pricing for one property) curl "https://api.scrape.do/plugin/google/hotels/detail?token=$TOKEN&detail_token=Q2hrSXZfSHlpTktIcGY2eUFSb01MMmN2TVhvemRHSm5aM0J6RUFFfDB4MTRiZTZkN2IxYjkwM2VjMTowYzZkMjFhMzRiMDgwNGNkZQ&check_in_date=2026-05-01&check_out_date=2026-05-03¤cy=USD" ``` Use the **same** `check_in_date`, `check_out_date`, and `currency` in both calls. ### Detail Parameters #### Required | Parameter | Type | Description | |-----------|------|-------------| | `token` | string | Your Scrape.do API token | | `detail_token` | string | From a listing response's `properties[].detail_token`. Pass it back unchanged | | `check_in_date` | string | `YYYY-MM-DD` | | `check_out_date` | string | `YYYY-MM-DD`. Must be after `check_in_date` | #### Optional | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `currency` | string | `USD` | ISO 4217 currency code | | `gl` | string | `us` | Country code | | `hl` | string | `en` | Language code | ### Detail Response ```json { "search_parameters": { "engine": "google_hotels_detail", "detail_token": "Q2hrSXZfSHlp...", "check_in_date": "2026-05-01", "check_out_date": "2026-05-03", "currency": "USD", "gl": "us", "hl": "en" }, "property": { "detail_token": "Q2hrSXZfSHlp...", "booking_sources": [ { "sponsored": true, "name": "Booking.com", "id": 184, "click": "/aclk?...", "icon": "//www.gstatic.com/travel-hotels/branding/icon_184.png", "rate_per_night": { "display": "$221", "amount": 221.04, "currency": "USD" }, "total_rate": { "display": "$442", "amount": 442.08, "currency": "USD" }, "num_guests": 2 }, { "name": "Hotels.com", "id": 1162912808, "click": "/aclk?...", "icon": "//www.gstatic.com/travel-hotels/branding/...", "rate_per_night": { "display": "$227", "amount": 227.33, "currency": "USD" }, "total_rate": { "display": "$455", "amount": 454.67, "currency": "USD" }, "num_guests": 2 } ] } } ``` #### `booking_sources[]` Each entry is one vendor's quote for the requested dates and currency. Sponsored entries appear first and carry `"sponsored": true`; organic entries follow. | Field | Type | Always present | Description | |-------|------|:-:|-------------| | `sponsored` | boolean | | `true` on paid placements ("Featured options"); omitted on organic offers | | `name` | string | yes | Vendor brand (e.g. `"Booking.com"`, `"Hotels.com"`, `"Agoda"`) | | `id` | integer | | Internal source identifier | | `click` | string | | Click-through URL that redirects to the vendor's listing | | `icon` | string | | Vendor brand icon URL | | `rate_per_night` | object | | Per-night rate. See [Price](#price). Omitted when not quoted | | `total_rate` | object | | Total stay cost. See [Price](#price). Omitted when not quoted | | `num_guests` | integer | | Occupancy the rate is quoted for — always `2` when present | `rate_per_night.currency` and `total_rate.currency` reflect the request's `currency`. Numeric `amount` values are normalized — thousands separators are stripped before parsing. --- ## Amenity Codes Raw integer codes from Google's classification. Common values: | Code | Amenity | Code | Amenity | |------|---------|------|---------| | 1 | Fitness center | 16 | Outdoor pool | | 2 | Bar | 17 | Pet-friendly | | 4 | Restaurant | 20 | Indoor pool | | 5 | Room service | 22 | Pool | | 6 | Free breakfast | 23 | Air-conditioned | | 7 | Kids' club | 24 | Kitchen / kitchenette | | 8 | Spa | 25 | Smoke-free | | 9 | Business center | 26 | Full-service laundry | | 10 | Child-friendly | 27 | Free Wi-Fi | | 11 | Accessible | 29 | Wi-Fi | | 14 | Beach access | 31 | Airport shuttle | | 15 | Parking | | | > [!NOTE] > **Codes may change without notice.** Raw integer values are forwarded as-is from Google. The same codes are returned in `properties[].amenities[]`, so they round-trip safely. --- ## Property Types | Value | When returned | |-------|---------------| | `"hotel"` | Traditional hotel, resort, inn, or hostel | | `"vacation rental"` | Vacation rental, apartment, or villa. Returned when `property_types=12` is set | > [!NOTE] > **Mode switching depends on inventory.** Some destinations continue to return `type: "hotel"` even when `property_types=12` is set if no vacation rentals are listed. --- ## Error Handling ```json { "error": "error_code", "message": "Human readable error message" } ``` ### Common Error Codes | Status | Error | Description | |--------|-------|-------------| | `400` | `token is required` | Missing token | | `400` | `q (hotel search query) is required` | Missing `q` | | `400` | `check_in_date is required (format: YYYY-MM-DD)` | Missing or malformed `check_in_date` | | `400` | `check_out_date is required (format: YYYY-MM-DD)` | Missing or malformed `check_out_date` | | `400` | `check_out_date must be after check_in_date` | Date range inverted | | `400` | `sort_by must be 3, 8, or 13` | Invalid `sort_by` | | `400` | `min_price must be a non-negative integer` | Invalid `min_price` | | `400` | `max_price must be a non-negative integer` | Invalid `max_price` | | `400` | `min_price must be <= max_price` | Range inverted | | `400` | `rating must be 7, 8, or 9` | Invalid `rating` | | `400` | `hotel_class values must be 2-5` | Invalid `hotel_class` | | `400` | `detail_token is required` | Detail endpoint called without `detail_token` | | `400` | `invalid detail_token: ...` | `detail_token` malformed or not base64url | | `502` | `request failed` | Transient. Retry | | `502` | `unexpected response` | Non-200 upstream | | `500` | `decompression failed` / `parse failed` | Transient. Retry | ---