# Google Hotels Scraper & Google Hotels API: Prices per Site (`hyperbach/google-hotels-scraper`) Actor

Google Hotels as a hotel data API, no login: every hotel Google lists for a place and stay with class, rating, reviews, prices before and with taxes, hotel deals, amenities, photos; OTA prices per booking site with links, rate parity, a price calendar, filters, vacation rentals, 70+ currencies.

- **URL**: https://apify.com/hyperbach/google-hotels-scraper.md
- **Developed by:** [Hyperbach](https://apify.com/hyperbach) (community)
- **Categories:** Travel, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.44 / 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.
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?

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 & Google Hotels API: Prices per Site

**Google Hotels search results as data, logged out: a place (or a hotel) and a stay in, one row per hotel out — Google's own record with class, rating and review count, the nightly and stay prices before and with taxes (taxes and fees apart), the deal line ("25% less than usual"), amenities, photos, nearby places with travel times, check-in times, and Google's ids and links.** On request: the price per booking site for the stay (Google's click-out link and the site's own deep link, the official-site flag, free cancellation, rate parity), the full record (address, phone, rating histogram, review aspects and texts), a price calendar (one row per check-in date with its site list), filters (class, guest rating, price, amenities, free cancellation, special offers, vacation rentals), Google's own sorts, 70+ currencies, markets and languages, batches of places, and a memory that delivers only the hotels whose price moved. A free summary row per search states Google's count for the stay, how many distinct hotels were read and whether the list was COMPLETE, TRUNCATED or CAPPED. Dates as `YYYY-MM-DD` or `+N` days from the day of the run, so a saved task never asks for a past day. No login, no Google account, no API key, no browser, proxies handled for you.

### Why this Google Hotels scraper

- **Every hotel Google lists, counted.** Google Hotels shows 18 hotels a page and serves about 200 distinct hotels per sorted list and 500 under relevance; the lane's tools stop at 20, 200 or their cap and never say where the list ended. Here a place search walks the relevance list to its end, then the class facets under two orders, de-duplicates by Google's id, and the free summary row states Google's own count for the stay (`results_count`, 1,221 for New York on our test), how many distinct hotels were read and a verdict: COMPLETE, TRUNCATED (Google's lists end before its count) or CAPPED (your `maxHotelsPerSearch`).
- **The stay and the currency you asked, or nothing.** Every record Google answers echoes the stay and the currency; a record that carries another stay or currency is never delivered as yours — the search becomes a free `failed` row that says what Google answered. The lane's leaders read Google's default stay or another market without a word.
- **One price model, both tax states.** Every row carries the stay's parts — `price_base`, `taxes`, `fees`, `total_price_with_taxes` — and from them the nightly price before taxes (`nightly_price`, Google's main figure) and with taxes and fees (`nightly_price_with_taxes`), the same on every exit and market; `price_tax_state` names what the figures are. Twelve rival actors deliver one figure and disagree on which.
- **The price per booking site, dated, with two links.** `detailsFor` (or a hotel in `hotels`) reads the booking-site list for the asked stay — 28–36 sites for a Manhattan hotel in our tests, every one priced before and with taxes — with Google's click-out link **and** the site's own deep link for the stay (`site_url`), the official-site flag, free cancellation and its deadline, the member-rate note, and the parity gap between the hotel's own site and the cheapest one. The sponsored block (Google's "Featured options") is delivered apart in `sponsored_sites`.
- **The full record on the same row.** With the details call: address, phone, website, the rating histogram, Google's review aspects with positive and negative counts, the review snippets and the external ratings (Tripadvisor, Trip.com), Google's review summary, the amenity groups, nearby landmarks, transit stops, airports and restaurants with walking, driving and transit times, check-in and check-out times, the neighbourhood text.
- **Honest runs.** A search Google lists nothing for, a value that is no search, a refusal the exits could not pass, a hotel name Google does not answer and a list in the wrong stay or currency are free `search` rows with the reason; nothing silent, nothing charged. The run summary (`RUN_SUMMARY`) carries the walk per search and the share of fresh exits Google served in your run's own window.
- **Plain HTTP, 256 MB, seconds a search.** A page of 18–20 hotels is one call to Google's own page API (45 KB on the wire), a hotel's dated site list one more (54–81 KB): no browser, no page load, no token to mint. A 25-hotel search with the site list for two of them took 15 seconds from a cold start in our tests.

### Who it's for

- **Revenue managers and rate-parity teams** — a hotel by name, URL or id with the price per booking site for the stay, the official site's price against the cheapest OTA, free-cancellation deadlines, and a price calendar over the next weeks; a saved task on a schedule with `onlyChanges` delivers only the sites whose price moved.
- **Travel apps and meta-search** — the hotel list for a place and stay with Google's ids, class, rating, the nightly and stay prices before and with taxes, photos and amenities, in the market, language and currency of the user, sorted the way Google sorts.
- **Analysts and consultants** — batches of places with their own stays, Google's count per stay, class and rating filters, the whole list de-duplicated with a verdict, the deal line and the review aspects.
- **Developers and agents** — typed rows keyed by `search_id`, a free summary row per search with the status and its reason, and a run summary to check a pipeline against; every input constrained in the schema.

### Quick start

**A place and a stay, Google's first 20 hotels**

```json
{
  "query": "hotels in New York",
  "checkIn": "+30",
  "checkOut": "+32",
  "maxHotelsPerSearch": 20
}
```

**Every hotel Google lists, with the booking-site list for the first 10**

```json
{
  "query": "hotels in Barcelona",
  "checkIn": "+30",
  "checkOut": "+33",
  "detailsFor": 10,
  "maxItems": 1000
}
```

**One hotel: the price per booking site and a 30-day price calendar**

```json
{
  "hotels": [
    "Arlo NoMad New York"
  ],
  "checkIn": "+30",
  "checkOut": "+32",
  "calendarDays": 30
}
```

**Filters, a sort and a market**

```json
{
  "query": "hotels in Berlin",
  "checkIn": "+30",
  "checkOut": "+32",
  "hotelClass": [
    "4",
    "5"
  ],
  "minRating": "4",
  "maxPrice": 250,
  "freeCancellation": true,
  "sortBy": "lowest_price",
  "market": "DE",
  "language": "de",
  "currency": "EUR",
  "maxHotelsPerSearch": 50
}
```

### Output

One row per hotel (and one free summary row per search; price-calendar days are rows of their own kind):

