Monitor Google Hotels Prices for Revenue Strategy (2026)
Monitor Google Hotels prices, ratings, and competitors by destination and stay date. Build repeatable hotel revenue reports with Python and Apify schedules.

The Thirdwatch Google Hotels Scraper turns destination and property searches into structured hotel records with displayed prices, ratings, review counts, hotel class, images, and Google Travel links. Revenue managers, travel analysts, destination teams, and hotel operators can schedule identical searches, build competitive-set snapshots, compare neighborhoods or date windows, and detect meaningful rate-positioning changes without manually copying Google Hotels results.
▶ Skip the setup: Run the hotel revenue-strategy Task on Apify → — it is preloaded with the small, tested London configuration from this guide. No code required.
Disclosure: Thirdwatch's Apify links include its referral parameter. This does not change your price.
Why monitor Google Hotels prices for revenue strategy
Google Hotels price monitoring provides a consistent external view of how properties appear to travelers. Google's own Travel Help explains that hotel results can be filtered by price, location, user rating, and class, while ranking considers search terms, location, price, ratings, and reviews. It also states that a hotel is labeled a “Deal” when its price ratio is at least 15% lower than comparable nearby properties, and a “Great Deal” at 25% lower.
That makes the search surface useful for revenue strategy, but only when inputs are controlled. A London hotel searched for next weekend is not comparable with the same property searched for a weekday three months away. Currency, guest count, language, dates, and destination wording all affect the displayed context.
A disciplined monitor repeats the same search matrix, stores snapshots, and flags changes relative to the competitive set. The Google Hotels Scraper actor page supplies the structured search-result layer; the analyst defines the segments and decision rules.
How does this compare to the alternatives?
Hotel teams can shop rates manually, license a revenue platform, or automate focused Google Hotels snapshots.
| Method | Commercial model | Reliability | Setup time | Maintenance |
|---|---|---|---|---|
| Manual Google Hotels checks | Staff time | Good for a tiny competitive set | Minutes | Repeated searching and spreadsheets |
| Enterprise revenue platform | Subscription and implementation | Broad integrations | Weeks | Vendor and property onboarding |
| Thirdwatch Google Hotels Scraper | Pay per saved hotel | Repeatable search-result records | About five minutes | Thirdwatch maintains the Actor |
Manual checks are appropriate for investigating a specific anomaly. Enterprise systems are appropriate when forecasting, inventory, distribution, and property-management integrations must sit in one product. The Thirdwatch Actor fits teams that need a transparent search-result feed for custom dashboards, market reports, lead generation, or an existing revenue stack.
How to monitor Google Hotels prices in 4 steps
How do I define a stable hotel search matrix?
Fix the dimensions that should not change between snapshots. Use descriptive destination queries and explicit stay dates, adults, currency, and language.
from datetime import date, timedelta
today = date.today()
check_in = today + timedelta(days=30)
check_out = check_in + timedelta(days=2)
run_input = {
"queries": [
"4 star hotels near Tower Bridge London",
"boutique hotels in Shoreditch London",
"family hotels near Hyde Park London",
],
"checkIn": check_in.isoformat(),
"checkOut": check_out.isoformat(),
"adults": 2,
"currency": "GBP",
"language": "en",
"maxResultsPerQuery": 50,
}Specific segments reduce overlap and make the output easier to explain. Keep a versioned configuration file so an analyst can tell whether a price movement came from the market or from an input change.
How do I collect Google Hotels results with Python?
Use the official Apify client and the exact Actor input fields. The Apify API documentation explains the underlying run and dataset resources.
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("thirdwatch/google-hotels-scraper").call(run_input=run_input)
hotels = list(client.dataset(run["defaultDatasetId"]).iterate_items())
print(f"Collected {len(hotels)} hotel search results")
for hotel in hotels[:5]:
print(hotel.get("query"), hotel.get("name"), hotel.get("price"))Every row retains the originating query, which is important when one property appears in several segments. Store the dataset ID and collection time with each snapshot.
How do I normalize displayed hotel prices?
The price field is display text, so normalize it before calculating deltas. Keep the original field for auditability.
import re
import pandas as pd
df = pd.DataFrame(hotels)
def parse_price(value):
digits = re.sub(r"[^0-9.,]", "", value or "")
if not digits:
return None
if "," in digits and "." in digits:
decimal = "," if digits.rfind(",") > digits.rfind(".") else "."
thousands = "." if decimal == "," else ","
digits = digits.replace(thousands, "").replace(decimal, ".")
elif "," in digits:
head, tail = digits.rsplit(",", 1)
digits = f"{head.replace(',', '')}.{tail}" if len(tail) in (1, 2) else digits.replace(",", "")
elif "." in digits:
head, tail = digits.rsplit(".", 1)
digits = f"{head.replace('.', '')}.{tail}" if len(tail) in (1, 2) else digits.replace(".", "")
return float(digits)
df["price_value"] = df["price"].map(parse_price)
df["snapshot_date"] = date.today().isoformat()
df.to_parquet(f"google-hotels-{date.today().isoformat()}.parquet", index=False)
segment_summary = (
df.groupby("query", dropna=False)
.agg(hotels=("name", "nunique"), median_price=("price_value", "median"),
median_rating=("rating", "median"))
)
print(segment_summary)Do not mix currencies in a single median. A blank price is a missing observation, not zero. Keep it out of price aggregates while retaining the hotel for coverage analysis.
How do I detect competitive rate changes?
The Actor does not expose a durable property identifier, so join snapshots on an explicit composite key and keep a reviewable alias table for renamed hotels. This is more honest than treating a name-derived Google search URL as a stable ID.
current = df.copy()
previous = pd.read_parquet("google-hotels-previous.parquet")
def property_key(row):
parts = [row.get("name", ""), row.get("query", ""), str(row.get("hotel_class", ""))]
return "|".join(re.sub(r"\W+", "-", part.lower()).strip("-") for part in parts)
current["property_key"] = current.apply(property_key, axis=1)
previous["property_key"] = previous.apply(property_key, axis=1)
changes = current.merge(
previous[["property_key", "price_value"]],
on="property_key", suffixes=("_now", "_before")
)
changes["price_change_pct"] = (
changes["price_value_now"] / changes["price_value_before"] - 1
) * 100
alerts = changes[changes["price_change_pct"].abs() >= 10]
print(alerts[["name", "price_value_before", "price_value_now", "price_change_pct"]])A 10% threshold is an operational starting point, not a universal rule. Tune it to the normal volatility of the destination and booking window.
Sample Google Hotels output
One result represents a property as displayed for its originating search.
The record below is an illustrative synthetic example, not a current rate observation.
{
"query": "4 star hotels near Tower Bridge London",
"name": "The Tower Hotel, London",
"price": "£189",
"currency": "GBP",
"rating": 4.1,
"reviews_count": 6421,
"hotel_class": 4,
"details": "4-star hotel",
"image_url": "https://lh3.googleusercontent.com/example",
"url": "https://www.google.com/travel/search?q=The+Tower+Hotel%2C+London"
}Use query to preserve the segment, price and currency for rate observations, and rating, review count, and class for competitive-set context. The URL supports manual verification. Optional values can be absent when Google does not display them for that search.
Common pitfalls in Google Hotels monitoring
The largest error is comparing different stay contexts. Keep dates, occupancy, currency, language, and query stable. The second is treating a displayed price as a final quote. Google says partner prices can change quickly and advises checking the final room cost; taxes, fees, availability, device-specific offers, and sign-in state can differ. The third is assuming missing price means unavailable. It only means the search result did not expose a price in that response.
Duplicate properties across queries can also inflate portfolio counts. Deduplicate at the property level while retaining a list of matched segments. Finally, hotel names are not perfect identifiers. Prefer the URL and maintain a reviewable alias table. Thirdwatch returns the observable search fields and query provenance so these controls can be implemented without hiding uncertainty.
Related hotel intelligence use cases
Frequently asked questions
Can Google Hotels prices be monitored automatically?
Yes. Run the same destination, dates, guests, currency, and language on a schedule, then compare each dated dataset. Stable inputs are essential because changing the stay context can change the displayed price independently of a hotel's pricing decision.
Are Google Hotels prices final booking quotes?
No. The results are prices displayed by Google for the selected search context. Taxes, fees, availability, personalized offers, and booking conditions can change before checkout, so material decisions should be confirmed with the booking provider.
Does the Actor return room-level offers and amenities?
No. The Actor focuses on hotel search results: names, displayed prices, ratings, review counts, class, details, images, and Google Travel links. Use a deeper hotel Actor when room inventories, booking-provider offers, amenities, or full reviews are required.
How should hotels be compared across markets?
Compare hotels within the same destination, stay dates, guest count, currency, and search segment. Normalizing those inputs prevents currency and booking-window differences from being mistaken for competitive price movement.
Related
100 free credits, no credit card.
About 30 real searches. Add the MCP to Claude or Cursor in two minutes.