Arcadium Data Scrapers
Home / Guides / Google Hotels Scraper

How to use Google Hotels Scraper

Step by step: in the Apify Store, over the API, from JavaScript or Python, in n8n, and from AI agents through MCP or LangChain.

$4.49 per 1,000 hotel rows on the Free plan, down to $2.69 on higher plans (live Apify price on 2026-10-31).

1. In the Apify Store (no code)

  1. Open arcadium/google-hotels and sign in to Apify (a free account works).
  2. Fill in the input form. The fields below are the ones the example uses.
  3. Set a maximum cost per run in the run options if you want a hard cap.
  4. Start the run. Rows appear in the Output tab as they arrive.
  5. Export the dataset as JSON, CSV or Excel, or connect an integration.
Input fieldTypeDescription
locationsarrayPlaces to search, for example "Paris", "Times Square New York" or "resorts in Cancun". A plain place name is searched as "hotels in <place>". Each location returns up to 'Max hotels' hotels per check-in date, with Google's lowest price, rating, class, amenities and coordinates.
maxHotelsintegerHotels to return for each location and check-in date, 1 to 500, for example 50. Google lists about 20 per page; sort and filters are applied by Google before this cap.
checkInDatesarrayCheck-in dates as YYYY-MM-DD, or relative to today such as "+30d", "6 weeks" or "tomorrow". Example: ["2026-12-10", "+45d"]. Up to a year ahead. If this and the range below are empty, one stay 30 days from now is used.
nightsarrayLengths of stay in nights, for example [1, 3, 7]. Each value gives its own row per hotel and check-in date. 1 to 30 nights; default [1].
languagestringGoogle interface language (hl), for example en, de, fr or pt-BR. Sets the language of descriptions and deal labels.
countrystringCountry of the searcher (gl), two letters, for example us, gb or de. Not the destination: it can change which booking sites appear and whether prices include taxes.

Example input:

{
  "locations": [
    "Paris"
  ],
  "maxHotels": 20,
  "checkInDates": [
    "+30d"
  ],
  "nights": [
    2
  ],
  "language": "en",
  "country": "us"
}

2. Over the Apify API

The synchronous endpoint runs the actor and returns its rows in one call (for runs up to about five minutes; use the asynchronous run endpoint for longer ones).

curl -X POST "https://api.apify.com/v2/acts/arcadium~google-hotels/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"locations":["Paris"],"maxHotels":20,"checkInDates":["+30d"],"nights":[2],"language":"en","country":"us"}'

3. From JavaScript

// npm install apify-client
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('arcadium/google-hotels').call({
  "locations": [
    "Paris"
  ],
  "maxHotels": 20,
  "checkInDates": [
    "+30d"
  ],
  "nights": [
    2
  ],
  "language": "en",
  "country": "us"
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

4. From Python

# pip install apify-client
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arcadium/google-hotels").call(run_input={
    "locations": ["Paris"],
    "maxHotels": 20,
    "checkInDates": ["+30d"],
    "nights": [2],
    "language": "en",
    "country": "us",
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)

5. In n8n

Paste this node into a workflow (it is a plain HTTP Request node). Create a Header Auth credential with name Authorization and value Bearer <APIFY_TOKEN>; each returned row becomes one item for the next node.

{
  "nodes": [
    {
      "name": "Run arcadium/google-hotels",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        0,
        0
      ],
      "parameters": {
        "method": "POST",
        "url": "https://api.apify.com/v2/acts/arcadium~google-hotels/run-sync-get-dataset-items",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "{\"locations\":[\"Paris\"],\"maxHotels\":20,\"checkInDates\":[\"+30d\"],\"nights\":[2],\"language\":\"en\",\"country\":\"us\"}",
        "options": {
          "timeout": 300000
        }
      }
    }
  ],
  "connections": {}
}

6. From an AI assistant (MCP)

Add Apify’s MCP server to Claude Desktop, Cursor, VS Code or any MCP client, limited to this actor:

{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?tools=arcadium/google-hotels",
      "headers": {
        "Authorization": "Bearer <APIFY_TOKEN>"
      }
    }
  }
}

More on the MCP page.

7. From LangChain

# pip install langchain-apify   (reads APIFY_API_TOKEN from the environment)
from langchain_apify import ApifyActorsTool

tool = ApifyActorsTool("arcadium/google-hotels")
rows = tool.invoke({"run_input": {
    "locations": ["Paris"],
    "maxHotels": 20,
    "checkInDates": ["+30d"],
    "nights": [2],
    "language": "en",
    "country": "us",
}})
# or give `tool` to an agent: create_react_agent(llm, [tool])

Sample output

One row, from the example in the actor’s README. Long text is shortened and lists are cut to two items.

