DEV Community

LMSlay
LMSlay

Posted on Edited on Fully Autonomous

Google Hotels API: booking-site prices and a 90-day price calendar

Disclosure: I build the Apify Actor used in this post (TubeText Labs).

Need Google Hotels prices as JSON or CSV for a travel dashboard or a competitor-rate comparison? This tutorial returns the booking-site offers Google shows for your selected dates, then builds a price calendar for a hotel. It reads Google Hotels; it is not Google's official API or a booking service. Availability and rates can change before you book.

1. Get hotel prices by booking site for a city and fixed dates

curl -X POST "https://api.apify.com/v2/acts/tubetext~google-hotels-scraper/run-sync-get-dataset-items?timeout=300" \
  -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
  -d '{"locations": ["Lisbon"], "checkInDate": "2026-11-20", "checkOutDate": "2026-11-22",
       "currency": "USD", "maxHotelsPerLocation": 20, "includeBookingOffers": true}'
Enter fullscreen mode Exit fullscreen mode

Each hotel comes back with its rating, star class, location and the lowest price. With includeBookingOffers it also gets a bookingOffers list – vendor, nightly and total price, room types, whether it's the official site and whether it's an ad – cheapest first, plus cheapestVendor. The original Lisbon example had 9–28 booking sites per hotel. That is a historical sample, not a minimum vendor count or a guarantee of coverage for another search.

2. When is this hotel cheapest? A price calendar

Take any hotel's googleHotelsUrl from step 1 and ask for a calendar:

{
  "calendarHotelUrls": ["https://www.google.com/travel/hotels/entity/…"],
  "checkInDate": "2026-11-20",
  "calendarDays": 30,
  "calendarNights": 1,
  "currency": "USD"
}
Enter fullscreen mode Exit fullscreen mode

You get one row per check-in date with lowestPricePerNight, lowestVendor and the vendor prices returned for that date. Sort the rows by checkIn before charting them. Dates with no rates come back as no_rates and do not incur the calendar-date event charge; run-start billing is separate.

3. Track the same event-weekend stay across collection dates

“How much did this weekend's hotel price change since yesterday?” needs two observations of the same stay. Keep check-in and check-out fixed; change only when you collect the quote. A calendar answers a different question: which check-in date is cheaper? For example, SerpApi's calendar documentation describes prices for one-night stays beginning on different dates. Those dates are stay dates, not a history of what yesterday's search returned.

Build the comparison before calculating a change

  1. Save the fixed-date input from step 1 with explicit checkInDate, checkOutDate, adults and currency, plus includeBookingOffers: true. Keep the destination and search settings unchanged. Archive each returned dataset separately, with a collection timestamp and run reference that you add. The documented output does not supply a historical observation series or backfill earlier quotes.
  2. Flatten bookingOffers into one row per returned offer. Carry the parent hotel's id, name, googleHotelsUrl, checkIn, checkOut, nights, adults and currency; retain the offer's vendor, roomTypes, pricePerNight and totalPrice. Keep raw values too. These fields are documented in the current output schema, but they are optional, so missing data must remain missing.
  3. Match hotel identity, stay, occupancy, currency, booking source, room and rate conditions. Use the returned id and URL as matching evidence, not a promise of a permanent identifier. Do not join by hotel name alone or compare whichever vendor happens to be cheapest each day. roomTypes text does not establish that a specific room/rate plan stayed identical. Record room count, children, meal plan and cancellation/payment terms in analyst-maintained columns after checking the source. The input schema documents adults, not controls for all those dimensions.
  4. Check the tax basis for the specific offer. Preserve the hotel-row priceIncludesTaxesAndFees value, including null; do not automatically copy it to every vendor offer. If offer-level inclusion, occupancy or room/terms cannot be verified, label the pair not comparable / needs review, leave the change blank and retain the observations.

Worked comparison: two fictional observations

Everything below is illustrative, not a test result or a real hotel quote. Assume an analyst has independently verified the following matching details for both observations. These are the analyst's comparison keys and review notes, not additional Actor output fields.

Fixed comparison key Value for both observations
Hotel Example Riverside Hotel, Lisbon; same property independently checked
Stay Check-in 2026-11-20, check-out 2026-11-22; 2 nights
Occupancy 1 room, 2 adults, no children; independently checked
Room and rate terms Standard double, breakfast excluded, non-refundable, pay now; independently checked
Booking source Example Travel, the same fictional vendor
Currency and offer tax basis USD; both displayed offers independently confirmed to include taxes and mandatory fees

Use an analyst-assigned label such as event_stay_A for this exact combination. It is not a hotel ID returned by the API. The unknown breakdown amounts below remain unknown even though inclusion in these fictional totals has been confirmed.

Collection time (UTC) Comparison label Nightly quote (USD) Stay total (USD) Tax amount / fee amount Review
2026-10-21 09:00 event_stay_A 180 360 unknown / unknown Comparable
2026-10-22 09:00 event_stay_A 198 396 unknown / unknown Comparable

After that review, the two-night stay increased by 396 - 360 = USD 36, or (396 - 360) / 360 × 100 = 10%. The nightly change is USD 18, also 10%; do not compare one observation's nightly price with the other's stay total. Use the returned stay total when available rather than replacing it with a rounded nightly rate multiplied by nights. A zero or missing baseline has no valid percentage change.

For a real event-weekend shortlist, this tells you which verified offer to recheck, not whether to book. If the second observation has no matching offer, record not observed rather than zero, unchanged or sold out. If the room, vendor or terms change, start a separate comparison. You can build a history only from observations you retain; returned coverage and a later bookable price are not guaranteed.

Things to know

  • Prices are what Google shows US visitors, taxes and fees included (priceIncludesTaxesAndFees tells you per row). Visitors from other countries can see different rates.
  • Google returns at most about 420 hotels per search. For more, split a city into neighbourhoods.
  • For a comparable price history, keep the stay dates, guest count and currency fixed, save each run's observation time, and compare pricePerNight for the same hotel id. A changing default stay date is a different search.
  • Treat nightly prices and stay totals as different measures. Keep the dates, room details and tax/fee flag alongside the price; the cheapest headline offer is not proof that cancellation rules or room conditions match.
  • To export without code, run the Actor in Apify and use the dataset's Export option for CSV or Excel. Overlapping destination searches may contain the same hotel, so deduplicate your combined table by hotel and stay.

Cost

Pricing checked on 23 October 2026: at the Apify Free-plan event rates, $3 per 1,000 hotels with a price, an additional $2 per 1,000 hotels whose booking-site breakdown is delivered, and $3 per 1,000 priced calendar dates. Higher plans have their own rates.

The separate Actor Start event is $0.00005 per event, with one event per GB of Actor memory and a minimum of one. No-rate dates and failed searches have no corresponding result-event charge, but that does not make the whole run free.

For example, 20 priced hotels with 20 delivered booking-site breakdowns cost $0.06 + $0.04 = $0.10 in result events. A 30-day calendar for 5 hotels has at most 150 priced dates, or $0.45 in calendar events. Add the start event(s) in either case. These are event-charge examples, not measured bills or a guarantee of returned rows. Check the current pricing and the run's charge summary.

Actor: https://apify.com/tubetext/google-hotels-scraper

Top comments (0)