I built this actor; it's a paid tool on Apify with a free trial credit.
Google Hotels shows you a price for every hotel in a city, but there's no official API for it. If you want to watch how prices move over a few weeks, compare a hotel against its neighbours, or feed prices into a trip planner, you end up copying numbers by hand.
I'm an 18-year-old engineering student, and I wrote a scraper for this called Google Hotels Scraper. This post shows how to call it from Python and Node, what the data looks like, and one small project: logging Charlotte hotel prices to a Google Sheet once a day.
How it works, briefly
Google Hotels pages already carry their result data inside AF_initDataCallback script blobs. The actor fetches the page over plain HTTP (no headless browser), parses those blobs and picks out anything shaped like a hotel record. That's why a 50-hotel query usually finishes in well under a minute.
Python example
pip install apify-client
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("rel8ble/google-hotels-scraper").call(run_input={
"queries": ["hotels in Charlotte"],
"checkIn": "2026-10-15",
"checkOut": "2026-10-18",
"adults": 2,
"currency": "USD",
"maxResults": 50,
})
for hotel in client.dataset(run["defaultDatasetId"]).iterate_items():
print(hotel["name"], hotel["pricePerNight"], hotel["rating"], hotel.get("deal"))
Node example
npm install apify-client
import { ApifyClient } from "apify-client";
const client = new ApifyClient({ token: "<YOUR_APIFY_TOKEN>" });
const run = await client.actor("rel8ble/google-hotels-scraper").call({
queries: ["hotels in Charlotte"],
checkIn: "2026-10-15",
checkOut: "2026-10-18",
maxResults: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((h) => `${h.name}: $${h.pricePerNight}/night`));
What comes back
One item per property. This is a real row from a test run (Charlotte, 3 nights, 15-18 Oct 2026), trimmed:
{
"query": "hotels in Charlotte",
"position": 1,
"name": "Sonesta Select Charlotte University Research Park",
"pricePerNight": 75,
"pricePerNightWithTaxes": 88,
"totalPrice": 263,
"totalTaxesAndFees": 54.5,
"currency": "USD",
"deal": "DEAL 19% less than usual",
"nights": 3,
"rating": 3.9,
"reviewCount": 915,
"hotelClass": 3,
"latitude": 35.3072356,
"longitude": -80.7534261,
"checkInTime": "4:00 PM",
"checkOutTime": "11:00 AM",
"entityToken": "ChYIl4r5ruWLqpcWGgovbS8wejlfbDlqEAE",
"googleMapsUrl": "https://www.google.com/maps?cid=16387801168794899843",
"scrapedAt": "2026-09-23T23:01:40.083Z"
}
You also get amenities, nearby places with travel times, photos, a short description and the official website. Turn on includeDetails and you get the street address and phone number too (one extra request per hotel).
The field I lean on most is entityToken. It stays the same across runs, so it's the key for joining today's price to yesterday's.
Use case: log Charlotte hotel prices to Google Sheets every day
The goal: one row per hotel per day, so after a couple of weeks you can chart how prices move for a fixed stay.
I use gspread with a Google service account (share the sheet with the service account's email first).
pip install apify-client gspread
import datetime
import gspread
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
sheet = gspread.service_account(filename="service-account.json").open("Charlotte hotel prices").sheet1
run = client.actor("rel8ble/google-hotels-scraper").call(run_input={
"queries": ["hotels in Charlotte"],
"checkIn": "2026-11-20",
"checkOut": "2026-11-22",
"currency": "USD",
"maxResults": 50,
})
today = datetime.date.today().isoformat()
rows = []
for h in client.dataset(run["defaultDatasetId"]).iterate_items():
rows.append([
today,
h["entityToken"],
h["name"],
h.get("pricePerNight"),
h.get("totalPrice"),
h.get("rating"),
h.get("deal") or "",
])
sheet.append_rows(rows, value_input_option="USER_ENTERED")
print(f"appended {len(rows)} rows")
Run it once a day with cron, Task Scheduler or a GitHub Actions schedule. You could also skip the script: set up a Schedule in the Apify Console and use the Google Sheets integration there. After a week, a pivot table on entityToken × date shows you which hotels are dropping and which aren't.
Keep the check-in and check-out dates fixed. If you change them, you're comparing different stays, not watching one stay's price move.
What it costs
Pricing is $3.50 per 1,000 results, and one result is one hotel saved. You aren't charged for duplicates or failed requests.
- The daily job above: 50 hotels × 30 days = 1,500 results ≈ $5.25/month
- A one-off market scan of 1,000 hotels = $3.50
- Apify's free plan gives $5 of monthly credit, which covers roughly 1,400 hotels
Limits
These come straight from my testing:
-
About 150-250 unique hotels per query. After that Google only serves vacation rentals or repeats. For a big city, split it up:
"hotels in Shinjuku","hotels in Shibuya". -
Prices are Google's "from" price: the lowest rate across booking partners for your dates and guests. Properties with no rooms for your dates return
pricePerNight: null(about 9% in a 300-hotel test). - No per-partner price list (Booking.com vs Expedia vs direct) and no review texts in this version.
-
Address and phone need
includeDetails, which is slower. - Google reshuffles results between pages, so a page sometimes adds fewer than 20 new hotels after dedup.
If something breaks or a field is wrong, the Issues tab on the actor page reaches me directly.
Google Hotels Scraper on Apify
This article was drafted with AI and published by me.
Top comments (0)