search_stays
Search available hotels and vacation rentals by city, dates, and party size. Returns ranked results with prices, ratings, amenities, and booking links.
Instructions
๐ฏ RENDERING DIRECTIVE โ READ FIRST. When this tool returns 2+ stay offers, you MUST present them as an interactive HTML/React artifact (Artifacts block, not flowing prose). Each stay is a visually distinct CARD with a prominent "Book on Google Hotels" button styled as an HTML button, NOT an inline markdown hyperlink. Plain prose with [text](url) links is NOT acceptable for multi-result responses โ the user can't click a paragraph. If this call is part of a larger trip-plan response, the trip plan ITSELF should be an artifact containing the stay cards. Single-result responses may use prose.
Search Google's hotel AND vacation rental listings for a city, date range, and party size, returning a ranked unified list of available places to stay.
Returns ranked stay offers โ each with name, photos, star rating (hotels only), review score, price (per-night and total), top amenities, GPS coordinates, a category badge ("hotel" or "vacation_rental"), per-property OTA price comparison via sources, and a Google Hotels deep link. Does NOT book โ the booking_url opens the specific property's Google Hotels entity page with the user's check-in/check-out pre-filled, where they can click through to a booking partner.
category selector:
"all"(default) โ fans out to TWO SerpAPI calls in parallel: one for hotels, one for vacation rentals. Merges, dedupes, sorts. Latency is ~3s (parallel, not summed). Costs 2 SerpAPI calls instead of 1 per query โ burns SERPAPI quota twice as fast."hotels"โ only hotel-class properties. One SerpAPI call."vacation_rentals"โ only short-term rentals via SerpAPI's aggregation. Surfaces OTAs (Booking.com, Hotels.com, Bluepillow.com, Vrbo.com when available). Airbnb is NOT in Google's aggregation โ usecategory="airbnb"for that."airbnb"โ bypasses SerpAPI entirely and queries Airbnb directly (via the pyairbnb library). Use this when the user specifically asks for "Airbnb" / "AirBNB" / "stuff on Airbnb". Costs NO SerpAPI quota but is slower and more fragile (Airbnb may block scraping during high traffic). Filter parameters supported:min_bedrooms,min_bathrooms,min_review_score,max_price_per_night.min_ratingis ignored (Airbnb listings have no hotel-class star rating).
sources is a per-offer list of (name, price_per_night) entries showing the same property listed across different booking partners. Empty list for hotels in the current data (SerpAPI doesn't surface partner prices for hotels in our queries). Populated for vacation rentals.
Prices come back in EUR by default (matches the flights tool's typical response currency for European-IP users). Pass currency (ISO 4217, e.g. "USD", "JPY", "GBP") to override per call. The currency field on each offer reflects what was actually requested.
Filter scoping (important โ the wrong filter on the wrong category is silently dropped):
min_rating(1-5 stars) applies only to hotels. Whencategory="all", it filters the hotel side; vacation rentals pass through unfiltered (they have no hotel class).min_bedroomsandmin_bathroomsapply only to vacation rentals. Filter the rental side; hotels pass through.min_review_score,max_price_per_night,required_amenities,sort_by,max_results,currencyapply uniformly.
address is always null on offers โ SerpAPI's google_hotels list endpoint doesn't carry per-property addresses. Use latitude/longitude for location.
The review score is Google's native 0-5 scale (e.g., 4.6 / 5), NOT a 0-10 scale.
sort_by accepts: BEST (preserve SerpAPI's returned order; for the merged path this falls back to price-ascending as the tie-breaker since neither response has a globally meaningful rank), PRICE_LOW, PRICE_HIGH, RATING (star rating descending; hotels-only signal), REVIEW_SCORE (review_score descending, review_count tie-break).
PRE-CALL ELICITATION: Before calling this tool, confirm with the user:
Type of stay (
category): default to"all"unless the user signals otherwise. "Find me a place to stay in Lisbon" stays at"all". "Find me a nice hotel in Lisbon" โ"hotels". "Find me a rental in Lisbon" โ"vacation_rentals". "Find me an Airbnb in Lisbon" โ"airbnb"(this hits Airbnb directly; SerpAPI doesn't include Airbnb listings).Location: specific city or neighborhood โ "Tampere" works, "Notting Hill, London" works, "somewhere in Europe" does not. Ask if vague.
Check-in and check-out dates: both required and check_out must be strictly after check_in. Confirm UTC-today or later.
Party size: adults, children, and number of rooms. Default is 2 adults / 0 children / 1 room โ don't assume; ask if not stated.
Budget: any per-night ceiling? If the user said "cheap" or "affordable", ask for a concrete number to set max_price_per_night.
Must-have amenities: wifi, breakfast, parking, gym, pool, pet-friendly? Don't assume; ask.
Star rating or review score floor: "at least 4 stars", "well-reviewed (8+)"? Map to min_rating or min_review_score (remember review_score is 0-5, so "8+" should become min_review_score=4.0 or you should ask for clarification).
Rental size: if the user mentioned bedrooms or bathrooms ("a 2-bedroom apartment"), set
min_bedrooms/min_bathrooms. These constrain the vacation-rental side only.Sort priority: cheapest first, highest-rated, best location? Map to sort_by.
Currency: infer from the user's stated location or budget. "I'm in Tokyo, budget ยฅ30000/night" โ
currency="JPY",max_price_per_night=30000. "$200/night in NYC" โcurrency="USD". Default"EUR"if the user gives no signal. Always pass the currency that matches the units the user spoke in formax_price_per_nightโ mixing currencies silently corrupts the budget filter.
RESULT PRESENTATION: When returning 2+ stays, render them as an interactive artifact with one card per offer. Each card shows:
The stay name, prominent and large at the top of the card (it carries the card's visual hierarchy in the absence of a photo).
A small category badge at the top:
HotelorVacation rental, taken from thecategoryfield.Star rating (hotels only โ render as filled stars if you can) and review_score with review_count: "4.6 / 5 (686 reviews)".
For vacation rentals, surface bedrooms / bathrooms / sleeps inline if present (e.g. "2 BR ยท 2 BA ยท sleeps 6").
Price per night with the total alongside in smaller text, in the response currency.
For offers with a non-empty
sourcesarray, show "from โฌX on [cheapest source]" with a smaller "also on [other sources]" note when 2+ sources are present.Top 3-4 amenities pulled from the
amenitieslist.Short description if present (hotels only โ rentals leave this null and surface essential_info via the bedrooms/bathrooms/sleeps fields above).
A "Book on Google Hotels" button linking to
booking_url, opening in a new tab.
Do NOT render the images field as photo elements. Hotel image CDNs (Google's signed gps-cs-s URLs, hotelbeds, trvl-media, bstatic, giata) use hotlink protection that breaks these URLs outside their intended hosts; broken images degrade the card more than missing photos. The images field stays on the response model for future use (e.g., a server-side image proxy layer), but card rendering should be text-only. Compensate for the missing visual hierarchy by making the stay name larger and prominent at the top of each card.
If the response has a non-empty warnings array, surface them verbatim above the cards (e.g., "Note: vacation rental data was unavailable for this query; showing hotels only."). Do NOT silently swallow them.
Sort cards by the same sort_by the user requested. For a single result, prose is fine.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| rooms | No | ||
| adults | No | ||
| sort_by | No | BEST | |
| category | No | all | |
| children | No | ||
| currency | No | EUR | |
| location | Yes | ||
| min_rating | No | ||
| max_results | No | ||
| min_bedrooms | No | ||
| check_in_date | Yes | ||
| min_bathrooms | No | ||
| check_out_date | Yes | ||
| min_review_score | No | ||
| required_amenities | No | ||
| max_price_per_night | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||