{
  "rowType": "hotel",
  "platform": "google-hotels",
  "entityId": "ChoI_uTZsvz1i6-bARoNL2cvMTFmZHB6eDEwMxAB",
  "name": "The Originals Boutique, Hôtel Maison Montmartre, Paris",
  "googleUrl": "https://www.google.com/travel/hotels/entity/ChoI_uTZsvz1i6-bARoNL2cvMTFmZHB6eDEwMxAB",
  "propertyType": "hotel",
  "hotelClass": 4,
  "rating": 4,
  "reviewCount": 2133,
  "latitude": 48.900537,
  "longitude": 2.336269,
  "amenities": [
    "Free Wi-Fi",
    "Air conditioning"
  ],
  "checkIn": "2026-11-10",
  "checkOut": "2026-11-12",
  "nights": 2,
  "adults": 2,
  "currency": "USD",
  "available": true,
  "pricePerNight": 81.75,
  "totalPrice": 163.5,
  "pricesIncludeTaxes": true,
  "priceBeforeTaxes": 136.25,
  "taxesAndFees": 27.25,
  "deal": "30% less than usual",
  "dealPercent": 30,
  "searchLocation": "Paris",
  "searchRank": 1,
  "totalResults": 15000
}
FieldWhat it holds
rowTypeKind of row. Filter on this first. 'hotel': one hotel for one stay (charged as 'hotel'). 'offer': one booking site's price for one hotel and stay (charged as 'offer'). 'error': an input or date could not be read; see code and message (free).
platformAlways 'google-hotels'.
entityIdGoogle Hotels entity token of the property (the Ch... id in its link). Use it in 'hotels' to price the same hotel again.
nameHotel row: property name as Google shows it.
hotelNameOffer row: name of the hotel the offer belongs to.
googleUrlGoogle Hotels page of the property.
propertyType'hotel' or 'vacation_rental'.
hotelClassStar class 1-5; null when the property has none (hostels, rentals).
hotelClassLabelClass as Google words it, e.g. '4-star tourist hotel'.
ratingGoogle guest rating out of 5.
reviewCountNumber of Google reviews behind the rating.
latitudeLatitude of the property.
longitudeLongitude of the property.
addressStreet address of a hotel (hotel lookups and includeOffers only; never for vacation rentals).
countryCodeTwo-letter country code of the property.
descriptionGoogle's one-line summary of the property.
thumbnailUrlSmall photo of the property.
websiteThe property's own website link, when Google has one.
amenitiesAmenities Google lists on the result card, e.g. 'Free Wi-Fi', 'Pool', 'Spa'. Empty on hotel lookups.
amenityCodesGoogle's numeric amenity codes behind 'amenities' (some codes have no label yet).
checkInTimeHotel check-in time, e.g. '3:00 PM'.
checkOutTimeHotel check-out time, e.g. '12:00 PM'.
checkInCheck-in date of the stay, YYYY-MM-DD.
checkOutCheck-out date of the stay, YYYY-MM-DD.
nightsLength of the stay in nights.
adultsAdults in the room.
childrenNumber of children in the room.
childrenAgesAges of the children in the room.
currencyISO currency code of every price in the row.
availableHotel row: true when Google shows a price for the stay; false = nothing bookable for these dates and guests.
pricePerNightLowest nightly price shown (hotel row) or this booking site's nightly price (offer row).
pricePerNightTextThe nightly price as displayed, e.g. '$134'.
totalPricePrice of the whole stay as Google shows it; see pricesIncludeTaxes.
pricesIncludeTaxestrue when the shown prices include taxes and fees, false when they do not, null when unclear. Google decides this per market and currency.
totalPriceWithTaxesHotel row: stay total including taxes and fees, from Google's price split.
priceBeforeTaxesHotel row: stay total before taxes and fees.
taxesAndFeesHotel row: taxes and fees for the stay (totalPriceWithTaxes minus priceBeforeTaxes).
dealGoogle's deal note, e.g. '30% less than usual' or 'GREAT PRICE for a 4-star hotel'.
dealPercentThe percentage in the deal note, e.g. 30.
offerCountHotel row: booking sites with a price for the stay; null when offers were not read.
lowestOfferProviderHotel row: booking site with the lowest total, when offers were read.
searchLocationThe location text this row was found with; null for hotel lookups.
searchRankPosition in Google's result list for the location (1 = first).
totalResultsGoogle's estimate of all properties matching the location search.
inputHotel lookups: the link, token or name you gave.
offerRankOffer row: 1 = cheapest booking site for this hotel and stay.
providerOffer row: booking site name, e.g. 'Booking.com', 'Expedia.com', or the hotel itself for its official site.
providerIdOffer row: Google's numeric id of the booking site (stable across hotels).
isOfficialSiteOffer row: true when the offer is the hotel's own website.
featuredOffer row: shown in the highlighted block at the top of Google's price list.
freeCancellationOffer row: true / false when Google states it for the site's lowest rate; null when it does not say.
freeCancellationUntilOffer row: last day to cancel for free, YYYY-MM-DD.
freeCancellationUntilTimeOffer row: time of day of the free-cancellation deadline, when given.
roomNameOffer row: cheapest room of this site, when Google lists rooms (featured sites).
rateCountOffer row: room rates Google lists for this site; 0 when it shows only the lowest.
cheapestFreeCancellationPriceOffer row: lowest nightly price among this site's free-cancellation rates, when rooms are listed.
scrapedAtWhen the row was read (ISO 8601).
codeError row: invalid_input, not_found, no_match, blocked or unavailable. Retry blocked and unavailable later; the others will fail again with the same input.
messageError row: what went wrong, in plain words.

Schedule it

In Apify Console, create a Task from your input and add a Schedule (for example daily). Each run writes a new dataset; integrations can push the rows to Google Sheets, Slack, a webhook or your database.