| field | meaning |
|---|---|
| `row_type` | `hotel` (one hotel, charged), `search` (the free summary row of a search) or `calendar_day` (one check-in date of a hotel's price calendar, charged). |
| `search_id` | `s1`, `s2`, …: the search the row answers, in the order of the input; join rows by it. |
| `search_label` | The search as you gave it (the place and stay, the search object, the hotel name, URL or id). |
| `status` | On a hotel or calendar row `ok`. On a search row: `ok` (the list was served), `no_hotels` (Google listed nothing for it, or no hotel of that name), `failed` (a refusal the exits could not pass, Google's own error, or a stay or currency Google did not honour), `invalid` (a value that is no search). |
| `status_detail` | The reason behind a status that is not `ok`, in a sentence; on a hotel row a note when the details call was not served. |
| `scraped_at` | When the row was read, ISO 8601 UTC. |
| `query` | The place words asked (a search), or the hotel name asked (a hotel by name). |
| `check_in` | The check-in date of the stay, `YYYY-MM-DD` (a `+N` date resolved to the day). |
| `check_out` | The check-out date of the stay, `YYYY-MM-DD`. |
| `nights` | Nights of the stay. |
| `adults` | Adults the prices are for. |
| `children_ages` | The children's ages the prices are for, or null. |
| `market` | The market (point of sale) asked, a two-letter country code. |
| `language` | The language of the texts asked. |
| `currency` | The currency asked. |
| `currency_served` | The currency Google answered with (every price of the row is in it); equal to `currency` on a delivered row. |
| `sort` | The sort asked: `relevance`, `lowest_price`, `highest_rating` or `most_reviewed`. |
| `filters` | The filters applied to the search (sortBy, hotelClass, minRating, maxPrice, minPrice, amenities, freeCancellation, specialOffers, propertyType), or null when none narrows the list. |
| `property_type_asked` | `hotels`, `vacation_rentals` or `all`: the view asked. |
| `rank` | The hotel's position in the delivered list of its search (1 = first); null on a hotel asked by name, URL or id. |
| `name` | The hotel's name as Google lists it. |
| `property_type` | `hotel` or `vacation_rental`, from Google's own type flag. |
| `hotel_class` | Google's class as a number of stars (1–5); null when Google shows none (unclassed hotels, rentals). |
| `hotel_class_label` | Google's class label in the language asked (`4-star hotel`, `4-Sterne-Hotel`). |
| `rating` | Google's guest rating (0–5). |
| `reviews_count` | The number of Google reviews behind the rating. |
| `feature_id` | Google's feature id of the place (`0x…:0x…`), the key a hotel is de-duplicated on; null on a vacation rental. |
| `entity_id` | Google Hotels' entity id (`ChkI…`): the id of the hotel's own page and of the `hotels` input. |
| `cid` | Google's cid of the place (the Maps listing's id). |
| `google_hotels_url` | The hotel's Google Hotels prices page for the stay (the stay in its `ts` token). |
| `google_maps_url` | The hotel's Google Maps link (from the details call). |
| `website` | The hotel's own website as Google links it. |
| `latitude` | Latitude of the hotel. |
| `longitude` | Longitude of the hotel. |
| `address` | The hotel's address as Google shows it (from the details call; on a list row only when Google's first screen carries it). |
| `phone` | The hotel's phone number as Google shows it (from the details call). |
| `country_code` | The two-letter country of the hotel. |
| `neighborhood` | The innermost place Google files the hotel under (`Midtown South`). |
| `neighborhood_description` | Google's text about the hotel's area (from the details call). |
| `check_in_time` | The hotel's check-in time as Google shows it (`3:00 PM`). |
| `check_out_time` | The hotel's check-out time (`11:00 AM`). |
| `description` | Google's one-line description of the hotel. |
| `description_long` | With the details call: Google's long description of the hotel (null when Google has none). |
| `thumbnail` | The hotel's thumbnail image URL. |
| `images` | The hotel's photo URLs as Google serves them (9 on a list record). |
| `more_photos` | With the details call: further photo URLs of the hotel (guests' and the hotel's own; 10–16 a hotel). |
| `amenities` | The amenities Google marks available, by name (`Free Wi-Fi`, `Pool`, `Pet-friendly`); a code the map does not know is `code:<n>`. |
| `amenities_unavailable` | The amenities Google marks as not offered (`Parking`, `Breakfast`). |
| `amenity_codes` | Google's raw amenity codes with their availability flag and Google's qualifier where it gives one ({code, available, qualifier}: free, extra charge, 24 hours), for a map of your own. |
| `amenity_groups` | With the details call: the amenities by Google's groups ({group, amenities, unavailable}: Internet, Food & drink, Pools, Parking & transportation, Accessibility, Pets, Services, Wellness, Rooms, Bathrooms, …). |
| `nearby` | Nearby places Google lists with travel times ({name, kind (landmark, transit, airport, restaurant), walk_minutes, drive_minutes, transit_minutes, rating, reviews_count, category, latitude, longitude}); the details call carries the full set. |
| `rating_histogram` | Google's reviews by stars ({"5": n, "4": n, …}). |
| `review_aspects` | Google's review aspects ({name, mentions, positive, negative, sentiment, score}): Location, Service, Cleanliness, Breakfast, …; the details call carries the full set. |
| `reviews` | With the details call: the review snippets Google shows ({source, author, text, date, rating, url}) — Google's own highlights and the external sources' entries (Tripadvisor, Trip.com). |
| `external_ratings` | With the details call: the hotel's ratings on other sites ({source, rating, scale, reviews_count, url}). |
| `review_summary_positive` | With the details call: Google's own summary of what guests praise. |
| `review_summary_negative` | With the details call: Google's own summary of what guests complain about. |
| `nightly_price` | The nightly price before taxes (Google's main figure: the room rate with fees, taxes out), in `currency_served`: (price_base + fees) / nights. |
| `nightly_price_with_taxes` | The nightly price with taxes and fees: total_price_with_taxes / nights. |
| `total_price` | The stay's price before taxes (price_base + fees). |
| `total_price_with_taxes` | The stay's price with taxes and fees (Google's total). |
| `price_base` | The stay's room rate before fees and taxes, as Google's parts give it. |
| `taxes` | The stay's taxes, as Google's parts give them. |
| `fees` | The stay's fees (resort, destination, cleaning …), as Google's parts give them. |
| `price_tax_state` | `both` when the figures come from Google's parts (the before- and with-taxes figures are computed from them: the usual case), `as_displayed` when only the display strings were there, null on a record without a price. |
| `nightly_price_display` | The nightly price as Google displayed it (`$180`, `58 €`). |
| `nightly_price_with_taxes_display` | The nightly price with taxes as Google displayed it (`$210`); null where Google showed one figure (a non-US market read on some exits). |
| `deal` | Google's deal line when it shows one (`25% less than usual`). |
| `deal_percent` | The deal's percentage below the usual price (25 for `25% less than usual`). |
| `deal_level` | `deal` or `great_deal`, Google's own level of the deal line. |
| `typical_price_low` | With the details call: the low end of Google's typical nightly price range for this hotel and stay, in `currency` as Google displays it. |
| `typical_price_high` | With the details call: the high end of Google's typical nightly price range for this hotel and stay, in `currency`. |
| `details_read` | True when the row carries the details call (the booking-site list and the full record): the `details` event. |
| `sites` | The dated booking-site list, Google's organic list in its order ({site, partner_id, is_official_site, nightly_price, nightly_price_with_taxes, total_price, total_price_with_taxes, nightly_price_display, free_cancellation, free_cancellation_until, rate_note, member_nightly_price, booking_url (Google's click-out link), site_url (the site's own deep link for the stay), sponsored (false), logo}). |
| `sites_count` | The number of organic booking sites Google lists for the stay. |
| `sites_priced` | How many of them carry a price. |
| `lowest_site` | The booking site with the lowest nightly price. |
| `lowest_site_price` | The lowest nightly price among the sites (before taxes). |
| `lowest_site_price_with_taxes` | That site's nightly price with taxes. |
| `official_site_price` | The hotel's own site's nightly price when it is in the list. |
| `parity_gap` | official_site_price − lowest_site_price: how much the hotel's own site is above the cheapest OTA (negative when it is the cheapest). |
| `sponsored_sites` | Google's featured block (ads) above the list, with the same site fields and `sponsored` true (their links are Google's ad links). |
| `results_count` | Google's own count of results for the search and stay, for the view read (hotels, or all lodging when the walk read only the mixed list); the yardstick of the verdict. |
| `results_count_page` | The count the Google Hotels page shows for the stay (its first screen's figure, 1,221 for New York); read when nothing narrows the list. |
| `place_resolved` | The place Google resolved the words to (`New York`); an unknown place resolves to Google's nearest guess, never to an empty list. |
| `hotels_found` | On a search row: distinct hotels read for the search (de-duplicated by Google's id). |
| `hotels_delivered` | On a search row: hotel rows delivered for the search (the cap and `maxItems` may keep some back). |
| `verdict` | On a search row: `COMPLETE` (≥ 90 % of Google's count read), `TRUNCATED` (Google's lists ended before its count) or `CAPPED` (your cap stopped the walk). |
| `verdict_detail` | The verdict in a sentence: what was read against Google's count, the pages and facet lists, where Google stopped. |
| `list_calls` | On a search row: calls made to Google for the search (pages, facet lists, details calls). |
| `change_type` | With `onlyChanges`: `new` (first delivery), `changed` (a watched price moved since the last delivery) or `unchanged` (not delivered). |
| `changed_fields` | With `onlyChanges`: which watched fields moved (`price`, `sites`). |
| `previous_read_at` | With `onlyChanges`: when this hotel and stay were last delivered. |
| `first_read_at` | With `onlyChanges`: when this hotel and stay were first read by the memory. |
| `times_read` | With `onlyChanges`: how many runs read this hotel and stay. |
| `previous_price` | With `onlyChanges`: the nightly price with taxes as last delivered. |
| `price_change` | With `onlyChanges`: nightly_price_with_taxes − previous_price. |
| `sites_gained` | With `onlyChanges` and the details call: booking sites in the list now that were not in the last delivered one. |
| `sites_lost` | With `onlyChanges` and the details call: booking sites of the last delivered list that are gone. |
| `sites_changed` | With `onlyChanges` and the details call: sites whose nightly price moved ({site, previous_price, price}). |
| `price_history_own` | With `onlyChanges`: our own reads of this hotel and stay ({at, price}), the newest 60. |
| `date` | On a calendar row: the check-in date of the day (the stay's length kept). |
| `day_rank` | On a calendar row: the date's rank by the lowest site price among the calendar's dates (1 = cheapest). |
| `is_cheapest` | On a calendar row: true on the cheapest date of the calendar. |

Example record:

```json
{
  "row_type": "hotel",
  "search_id": "s1",
  "search_label": "hotels in New York 2026-11-12 → 2026-11-14",
  "status": "ok",
  "status_detail": null,
  "scraped_at": "2026-10-14T14:41:52Z",
  "query": "hotels in New York",
  "check_in": "2026-11-12",
  "check_out": "2026-11-14",
  "nights": 2,
  "adults": 2,
  "children_ages": null,
  "market": "US",
  "language": "en",
  "currency": "USD",
  "currency_served": "USD",
  "sort": "relevance",
  "filters": null,
  "property_type_asked": "hotels",
  "rank": 1,
  "name": "Fairfield by Marriott Inn & Suites New York Staten Island",
  "property_type": "hotel",
  "hotel_class": 3,
  "hotel_class_label": "3-star hotel",
  "rating": 3.8,
  "reviews_count": 657,
  "feature_id": "0x89c24d347e74e265:0x5c9e5ad04f3207da",
  "entity_id": "ChkI2o_I-YTals9cGg0vZy8xMWZsMHRrazhqEAE",
  "cid": "15613996860267130446",
  "google_hotels_url": "https://www.google.com/travel/hotels/entity/ChkI2o_I-YTals9cGg0vZy8xMWZsMHRrazhqEAE/prices?hl=en&gl=us&curr=USD&ts=CAESCgoCCAMKAggDEAAaGBIWEhQKBwjqDxALGAwSBwjqDxALGA4YAioHCgU6A1VTRA",
  "google_maps_url": "https://maps.google.com/maps?hl=en&gl=US&um=1&ie=UTF-8&fb=1&sa=X&ll=40.5868991,-74.1911844&z=11&ftid=0x0:0x5c9e5ad04f3207da&q=Fairfield+by+Marriott+Inn+%26+Suites+New+York+Staten+Island",
  "website": "https://www.marriott.com/en-us/hotels/nycfd-fairfield-inn-and-suites-new-york-staten-island/overview/?scid=f2ae0541-1279-4f24-b197-a979c79310b0",
  "latitude": 40.5868196,
  "longitude": -74.19115780000001,
  "address": "290 Wild Ave, Staten Island, NY 10314",
  "phone": "(718) 698-8811",
  "country_code": "US",
  "neighborhood": "Mid Island",
  "neighborhood_description": "Suburban Mid Island is home to the Staten Island Greenbelt, a cluster of nature preserves and parks with miles of trails through woods and wetlands. Historic Richmond Town, a village complex with restored 19th-century homes and shops, features guided tours and a local history museum. The hillside Jacques Marchais Museum of Tibetan Art displays Buddha sculptures and other Himalayan works in a monastery-style setting.",
  "check_in_time": "3:00 PM",
  "check_out_time": "12:00 PM",
  "description": "Informal hotel with a gym & a restaurant/bar, plus free breakfast, Wi-Fi & a ferry terminal shuttle.",
  "description_long": "Set 11 miles from St. George Ferry Terminal, offering access to Manhattan, this down-to-earth hotel is 5 miles from The Jacques Marchais Museum of Tibetan Art and 8 miles from the Staten Island Zoo.",
  "thumbnail": "https://lh3.googleusercontent.com/grass-cs/AABkmLfSOrgWfpF0URc5NWNnvKxDk4ngHsCl-S10Zu8glBX6jUa0bbwDS529-3T4-LE58SeW50HyJK4QCnOaauIBw0LEODyr6I22FJ6N2qOKszvBBXDd2n-7EaNaVhr3ihNE4BaaLwG8gg=s150-w92-h150-n-k-no",
  "images": [
    "https://lh3.googleusercontent.com/grass-cs/AABkmLdYG1iSQWhQIV2oASS1FN1t7aWAiqAojR_kA5yUFBx-eF4yn2OdnDktbgnILTcYui34CrHqo01-7sv9EUNHjGE_sew_fGnLY9ddMkkhbEH6shaN9JCJCO8ORGSNg8BLUeFo4zbBofQ9hNA=s287-w287-h192-n-k-no-v1",
    "https://lh3.googleusercontent.com/grass-cs/AABkmLd0JBzkOWVFMHXR9ifi6iRMa-nb_YdqQW5nry1kf7f0K1IVOfYJusIt5WoK-mGb4bW20xYAeCGrpmgWeqrgUtaFi9SiHNBLCYB6dLxs4ovUgKVI31ZvRhUUMIBY_ln2_ao4DV4Fw0IQ9ZTF=s287-w287-h192-n-k-no-v1",
    "https://lh3.googleusercontent.com/grass-cs/AABkmLcva-__2t0lj8kWDhxT3n3ilVdaxxAXy6Xpsjg8YZzaGeDN_L_uur5_8fVPRMvUXuPfIpOzSJ8TAOUnyJVDgrEWMhA1GXcN5_xwaGACm9ZXWUxLeoZlvBMWRM4PGxg61Jpx49EgdcGAi74=s287-w287-h192-n-k-no-v1"
  ],
  "more_photos": [
    "https://lh3.googleusercontent.com/gps-cs-s/ANWiy9RC1ewUBuzQcCagkR8elHBy1SRpQRDV8XMl5Hc1fjofUhYStX0yQ_rmaYJmvSUpSCiC8DTbWycLbxt_0XIP22oF1gKCm6oFXoqdXYYSgv0S45TKLYv8xTA4X9fyAipvW6xWBFWivwH6mvM=w252-h168-k-no",
    "https://lh3.googleusercontent.com/gps-cs-s/ANWiy9Sv3L20LZo2h3NPF-dgDGdWIAMrOy5HW6mWfHGrGYAW6BOJSDrEgC-ko8iH9JIWTWa8P3aN3HK_tBl4sWWf1bu49-SJ3pn661X_l84yAwOJ7qoYEqxEuRExr_FghG5L74j5Ok3iJprT1Stb=w252-h168-k-no"
  ],
  "amenities": [
    "Wi-Fi (free)",
    "Wi-Fi in public areas",
    "Table service",
    "Breakfast (free)",
    "Breakfast buffet",
    "Smoke-free property",
    "Credit cards",
    "Cash",
    "Checks",
    "Front desk (24 hours)",
    "Baggage storage",
    "Convenience store",
    "Full-service laundry",
    "Self-service laundry",
    "Elevator",
    "Wake up calls",
    "Housekeeping",
    "Kid-friendly",
    "Parking (free)",
    "Self parking (free)",
    "Accessible",
    "Accessible parking",
    "Fitness center (free)",
    "Treadmill",
    "Free weights",
    "English",
    "Spanish",
    "Private bathroom",
    "Air conditioning",
    "Coffee maker"
  ],
  "amenities_unavailable": [
    "Pool",
    "Hot tub"
  ],
  "amenity_codes": [
    {
      "code": 28,
      "available": true,
      "qualifier": "free"
    },
    {
      "code": 162,
      "available": true
    },
    {
      "code": 148,
      "available": true
    },
    {
      "code": 54,
      "available": true,
      "qualifier": "free"
    },
    {
      "code": 56,
      "available": true
    }
  ],
  "amenity_groups": [
    {
      "group": "Internet",
      "amenities": [
        "Wi-Fi (free)",
        "Wi-Fi in public areas"
      ],
      "unavailable": []
    },
    {
      "group": "Food & drink",
      "amenities": [
        "Table service",
        "Breakfast (free)",
        "Breakfast buffet"
      ],
      "unavailable": []
    },
    {
      "group": "Policies & payments",
      "amenities": [
        "Smoke-free property",
        "Credit cards",
        "Cash",
        "Checks"
      ],
      "unavailable": []
    }
  ],
  "nearby": [
    {
      "name": "Statue of Liberty",
      "kind": "landmark",
      "walk_minutes": null,
      "drive_minutes": 24,
      "transit_minutes": 55,
      "rating": 4.7,
      "reviews_count": 112707,
      "category": "Point of interest",
      "latitude": 40.6892494,
      "longitude": -74.04450039999999
    },
    {
      "name": "Coney Island",
      "kind": "landmark",
      "walk_minutes": null,
      "drive_minutes": 25,
      "transit_minutes": 108,
      "rating": 4.6,
      "reviews_count": 6861,
      "category": "Point of interest",
      "latitude": 40.5755438,
      "longitude": -73.9707016
    },
    {
      "name": "Ellis Island",
      "kind": "landmark",
      "walk_minutes": null,
      "drive_minutes": 25,
      "transit_minutes": 95,
      "rating": 4.6,
      "reviews_count": 1470,
      "category": "Point of interest",
      "latitude": 40.6994748,
      "longitude": -74.0395587
    },
    {
      "name": "Governors Island",
      "kind": "landmark",
      "walk_minutes": 347,
      "drive_minutes": null,
      "transit_minutes": 84,
      "rating": 4.7,
      "reviews_count": 1455,
      "category": "Point of interest",
      "latitude": 40.689450099999995,
      "longitude": -74.016792
    }
  ],
  "rating_histogram": {
    "5": 299,
    "4": 144,
    "3": 84,
    "2": 40,
    "1": 90
  },
  "review_aspects": [
    {
      "name": "Breakfast",
      "mentions": 70,
      "positive": 45,
      "negative": 14,
      "sentiment": "positive",
      "score": 0.323
    },
    {
      "name": "Restaurant",
      "mentions": 41,
      "positive": 28,
      "negative": 6,
      "sentiment": "positive",
      "score": 0.462
    },
    {
      "name": "Service",
      "mentions": 170,
      "positive": 101,
      "negative": 57,
      "sentiment": "neutral",
      "score": 0
    },
    {
      "name": "Parking",
      "mentions": 33,
      "positive": 8,
      "negative": 24,
      "sentiment": "negative",
      "score": -0.371
    }
  ],
  "reviews": [
    {
      "source": "Google",
      "author": "Gary Fried",
      "text": "Rooms are generally clean, but service can be a bit hit or miss.",
      "date": null,
      "rating": null,
      "rating_scale": null,
      "url": null
    },
    {
      "source": "Google",
      "author": "D Johnson",
      "text": "Ugly location, first floor room very loud, could not sleep, over priced.",
      "date": null,
      "rating": null,
      "rating_scale": null,
      "url": null
    },
    {
      "source": "Google",
      "author": "Tom Gegan",
      "text": "Staff gave great directions and selections for dinner and cheapest gas!",
      "date": null,
      "rating": null,
      "rating_scale": null,
      "url": null
    }
  ],
  "external_ratings": [
    {
      "source": "Tripadvisor",
      "rating": 3.1,
      "scale": 5,
      "reviews_count": 60,
      "url": "https://www.tripadvisor.com/Hotel_Review-g48682-d5539370-r1072767421?m=68573&staydates=2026_10_25_2026_10_26&uguests=1_2_0&supdv=desktop&supuc=US&supul=en"
    },
    {
      "source": "Trip.com",
      "rating": 4.2,
      "scale": 5,
      "reviews_count": 56,
      "url": null
    },
    {
      "source": "Priceline",
      "rating": 7.5,
      "scale": 10,
      "reviews_count": 243,
      "url": null
    }
  ],
  "review_summary_positive": "Guests consistently praise this hotel for its spacious rooms, solid complimentary breakfast, and friendly, helpful staff.",
  "review_summary_negative": "Other reviews mention the service can be inconsistent and the rooms can be poorly maintained.",
  "nightly_price": 119.44,
  "nightly_price_with_taxes": 141.98,
  "total_price": 238.88,
  "total_price_with_taxes": 283.95,
  "price_base": 238.88,
  "taxes": 45.08,
  "fees": 0.0,
  "price_tax_state": "both",
  "nightly_price_display": "$119",
  "nightly_price_with_taxes_display": "$142",
  "deal": "16% less than usual",
  "deal_percent": 16,
  "deal_level": "deal",
  "typical_price_low": 128.0,
  "typical_price_high": 156.0,
  "details_read": true,
  "sites": [
    {
      "site": "Fairfield by Marriott Inn & Suites New York Staten Island",
      "partner_id": 100231600,
      "is_official_site": true,
      "nightly_price": 168.0,
      "nightly_price_with_taxes": 196.0,
      "total_price": 337.0,
      "total_price_with_taxes": 392.0,
      "nightly_price_display": "$168",
      "free_cancellation": false,
      "free_cancellation_until": null,
      "rate_note": "Get a lower price plus free Wi-Fi with free enrollment",
      "member_nightly_price": 168.0,
      "booking_url": "https://www.google.com/travel/lodging/clk?pc=AA80OsyQufwN93Ontl5jBDhl9NXfx3mLvWp_p8HYdvoaKdNWL6NpXiuDQUt9XQk_03e7dyp2gmDrDcFq5zb1tu822k2hZKK8Y7kONmMXRtqrCuNN6bkKq-f_ua2V7br7YRN45xsVR4PmqZB3pd0V6b4YghdwHZR4e3S-KSWb42pGcYY5GFRDVh2M43kjeCM&pcurl=https://marriottclk.koddi.com/clk?destination%3Dhttps%253A%252F%252Fad.doubleclick.net%252Fclk%253B269275299%253B95398642%253Bk%253Bu%253Dkoddi%2526sv2%253Dkoddi_hpa_US_NYCFD_localuniversal_2_desktop_11/12/2026_non-distributable__selected___organic%253Fhttps%253A%252F%252Fwww.marriott.com%252Freservation%252FavailabilitySearch.mi%253Fcid%253DOMS_GLB0002Y27_GLE00070C9_GLF000C1AH%2526pId%253D%2526isSearch%253Dfalse%2526propertyCode%253DNYCFD%2526fromDate%253D11%252F12%252F2026%2526toDate%253D11%252F14%252F2026%2526numberOfRooms%253D1%2526numberOfGuests%253D2%2526currency%253DUSD&s=AD1XQnlmxZTubhcXTYK0_fNQJDmy&ap=1",
      "site_url": "https://marriottclk.koddi.com/clk?destination=https%3A%2F%2Fad.doubleclick.net%2Fclk%3B269275299%3B95398642%3Bk%3Bu%3Dkoddi%26sv2%3Dkoddi_hpa_US_NYCFD_localuniversal_2_desktop_11/12/2026_non-distributable__selected___organic%3Fhttps%3A%2F%2Fwww.marriott.com%2Freservation%2FavailabilitySearch.mi%3Fcid%3DOMS_GLB0002Y27_GLE00070C9_GLF000C1AH%26pId%3D%26isSearch%3Dfalse%26propertyCode%3DNYCFD%26fromDate%3D11%2F12%2F2026%26toDate%3D11%2F14%2F2026%26numberOfRooms%3D1%26numberOfGuests%3D2%26currency%3DUSD",
      "sponsored": false,
      "logo": "https://www.gstatic.com/travel-hotels/branding/df3424c9-7799-4d27-aeb5-cdcabf8bf950.png"
    },
    {
      "site": "KAYAK.com",
      "partner_id": 100979605,
      "is_official_site": false,
      "nightly_price": 119.0,
      "nightly_price_with_taxes": 142.0,
      "total_price": 239.0,
      "total_price_with_taxes": 284.0,
      "nightly_price_display": "$119",
      "free_cancellation": false,
      "free_cancellation_until": null,
      "rate_note": null,
      "member_nightly_price": null,
      "booking_url": "https://www.google.com/travel/lodging/clk?pc=AA80OswR-O0R4xVKYl1eNf3kGu6i1fdj1vWP1qaXbnvtY-1mbg3UpEpF4ll6VgysdZ7hE3eeD1bNOUYjPlkhOAK0MtxxP5_bHyZTEtilek60qXoDv5IeBQrImrYqShPQiT9UHK2HtMXxOBvPipmcORqPalBjqaOUTcUchytK3Ub5u-_LV2ZAP-CC_-1_dA&pcurl=https://www.kayak.com/semi/ha/hotel_ads/746011/en.html?utm_source%3Dgoogle%26utm_medium%3Dcpc%26utm_term%3D746011%26adType%3D0%26utm_content%3Dlocaluniversal%26utm_campaign%3DHotelAds%26ci%3D2026-11-12%26co%3D2026-11-14%26gs%3Dlocaluniversal%26l%3D2%26pc%3DUSD%26rid%3D%26pdtax%3D45.08%26pdtotal%3D283.95%26rpid%3D%26uc%3DUS%26ucuc%3DUSD%26d%3Ddesktop%26lc%3Den%26v%3Dfalse%26rrid%3DUFJJQ0VMSU5FQ09SRQ%26k_pc%3D~UENMTkhPVEVMV0hJU0tZ%26k_rt%3D%26k_sid%3D2QBkJ8zJ1a%26k_kct%3D1791969899%26k_gct%3D1791979864%26g%3D2%26r%3D1%26ac%3D2%26k_cc%3Dus%26dt%3Dselected%26cmpid%3D%26cmptrack%3D&s=AD1XQnkEB6bgTU6-TxddAf9ePJNx&ap=1",
      "site_url": "https://www.kayak.com/semi/ha/hotel_ads/746011/en.html?utm_source=google&utm_medium=cpc&utm_term=746011&adType=0&utm_content=localuniversal&utm_campaign=HotelAds&ci=2026-11-12&co=2026-11-14&gs=localuniversal&l=2&pc=USD&rid=&pdtax=45.08&pdtotal=283.95&rpid=&uc=US&ucuc=USD&d=desktop&lc=en&v=false&rrid=UFJJQ0VMSU5FQ09SRQ&k_pc=~UENMTkhPVEVMV0hJU0tZ&k_rt=&k_sid=2QBkJ8zJ1a&k_kct=1791969899&k_gct=1791979864&g=2&r=1&ac=2&k_cc=us&dt=selected&cmpid=&cmptrack=",
      "sponsored": false,
      "logo": "https://www.gstatic.com/travel-hotels/branding/6417d44c-c676-4b16-8ae9-f3bbeaa51899.png"
    },
    {
      "site": "Priceline",
      "partner_id": 220,
      "is_official_site": false,
      "nightly_price": 129.0,
      "nightly_price_with_taxes": 152.0,
      "total_price": 258.0,
      "total_price_with_taxes": 303.0,
      "nightly_price_display": "$129",
      "free_cancellation": true,
      "free_cancellation_until": "Nov 9 11:59 PM",
      "rate_note": null,
      "member_nightly_price": null,
      "booking_url": "https://www.google.com/travel/lodging/clk?pc=AA80OszYeMVgd83ZIhfNzcSqFPE5-6A-IY39GsaU-ZEFlaiHzay92qKdnhfv5UzmrbTGLMZYQjx68ignOmNrY1C3L5HLrpuacx6MPI5yk3aq59EyXshxRHivM8jnxOQMN_Wyga_p_G0oIftDs-oboiEiXKJZpNwYsDkN1ezE9EsiT5G5VAwh1hEkTku2boQ6HQ3Qk4c&pcurl=https://www.priceline.com/r/?channel%3Dmeta%26product%3Dhotel%26theme%3DGoogle-L%26refid%3DPLGOOGLEMSS%26refclickid%3DUS_HP%257C43756706_localuniversal_2%257C20261112%257Cdesktop%257Cuserdate%7Cpublic%7C%7C%7C29%257C2%257C0%7C0%7CEN%26hotelid%3D43756706%26checkin%3D20261112%26checkout%3D20261114%26rooms%3D1%26cur%3DUSD%26POSCountryCode%3DUS%26taxDisplayMode%3DBP%26cityID%3D3000016474%26adults%3D4%26land%3DL%26metaid%3DH62cz-JuPRvOebA4y4svbysBGhV5iGFREq_5yxlaX49wORuc4QFZHd944tiJdvhobCuFG0Fj04kpqGVM5Gb6u79G6b9CVlrPTOMSF4iyis-uFp4dTgGXJiAlib8im38AnJ5LA_vvqbxW2MZRVcCpICzdUckg-PBHnN3fCJggjvA7YA2HLvayyuAcKOsZugfkP6ek1tQUAz6sIbonjetOr7PF1nI38UIqeyFXstpqeosVahcWtHR0IKZmtGEKg2_jZ6tO_wjkv2y0e-UJOfWVKkxTbtSDP3RCw0DrLzBsIL6OOj7x8hH5LRumr_LrUefTNgIREWPBiuixfwYeR90q3Yr_kwDHrzjao9mfXS-rx3bb20jThMoCb8T36cnBzBXqQ4XmpdJbr7uHLDxz3ON8ph_8xsEXhuYv15LYdjv9wCCVUzgmWKABWjiX_KBkhftaAXvE_m_HD5Qp7OKv75eZkX74Ptp-fceZu10NePOugs5enJ8ewPSwPcCY_YbcO2xtJE7rT8LPdVv_xIjxI46K6Q%26dblcnt%3Dtrue%26hc%3D1%26pdtax%3D45.08%26pdf%3D0.00%26pdt%3D303.08%26locale%3Den-us%26ad-src%3D%26numChild%3D0%26aid%3D%26selAdults%3D2&s=AD1XQnnQsGweJae76cMUCNZzcn4_&ap=1",
      "site_url": "https://www.priceline.com/r/?channel=meta&product=hotel&theme=Google-L&refid=PLGOOGLEMSS&refclickid=US_HP%7C43756706_localuniversal_2%7C20261112%7Cdesktop%7Cuserdate|public|||29%7C2%7C0|0|EN&hotelid=43756706&checkin=20261112&checkout=20261114&rooms=1&cur=USD&POSCountryCode=US&taxDisplayMode=BP&cityID=3000016474&adults=4&land=L&metaid=H62cz-JuPRvOebA4y4svbysBGhV5iGFREq_5yxlaX49wORuc4QFZHd944tiJdvhobCuFG0Fj04kpqGVM5Gb6u79G6b9CVlrPTOMSF4iyis-uFp4dTgGXJiAlib8im38AnJ5LA_vvqbxW2MZRVcCpICzdUckg-PBHnN3fCJggjvA7YA2HLvayyuAcKOsZugfkP6ek1tQUAz6sIbonjetOr7PF1nI38UIqeyFXstpqeosVahcWtHR0IKZmtGEKg2_jZ6tO_wjkv2y0e-UJOfWVKkxTbtSDP3RCw0DrLzBsIL6OOj7x8hH5LRumr_LrUefTNgIREWPBiuixfwYeR90q3Yr_kwDHrzjao9mfXS-rx3bb20jThMoCb8T36cnBzBXqQ4XmpdJbr7uHLDxz3ON8ph_8xsEXhuYv15LYdjv9wCCVUzgmWKABWjiX_KBkhftaAXvE_m_HD5Qp7OKv75eZkX74Ptp-fceZu10NePOugs5enJ8ewPSwPcCY_YbcO2xtJE7rT8LPdVv_xIjxI46K6Q&dblcnt=true&hc=1&pdtax=45.08&pdf=0.00&pdt=303.08&locale=en-us&ad-src=&numChild=0&aid=&selAdults=2",
      "sponsored": false,
      "logo": "https://www.gstatic.com/travel-hotels/branding/icon_220.png"
    }
  ],
  "sites_count": 18,
  "sites_priced": 18,
  "lowest_site": "KAYAK.com",
  "lowest_site_price": 119.0,
  "lowest_site_price_with_taxes": 142.0,
  "official_site_price": 168.0,
  "parity_gap": 49.0,
  "sponsored_sites": [
    {
      "site": "Fairfield by Marriott Inn & Suites New York Staten Island",
      "partner_id": 100231600,
      "is_official_site": true,
      "nightly_price": 168.0,
      "nightly_price_with_taxes": 196.0,
      "total_price": 337.0,
      "total_price_with_taxes": 392.0,
      "nightly_price_display": "$168",
      "free_cancellation": false,
      "free_cancellation_until": null,
      "rate_note": "Get the best prices plus free Wi-Fi with free membership enrollment",
      "member_nightly_price": 168.0,
      "booking_url": "https://www.google.com/aclk?sa=l&ai=DChsSEwjakpn73rmXAxW9bkcBHcSeEaUYACICCAEQJxoCcXU&co=1&ase=2&gclid=EAIaIQobChMI2pKZ-965lwMVvW5HAR3EnhGlEAoYASABEgJCQPD_BwE&cid=CAAS0wHkaPbql05Ohz0bmsFMVtHrY7N61Rid5ESBEHVDme_KuCv1SwkhQNfJrF0w40KCUpyj2U9wEzyHAqJt74s9TZZxO385_kVPKpA8jQ_XACXHtFX3SgHak8FCNHmBZMGN78U6g-_bvU9_RJRIIs7senw-u8XRwcZGiyYJbVBeCqY0Qp25i26Wc2ccR8keo7hFPx2GPU7dwSbXMVklEdDzLMSlksWeeIIN1TA3X__QBdPTL3jOhHieNOsJndKYIle0VJ-Mxb68rM9zSGVIzSzeIfIKkNy7&category=acrcp_v1_48&sig=AOD64_2B3X8C_RmKq9k4Ly-lXvk1oS6kuw&adurl",
      "site_url": null,
      "sponsored": true,
      "logo": "https://www.gstatic.com/travel-hotels/branding/df3424c9-7799-4d27-aeb5-cdcabf8bf950.png"
    },
    {
      "site": "Booking.com",
      "partner_id": 184,
      "is_official_site": false,
      "nightly_price": 168.0,
      "nightly_price_with_taxes": 196.0,
      "total_price": 335.0,
      "total_price_with_taxes": 392.0,
      "nightly_price_display": "$168",
      "free_cancellation": false,
      "free_cancellation_until": null,
      "rate_note": null,
      "member_nightly_price": null,
      "booking_url": "https://www.google.com/aclk?sa=l&ai=DChsSEwjakpn73rmXAxW9bkcBHcSeEaUYACICCAEQHxoCcXU&co=1&ase=2&gclid=EAIaIQobChMI2pKZ-965lwMVvW5HAR3EnhGlEAoYAiABEgKZFvD_BwE&cid=CAAS0wHkaPbql05Ohz0bmsFMVtHrY7N61Rid5ESBEHVDme_KuCv1SwkhQNfJrF0w40KCUpyj2U9wEzyHAqJt74s9TZZxO385_kVPKpA8jQ_XACXHtFX3SgHak8FCNHmBZMGN78U6g-_bvU9_RJRIIs7senw-u8XRwcZGiyYJbVBeCqY0Qp25i26Wc2ccR8keo7hFPx2GPU7dwSbXMVklEdDzLMSlksWeeIIN1TA3X__QBdPTL3jOhHieNOsJndKYIle0VJ-Mxb68rM9zSGVIzSzeIfIKkNy7&category=acrcp_v1_48&sig=AOD64_29NF7hPw24UT_0OdZsyC-ZX9bH8w&adurl",
      "site_url": null,
      "sponsored": true,
      "logo": "https://www.gstatic.com/travel-hotels/branding/icon_184.png"
    }
  ],
  "results_count": 1221,
  "results_count_page": 1221,
  "place_resolved": "New York",
  "hotels_found": null,
  "hotels_delivered": null,
  "verdict": null,
  "verdict_detail": null,
  "list_calls": null,
  "change_type": null,
  "changed_fields": null,
  "previous_read_at": null,
  "first_read_at": null,
  "times_read": null,
  "previous_price": null,
  "price_change": null,
  "sites_gained": null,
  "sites_lost": null,
  "sites_changed": null,
  "price_history_own": null,
  "date": null,
  "day_rank": null,
  "is_cheapest": null
}
```

### Pricing

**Pay only for the rows a run delivers**, with no start fee and no platform usage billed to you. Prices fall with your Apify plan.

| per 1,000 | Free | Starter | Scale | Business |
|---|---|---|---|---|
| Hotel (`hotel`) | $2.87 | $2.4395 | $2.009 | $1.435 |
| Booking-site list and full record of a hotel (`details`) | $4.00 | $3.40 | $2.80 | $2.00 |
| Price calendar day (`calendar_day`) | $3.00 | $2.55 | $2.10 | $1.50 |

A hotel row is **$2.87 per 1,000** on the Free plan ($0.00287 a hotel) and $1.435 on Business: Google's first page for a place (18–20 hotels) costs $0.0574 on the Free plan, 500 hotels of a large city $1.435. The booking-site list with the full record is an extra $0.004 ($0.002 on Business) on each hotel row that carries it (`details_read` true): the first `detailsFor` hotels of a search and every hotel of `hotels`. A price-calendar day is a row of its own at the price above: a calendar of N days is N `calendar_day` rows, the asked stay's date included (its row repeats that date's site list on the hotel row), so one hotel with a 30-day calendar costs $0.09687 on the Free plan (the hotel row, its booking-site list and 30 days). Free: every `search` summary row (Google's count, the distinct hotels read, the verdict, the status and its reason), a search Google lists no hotels for (`no_hotels`), a value that is no search (`invalid`), a refusal the exits could not pass or a list in another stay or currency than the one asked (`failed`), a calendar date Google did not answer (no row), the unchanged hotels `onlyChanges` does not deliver, and a run that failed before its first row. A run that stops early (a timeout, an abort) is charged for the rows it delivered. `maxItems` counts the charged rows (hotels and calendar days); before the first request the log says the most the run can cost at your plan's prices (for a search with no `maxHotelsPerSearch` and no `maxItems`, an estimate: such a search reads to Google's end, 893 hotels for New York on our run). Enterprise plans have their own rates — the Actor's Pricing tab shows the price for your plan.

### Usage patterns

- **One search or many** — Give `query` (a city, a neighbourhood, a landmark) with `checkIn` and `checkOut`, or list searches in `searches` (objects with their own stay, party, market and filters; texts such as `hotels in Paris 2026-11-12 2026-11-14`; Google Hotels search URLs), or hotels in `hotels` (a name with its city, a Google Hotels URL or an entity id). A date is `YYYY-MM-DD` or `+N`, N days after the day of the run (UTC): `+30` / `+32` for a two-night stay a month ahead, so a saved task or a schedule never asks for a past day (a past date is a free `invalid` row that says so). Every row carries `search_id` and `search_label`, and every search gets one free `search` row with its status and verdict.
- **What a row is** — `row_type` = `hotel`: one hotel Google lists for the search, in the order asked (`rank`; Google's order for `relevance`), with its class, rating, review count, prices, deal, amenities, photos, nearby places, Google's ids and links; with the details call also the booking-site list (`sites`), the address and phone, the histogram, the aspects, the reviews. `search`: the free summary of a search (Google's count, the place Google resolved, distinct hotels read and delivered, the verdict with its reason, the status). `calendar_day`: one check-in date of a hotel's price calendar with the lowest site price, the official site's price and the dated site list.
- **How far a search goes** — `maxHotelsPerSearch` = 0 (the default) reads every hotel Google lists for the stay: the relevance list to its end (Google repeats its pages after about 500 distinct records), then the hotels sorted by price and each class facet under both orders (about 200 more each), all de-duplicated by Google's id — 500–900 distinct hotels for a big city, 2–3 minutes on four exits. `maxHotelsPerSearch` = 20 is the first screen and one page (two calls). The summary row's `verdict` and `verdict_detail` say what was read against Google's `results_count`.
- **Filters and sorts** — `hotelClass`, `minRating` (3.5 / 4 / 4.5), `maxPrice`, `amenities` (18 of Google's amenity filters: pool, indoor and outdoor pool, free parking, parking, spa, fitness center, restaurant, bar, free breakfast, free Wi-Fi, pet-friendly, kid-friendly, airport shuttle, room service, hot tub, beach access, air conditioning; several = all of them), `freeCancellation` and `specialOffers` are applied by Google on its own request; `minPrice` is applied on the records read (Google's request takes no minimum we could find), so a hotel Google lists without a price is left out. `sortBy` relevance / lowest_price / highest_rating / most_reviewed are Google's own sorts; the rows come out in that order. `propertyType` hotels (the default), vacation_rentals or all: Google's mixed list holds both, told apart by Google's own type flag.
- **The booking-site list and the full record** — `detailsFor` N reads, for the first N hotels of each place search, one more call: the dated price per booking site with Google's click-out link (`booking_url`) and the site's own deep link for the stay (`site_url`), the official-site flag, free cancellation and its deadline, the member-rate note; plus the address and phone, the website, the amenity groups, the rating histogram, the review aspects and texts, the external ratings, the nearby places. A hotel in `hotels` always gets it. The row carries `lowest_site`, `lowest_site_price`, `official_site_price` and `parity_gap`; the sponsored block is `sponsored_sites`.
- **A price calendar** — `calendarDays` N reads, for each hotel of `hotels` (and the first `detailsFor` hotels of a search), the stay on each of the next N check-in dates with the stay's length kept: one `calendar_day` row per date with `lowest_site_price`, `official_site_price`, `sites_count` and the dated `sites` list; `day_rank` and `is_cheapest` rank the dates by the lowest price. The asked stay's date is the first row (from the call already made for the hotel row), each further date one call; every row is a charged `calendar_day`.
- **Monitoring: only what moved** — `onlyChanges` with a `stateStoreName` remembers every hotel row delivered (by Google's id and the stay) and, on the next run of the same memory, delivers only the hotels that are new or whose nightly price with taxes (or, with the details call, a site's price) moved: `change_type`, `previous_price`, `price_change`, `sites_gained`, `sites_lost`, `sites_changed` and `price_history_own` (our own reads) say what. Unchanged hotels are counted in the summary, not delivered, not charged. Save it as a task and schedule it with the stay's own dates (`YYYY-MM-DD`): a `+N` date moves with the day, so each day's list is new to the memory.
- **Markets, languages and currencies** — `market` (the point of sale), `language` (the texts: class labels, group names) and `currency` (every price) are sent on every call; the row carries `currency_served`, the currency Google answered with, and a list in another currency is a free `failed` row. The prices are computed from Google's own parts on every exit, so a German market read and a US market read of the same hotel carry the same `nightly_price` and `nightly_price_with_taxes`.

### Input configuration

| field | type | default | what it does |
|---|---|---|---|
| `query` | `string` | `""` | A place to search hotels in: a city, a neighbourhood, a landmark (`New York`, `hotels in Barcelona`, `Times Square hotels`). Google resolves the words; every row carries the place it resolved (`place_resolved`). Not searched when `searches` or `hotels` has an item: the list is then the whole run, and the dates and options here are its defaults. |
| `checkIn` | `string` | `""` | The check-in date, `YYYY-MM-DD`, or `+N` for N days after the day of the run (UTC): `+30`. A date in the past is a free `invalid` row. |
| `checkOut` | `string` | `""` | The check-out date, `YYYY-MM-DD` or `+N`; empty = the night after check-in. At most 30 nights. |
| `searches` | `array` | `[]` | A list of searches, each an object `{"query": "hotels in Paris", "checkIn": "+30", "checkOut": "+32", "adults": 2, "childrenAges": [8], "market": "FR", "language": "fr", "currency": "EUR", "sortBy": "lowest_price", "hotelClass": [4, 5], "minRating": 4, "maxPrice": 250, "amenities": ["pool"], "freeCancellation": true, "propertyType": "hotels"}` (the run's fields are the defaults; the run's `query` is then not searched), a text `hotels in Paris 2026-11-12 2026-11-14`, or a Google Hotels search URL. Up to 200 searches a run; a value that is no search is a free `invalid` row. |
| `hotels` | `array` | `[]` | One hotel per line for the stay above: a name with its city (`Arlo NoMad New York`), a Google Hotels URL (`https://www.google.com/travel/hotels/entity/ChkI…/prices`) or a bare entity id (`ChkI5-ea3sPi9Y9PGg0vZy8xMWM1NF81cHF3EAE`). Each one is a `hotel` row with the dated booking-site list and the full record (the `details` event). With a hotel here, the run's `query` is not searched. |
| `adults` | `integer` | `2` | Adults in the room (1–10). Google prices one room; every price is for this party. |
| `childrenAges` | `array` | `[]` | One line per child with the child's age (0–17): `8`, `3`. Google prices the stay for the party; the rows carry the ages asked. |
| `maxHotelsPerSearch` | `integer` | `0` | Stop a place search after this many distinct hotels. 0 = every hotel Google lists for the stay: the relevance list to its end, then the class facets and the price order (about 500–900 distinct for a big city; the summary row says how many Google counts and whether the list was COMPLETE, TRUNCATED or CAPPED). |
| `detailsFor` | `integer` | `0` | For the first N hotels of each place search, one more call each: the dated price per booking site (Google's click-out link and the site's own deep link, the official-site flag, free cancellation), the address and phone, the amenity groups, the rating histogram, the review aspects and texts, the nearby places. Charged as the `details` event on those rows. Hotels in `hotels` always get it. |
| `calendarDays` | `integer` | `0` | For each hotel of `hotels` (and the first `detailsFor` hotels of a search), read the stay on each of the next N check-in dates, the stay's length kept: one `calendar_day` row per date with the lowest site price, the official site's price and the dated site list. One call per date. |
| `sortBy` | `relevance` / `lowest_price` / `highest_rating` / `most_reviewed` | `"relevance"` | `relevance` keeps Google's own order (the first screen first); `lowest_price`, `highest_rating` and `most_reviewed` are Google's own sorts (the rows come out in that order). |
| `hotelClass` | `array` | `[]` | Keep these classes only, one per line: `4`, `5`. Applied by Google. |
| `minRating` | \`\` / `3.5` / `4` / `4.5` | `""` | Google's own rating steps: 3.5+, 4.0+ or 4.5+. Applied by Google. |
| `maxPrice` | `integer` | `0` | Keep hotels up to this nightly price (before taxes, in `currency`). Applied by Google. 0 = no limit. |
| `minPrice` | `integer` | `0` | Keep hotels from this nightly price up (before taxes, in `currency`). Applied on the records read (Google's request takes no minimum). 0 = no limit. |
| `amenities` | `array` | `[]` | Keep hotels with every one of these amenities, one per line: `free_parking`, `parking`, `indoor_pool`, `outdoor_pool`, `pool`, `fitness_center`, `restaurant`, `free_breakfast`, `spa`, `beach_access`, `kid_friendly`, `airport_shuttle`, `bar`, `pet_friendly`, `room_service`, `hot_tub`, `free_wifi`, `air_conditioning`. Applied by Google (its own amenity filter ids); several amenities = hotels with all of them. |
| `freeCancellation` | `boolean` | `false` | Keep hotels with a free-cancellation rate; the prices shown are the refundable rates. Applied by Google. |
| `specialOffers` | `boolean` | `false` | Keep hotels Google marks with a deal. Applied by Google. |
| `propertyType` | `hotels` / `vacation_rentals` / `all` | `"hotels"` | `hotels` (the default: Google's hotel records), `vacation_rentals` (the rental records of Google's mixed list: apartments, houses) or `all`. Every row carries `property_type`. |
| `market` | `string` | `"US"` | The two-letter country Google serves the view for (`US`, `GB`, `DE`, …): the point of sale and the strings' market. |
| `language` | `string` | `"en"` | The language of the texts (`en`, `de`, `fr`, `es`, `pt-BR`, …): class labels, descriptions, amenity group names. |
| `currency` | `string` | `"USD"` | The currency of every price (`USD`, `EUR`, `GBP`, `JPY`, …). Each row carries the currency Google answered with (`currency_served`); a list in another currency is a free `failed` row, never a charged one. |
| `onlyChanges` | `boolean` | `false` | Remember every hotel row delivered (by its Google id and stay) and, on the next run of the same memory, deliver only the hotels that are new or whose nightly price with taxes (or a site's price, with `detailsFor`) moved: `change_type`, `previous_price`, `price_change`, `sites_gained`, `sites_lost`, `sites_changed` say what. Unchanged hotels are counted, not delivered, not charged. |
| `stateStoreName` | `string` | `""` | With `onlyChanges`: the name of the memory to keep between runs (letters, digits, dashes); empty = a name derived from the searches. |
| `maxItems` | `integer` | `0` | Stop after this many charged rows (hotels and calendar days; the free `search` summary rows do not count). 0 = no limit. |

### Errors

**A run does not fail because of your input.** When an input cannot be used — a date that is not a date, an id in the wrong form, two settings that contradict each other — the run ends **Succeeded**, charges nothing, and says what to change:

- the status message starts with `INPUT REJECTED`;
- the dataset holds one row, `{"error": true, "code": "…", "message": "…"}`, and no results;
- the key-value store record `ERROR` holds the same object.

From code, check `error` on the first row before reading results.

A search Google lists no hotels for is not an error: it gets one free `search` row with `status` no_hotels and the reason, and the run goes on with the others. A run that ends **Failed** is a fault on our side, never your input; it charges nothing, and we are alerted.

### FAQ

**How many hotels does a search return?**

As many as you ask (`maxHotelsPerSearch`) up to every hotel Google lists for the stay. Google shows a count for the stay (`results_count`, 1,221 hotels for New York on our test) but serves about 200 distinct hotels per sorted list and 500 under relevance before its pages repeat; the Actor walks the relevance list, the price order and the class facets and reaches 500–900 distinct hotels for a big city. The summary row's verdict says COMPLETE, TRUNCATED (with the reason) or CAPPED.

**Which price is which?**

`nightly_price` is Google's main figure, the nightly rate before taxes (room rate and fees); `nightly_price_with_taxes` adds the taxes. `total_price` and `total_price_with_taxes` are the same for the whole stay; `price_base`, `taxes` and `fees` are the stay's parts Google itself sends, so nightly × nights = total. The display strings Google showed are in `nightly_price_display` and `nightly_price_with_taxes_display`. Every figure is in `currency_served`.

**Are the prices for my party?**

Yes: `adults` and `childrenAges` go into Google's request and every record echoes the stay; the rows carry the party asked. Google prices one room; there is no rooms input because Google Hotels has none.

**Do the booking links work?**

`booking_url` is Google's own click-out link (it redirects to the site) and `site_url` the site's own deep link for the stay, decoded from it, with the dates inside; both are delivered so a dead redirect is visible. `sponsored_sites` holds Google's featured block with its ad links apart from the organic list.

**Why does a search end as `failed` with 'Google answered the stay …'?**

Google Hotels takes the stay from the request's state; when its answer echoes another stay or another currency than the one you asked (it happens on a hotel-name search Google resolves to its default stay, or on a currency Google does not price), the rows would carry the wrong prices, so they are not delivered and the search says what Google answered. Nothing is charged for it.

**Can I get the Google Hotels amenities as names?**

Yes: Google sends amenity codes; the Actor maps the 73 codes it met on the pages it studied to Google's own names (`amenities`, `amenities_unavailable`), with Google's qualifier where it gives one (`Wi-Fi (free)`, `Parking (extra charge)`, `Front desk (24 hours)`), and delivers an unmapped code as `code:<n>` in `amenity_codes`, so nothing is lost. The details call adds the grouped list (`amenity_groups`: Internet, Food & drink, Pools, Parking, Accessibility, Pets, Services, Wellness, Rooms, Bathrooms, …).

**What about vacation rentals?**

`propertyType` = `vacation_rentals` keeps the rental records of Google's mixed list (apartments, houses, rooms; Google's own type flag), `all` keeps both. A rental has no class and no feature id; its amenities come as names.

**What does a run cost?**

The log's first line says the most the run can cost at your plan's prices for what you asked (an estimate for a search with no `maxHotelsPerSearch` and no `maxItems`: it reads to Google's end; set either for a hard maximum); only rows Google served are charged, the free rows never. A run that stops early (a timeout, an abort) is charged for the rows it delivered.

### Integration

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('hyperbach/google-hotels-scraper').call({"query": "hotels in New York", "checkIn": "+30", "checkOut": "+32", "maxHotelsPerSearch": 20});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('hyperbach/google-hotels-scraper').call(run_input={'query': 'hotels in New York', 'checkIn': '+30', 'checkOut': '+32', 'maxHotelsPerSearch': 20})
items = client.dataset(run['defaultDatasetId']).list_items().items
```

#### CLI

```bash
apify call hyperbach/google-hotels-scraper --input '{"query": "hotels in New York", "checkIn": "+30", "checkOut": "+32", "maxHotelsPerSearch": 20}'
```

#### REST

```bash
curl -X POST "https://api.apify.com/v2/acts/hyperbach~google-hotels-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H 'Content-Type: application/json' -d '{"query": "hotels in New York", "checkIn": "+30", "checkOut": "+32", "maxHotelsPerSearch": 20}'
```

### Support

apify@hyperbach.com

*This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.*

# Actor input Schema

## `query` (type: `string`):

A place to search hotels in: a city, a neighbourhood, a landmark (`New York`, `hotels in Barcelona`, `Times Square hotels`). Google resolves the words; every row carries the place it resolved (`place_resolved`). Not searched when `searches` or `hotels` has an item: the list is then the whole run, and the dates and options here are its defaults.

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

The check-in date, `YYYY-MM-DD`, or `+N` for N days after the day of the run (UTC): `+30`. A date in the past is a free `invalid` row.

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

The check-out date, `YYYY-MM-DD` or `+N`; empty = the night after check-in. At most 30 nights.

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

A list of searches, each an object `{"query": "hotels in Paris", "checkIn": "+30", "checkOut": "+32", "adults": 2, "childrenAges": [8], "market": "FR", "language": "fr", "currency": "EUR", "sortBy": "lowest_price", "hotelClass": [4, 5], "minRating": 4, "maxPrice": 250, "amenities": ["pool"], "freeCancellation": true, "propertyType": "hotels"}` (the run's fields are the defaults; the run's `query` is then not searched), a text `hotels in Paris 2026-11-12 2026-11-14`, or a Google Hotels search URL. Up to 200 searches a run; a value that is no search is a free `invalid` row.

## `hotels` (type: `array`):

One hotel per line for the stay above: a name with its city (`Arlo NoMad New York`), a Google Hotels URL (`https://www.google.com/travel/hotels/entity/ChkI…/prices`) or a bare entity id (`ChkI5-ea3sPi9Y9PGg0vZy8xMWM1NF81cHF3EAE`). Each one is a `hotel` row with the dated booking-site list and the full record (the `details` event). With a hotel here, the run's `query` is not searched.

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

Adults in the room (1–10). Google prices one room; every price is for this party.

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

One line per child with the child's age (0–17): `8`, `3`. Google prices the stay for the party; the rows carry the ages asked.

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

Stop a place search after this many distinct hotels. 0 = every hotel Google lists for the stay: the relevance list to its end, then the class facets and the price order (about 500–900 distinct for a big city; the summary row says how many Google counts and whether the list was COMPLETE, TRUNCATED or CAPPED).

## `detailsFor` (type: `integer`):

For the first N hotels of each place search, one more call each: the dated price per booking site (Google's click-out link and the site's own deep link, the official-site flag, free cancellation), the address and phone, the amenity groups, the rating histogram, the review aspects and texts, the nearby places. Charged as the `details` event on those rows. Hotels in `hotels` always get it.

## `calendarDays` (type: `integer`):

For each hotel of `hotels` (and the first `detailsFor` hotels of a search), read the stay on each of the next N check-in dates, the stay's length kept: one `calendar_day` row per date with the lowest site price, the official site's price and the dated site list. One call per date.

## `sortBy` (type: `string`):

`relevance` keeps Google's own order (the first screen first); `lowest_price`, `highest_rating` and `most_reviewed` are Google's own sorts (the rows come out in that order).

## `hotelClass` (type: `array`):

Keep these classes only, one per line: `4`, `5`. Applied by Google.

## `minRating` (type: `string`):

Google's own rating steps: 3.5+, 4.0+ or 4.5+. Applied by Google.

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

Keep hotels up to this nightly price (before taxes, in `currency`). Applied by Google. 0 = no limit.

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

Keep hotels from this nightly price up (before taxes, in `currency`). Applied on the records read (Google's request takes no minimum). 0 = no limit.

## `amenities` (type: `array`):

Keep hotels with every one of these amenities, one per line: `free_parking`, `parking`, `indoor_pool`, `outdoor_pool`, `pool`, `fitness_center`, `restaurant`, `free_breakfast`, `spa`, `beach_access`, `kid_friendly`, `airport_shuttle`, `bar`, `pet_friendly`, `room_service`, `hot_tub`, `free_wifi`, `air_conditioning`. Applied by Google (its own amenity filter ids); several amenities = hotels with all of them.

## `freeCancellation` (type: `boolean`):

Keep hotels with a free-cancellation rate; the prices shown are the refundable rates. Applied by Google.

## `specialOffers` (type: `boolean`):

Keep hotels Google marks with a deal. Applied by Google.

## `propertyType` (type: `string`):

`hotels` (the default: Google's hotel records), `vacation_rentals` (the rental records of Google's mixed list: apartments, houses) or `all`. Every row carries `property_type`.

## `market` (type: `string`):

The two-letter country Google serves the view for (`US`, `GB`, `DE`, …): the point of sale and the strings' market.

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

The language of the texts (`en`, `de`, `fr`, `es`, `pt-BR`, …): class labels, descriptions, amenity group names.

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

The currency of every price (`USD`, `EUR`, `GBP`, `JPY`, …). Each row carries the currency Google answered with (`currency_served`); a list in another currency is a free `failed` row, never a charged one.

## `onlyChanges` (type: `boolean`):

Remember every hotel row delivered (by its Google id and stay) and, on the next run of the same memory, deliver only the hotels that are new or whose nightly price with taxes (or a site's price, with `detailsFor`) moved: `change_type`, `previous_price`, `price_change`, `sites_gained`, `sites_lost`, `sites_changed` say what. Unchanged hotels are counted, not delivered, not charged.

## `stateStoreName` (type: `string`):

With `onlyChanges`: the name of the memory to keep between runs (letters, digits, dashes); empty = a name derived from the searches.

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

Stop after this many charged rows (hotels and calendar days; the free `search` summary rows do not count). 0 = no limit.

## Actor input object example

```json
{
  "query": "hotels in New York",
  "checkIn": "+30",
  "checkOut": "+32",
  "searches": [],
  "hotels": [],
  "adults": 2,
  "childrenAges": [],
  "maxHotelsPerSearch": 20,
  "detailsFor": 0,
  "calendarDays": 0,
  "sortBy": "relevance",
  "hotelClass": [],
  "minRating": "",
  "maxPrice": 0,
  "minPrice": 0,
  "amenities": [],
  "freeCancellation": false,
  "specialOffers": false,
  "propertyType": "hotels",
  "market": "US",
  "language": "en",
  "currency": "USD",
  "onlyChanges": false,
  "stateStoreName": "",
  "maxItems": 0
}
```

# Actor output Schema

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

All scraped records in the default dataset. One row per hotel (and one free summary row per search; price-calendar days are rows of their own kind):

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

How the run went: hotels, details and calendar days charged, free rows, searches by status, the walk per search (Google's count, pages and facet lists read, distinct hotels found and delivered, the verdict), unchanged hotels not delivered (onlyChanges), the exit window (fresh exits probed, exits open, the open rate, 'near <town>' answers, empty envelopes) and the source counters (requests, served, rotations, bytes).

# 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 = {
    "query": "hotels in New York",
    "checkIn": "+30",
    "checkOut": "+32",
    "maxHotelsPerSearch": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("hyperbach/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 = {
    "query": "hotels in New York",
    "checkIn": "+30",
    "checkOut": "+32",
    "maxHotelsPerSearch": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("hyperbach/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 '{
  "query": "hotels in New York",
  "checkIn": "+30",
  "checkOut": "+32",
  "maxHotelsPerSearch": 20
}' |
apify call hyperbach/google-hotels-scraper --silent --output-dataset

```

## MCP server setup

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