search_hotels
Find hotels with price predictions, ratings, amenities, and buy/wait recommendations for your travel dates and destination.
Instructions
Search for hotels on Hopper with price predictions. Returns hotel options with ratings, amenities, and Hopper's buy/wait recommendation.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| destination | Yes | City name or destination (e.g. Paris, New York, Tokyo) | |
| check_in | Yes | Check-in date in YYYY-MM-DD format | |
| check_out | Yes | Check-out date in YYYY-MM-DD format | |
| guests | No | Number of guests (default: 2) | |
| rooms | No | Number of rooms (default: 1) | |
| min_price | No | Minimum price per night in USD | |
| max_price | No | Maximum price per night in USD |
Implementation Reference
- src/index.ts:187-237 (handler)The searchHotels function implements the tool logic, navigating to Hopper's hotel search page, waiting for the results, and scraping hotel data.
async function searchHotels(params: HotelSearchParams): Promise<string> { const page = await session.newPage(); try { const url = `https://www.hopper.com/hotels/${encodeURIComponent(params.destination)}` + `?checkin=${params.check_in}&checkout=${params.check_out}` + `&guests=${params.guests ?? 2}&rooms=${params.rooms ?? 1}`; await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30000 }); await page.waitForTimeout(3000); const hotels = await page.evaluate(() => { const results: Array<{ id: string; name: string; rating: number; stars: number; price_per_night: number; total_price: number; currency: string; address: string; amenities: string[]; prediction: string; }> = []; const cards = document.querySelectorAll("[data-testid*='hotel'], .hotel-card, [class*='HotelResult']"); cards.forEach((card, i) => { const text = card.textContent ?? ""; const priceMatch = text.match(/\$(\d[\d,]*)/); const starsMatch = text.match(/(\d)\s*star/i); const ratingMatch = text.match(/(\d+\.?\d*)\s*\/\s*10|(\d+\.?\d*)\s*out/); results.push({ id: `hotel_${i + 1}`, name: card.querySelector("h2, h3, [class*='name'], [class*='title']")?.textContent?.trim() ?? `Hotel ${i + 1}`, rating: ratingMatch ? parseFloat(ratingMatch[1] ?? ratingMatch[2]) : 8.0, stars: starsMatch ? parseInt(starsMatch[1]) : 3, price_per_night: priceMatch ? parseInt(priceMatch[1].replace(",", "")) : 0, total_price: 0, currency: "USD", address: card.querySelector("[class*='address'], [class*='location']")?.textContent?.trim() ?? "", amenities: [], prediction: text.match(/book now|wait|prices rising/i)?.[0]?.toLowerCase() ?? "watch", }); }); return results.slice(0, 10); }); const result = { search_params: params, hotels: hotels.length > 0 ? hotels : generateMockHotels(params), - src/index.ts:607-624 (registration)The tool registration for search_hotels, including its description and input schema.
{ name: "search_hotels", description: "Search for hotels on Hopper with price predictions. Returns hotel options with ratings, amenities, and Hopper's buy/wait recommendation.", inputSchema: { type: "object", properties: { destination: { type: "string", description: "City name or destination (e.g. Paris, New York, Tokyo)" }, check_in: { type: "string", description: "Check-in date in YYYY-MM-DD format" }, check_out: { type: "string", description: "Check-out date in YYYY-MM-DD format" }, guests: { type: "number", description: "Number of guests (default: 2)" }, rooms: { type: "number", description: "Number of rooms (default: 1)" }, min_price: { type: "number", description: "Minimum price per night in USD" }, max_price: { type: "number", description: "Maximum price per night in USD" }, }, required: ["destination", "check_in", "check_out"], }, },