OmniScrape
ProductsSolutionsGuidesDocs ↗PricingAbout
ProductsSolutionsGuidesDocs ↗PricingAbout
← All guides
Site-Specific Scrapers

Booking.com Scraper: Hotel Rates, Room Types, and Availability

Booking.com is the dominant OTA in Europe and a critical data source for travel metasearch, hotel revenue management, and rate parity monitoring. It also defends that data aggressively: nightly rates shift by guest nationality, device fingerprint, session history, and time of day. A datacenter IP from the wrong country can receive inflated prices, empty rate tables, or a silent block — all without an error status code.

This guide covers the URL structure for hotel detail and search pages, the DOM selectors that survive across Booking's periodic redesigns, Akamai bot management behavior, and how to structure scraping jobs for reliable rate intelligence. For broader travel pipeline architecture, see travel web scraping.

On this page

1. Data fields revenue and metasearch teams track2. Booking.com URL patterns and required parameters3. Rate table, room row, and review DOM selectors4. Akamai bot management and session-dependent pricing5. Scraping a hotel detail page with dates6. Search results for property discovery7. Handling Akamai bot management on Booking.com8. Rate parity monitoring across OTAs9. Legal and contractual considerations10. FAQ

1.Data fields revenue and metasearch teams track

Rate shopping is only meaningful when comparisons are apples-to-apples: same check-in and check-out dates, same occupancy, same currency, captured within the same UTC window. The following fields represent the minimum viable dataset for parity monitoring and competitive intelligence. Capture them together in a single scrape — reconstructing missing fields from a second request risks rate drift.

Beyond raw price, the cancellation policy and breakfast flag materially affect total cost of stay comparisons. A nominally cheaper room with non-refundable terms and no breakfast is not equivalent to a slightly higher rate with free cancellation and breakfast included. Store both the headline price and the policy attributes.

  • Hotel ID (data-hotel-id attribute or hotelId URL parameter)
  • Property name and star rating
  • Room type name and bed configuration (double, twin, king)
  • Nightly rate, taxes and fees breakdown, and total stay price
  • Currency code (differs by TLD and proxy geo)
  • Cancellation policy: free cancellation deadline or non-refundable flag
  • Breakfast included / excluded flag
  • Rooms remaining count (urgency signals like '2 rooms left')
  • Review score (0–10 scale) and total review count
  • Genius loyalty discount badge and mobile-only rate flags
  • Property type (hotel, apartment, hostel, guesthouse)
  • Availability status (sold out vs bookable)

2.Booking.com URL patterns and required parameters

Booking.com hotel detail pages follow a predictable pattern: /hotel/{country_code}/{property-slug}.{locale}.html. The locale segment (en-gb, en-us, de-de) affects language of returned content but not necessarily currency — currency is driven by the proxy IP's country and the TLD. Always include date and occupancy parameters in the request URL; without them, Booking returns a calendar prompt rather than a rate table.

The hotel ID is embedded in the page as a data-hotel-id attribute on the main container and also appears in the URL parameter hotelId on some redirect flows. Capture it during your first scrape of a property and use it as the stable key for your rate time series — property slugs occasionally change after rebranding, but hotel IDs do not.

Search result URLs use searchresults.html with a destination string in the ss parameter. These pages are significantly more protected than hotel detail pages and should be used only for initial property discovery, not for ongoing rate collection. Once you have a hotel's detail URL, scrape that directly.

  • Hotel detail: https://www.booking.com/hotel/us/the-standard-high-line.en-gb.html
  • With dates and occupancy: ...?checkin=2025-08-10&checkout=2025-08-12&group_adults=2&no_rooms=1
  • Search results: https://www.booking.com/searchresults.html?ss=Paris&checkin=2025-09-01&checkout=2025-09-03&group_adults=2
  • Country TLDs: booking.com (USD/GBP), booking.de (EUR) — currency varies by TLD and proxy geo
  • Hotel ID in DOM: data-hotel-id on main property container
  • Locale variants: .en-gb.html, .en-us.html, .de-de.html — affects content language
  • Currency override: &selected_currency=EUR (not always honored; proxy geo takes precedence)

3.Rate table, room row, and review DOM selectors

Booking.com's rate table renders inside a table.hprt-table element. Each room type occupies a tr[data-block-id] row or, in the newer React-based layout, a div with a data-testid attribute. The room type name appears in td.hprt-table-cell-roomtype, and the price in span.prco-valign-middle-helper or div.bui-price-display__value depending on which A/B variant the session receives. Capture both selectors and fall back gracefully.

Rates are JavaScript-rendered — the rate table is populated after the page loads and date parameters are processed client-side. A request without checkin/checkout in the URL will receive a page with an empty rate section and a date picker prompt. Always embed dates in the URL rather than relying on JavaScript interaction to set them.

The review score badge is in div.bui-review-score__badge (the numeric score) and div.bui-review-score__text (the count and label). Property description text sits in div#property_description_content. Amenity lists use ul.hp-desc-highlighted-amenities for the headline features and a separate expandable section for the full list.

For the newer Booking.com layout (progressively rolling out), data-testid attributes are more stable than class names. Key testids: data-testid='title' for hotel name in search results, data-testid='price-and-discounted-price' for the price chip, data-testid='review-score' for the score container, and data-testid='title-link' for the anchor to the hotel detail page.

4.Akamai bot management and session-dependent pricing

Booking.com deploys Akamai Bot Manager across its entire domain. Datacenter IP ranges are fingerprinted and either challenged with an interstitial, served a CAPTCHA, or silently shown incorrect rates — the silent rate manipulation is the hardest failure mode to detect because the response returns HTTP 200 with plausible-looking but wrong prices.

Pricing on Booking.com is personalized along several dimensions simultaneously: the geographic origin of the request IP, the browser fingerprint and device type, the session's cookie history (repeat visits to a property page can trigger urgency pricing), and the guest's Genius loyalty tier if the session carries a logged-in cookie. For rate intelligence work, you need to control all of these variables and record them alongside every price observation.

Search result pages (searchresults.html) trigger Akamai challenges at much lower request rates than hotel detail pages. Use search only for property discovery — scrape a destination once to build a list of hotel detail URLs, then run all ongoing rate collection against those detail URLs directly.

  • Akamai Bot Manager: interstitial challenge, CAPTCHA, or silent rate distortion on datacenter IPs
  • Geo-personalized pricing: proxy country must match the guest nationality you are simulating
  • Session cookie binding: rate quotes are tied to session state; use session_id for multi-step flows
  • CAPTCHA escalation on searchresults.html pagination beyond page 2–3
  • Mobile vs desktop rate differences: some properties show lower rates to mobile user agents
  • Genius discount rates: only visible to sessions carrying a logged-in Genius account cookie
  • Silent block detection: compare returned prices against a known baseline to detect distortion

5.Scraping a hotel detail page with dates

Use mode js_rendering because the rate table is populated by JavaScript after page load. Set js_wait_selector to table.hprt-table so the request waits until the rate grid is present in the DOM before extracting. A residential proxy matching the guest nationality you are simulating is essential — use proxy residential:us for US-origin pricing, residential:gb for UK, and so on.

The css_selectors map extracts the core fields in a single request. The prices selector targets the per-night price chip; cancellation targets the policy cell in the rate table. If a room is sold out, the cancellation cell will be absent and prices will return an empty array for that row — handle this in your parser.

Store the proxy country, scrape timestamp (UTC), and the full URL including date parameters alongside every price record. Without these, rate time series are not comparable across runs.

Booking.com hotel detail — js_rendering with CSS extraction
json
1234567891011121314151617181920{
  "url": "https://www.booking.com/hotel/us/the-standard-high-line.en-gb.html?checkin=2025-08-10&checkout=2025-08-12&group_adults=2&no_rooms=1&selected_currency=USD",
  "mode": "js_rendering",
  "output_format": "css_extractor",
  "proxy": "residential:us",
  "js_wait_selector": "table.hprt-table",
  "js_wait_timeout": 15000,
  "css_selectors": {
    "hotel_name": "h2.pp-header__title",
    "hotel_id": "[data-hotel-id]",
    "review_score": "div.bui-review-score__badge",
    "review_count": "div.bui-review-score__text",
    "address": "span.hp_address_subtitle",
    "room_types": "td.hprt-table-cell-roomtype",
    "prices": "span.prco-valign-middle-helper",
    "cancellation_policies": "td.hprt-table-cell-conditions",
    "breakfast_flags": "td.hprt-table-cell-meal",
    "rooms_remaining": "td.hprt-table-cell-rooms-left"
  }
}

6.Search results for property discovery

Search result pages carry higher Akamai friction than hotel detail pages. Use them only for the initial discovery pass — scrape a destination once to collect hotel names, IDs, and detail URLs, then switch all ongoing rate collection to individual hotel detail pages. Avoid paginating search results beyond the first two pages in a single session.

The data-testid selectors below target Booking's newer React layout, which is more stable across redesigns than the legacy class-based selectors. The links selector returns relative paths — prepend https://www.booking.com to construct full hotel detail URLs.

Use a residential proxy matching the destination country to get locally relevant results and avoid geo-mismatch challenges. For Amsterdam searches, residential:nl returns results in EUR with locally accurate availability.

Booking.com search results — property discovery
json
1234567891011121314{
  "url": "https://www.booking.com/searchresults.html?ss=Amsterdam&checkin=2025-09-01&checkout=2025-09-03&group_adults=2&no_rooms=1&order=price",
  "mode": "auto",
  "output_format": "css_extractor",
  "enable_solver": true,
  "proxy": "residential:nl",
  "css_selectors": {
    "hotel_names": "div[data-testid='title']",
    "prices": "span[data-testid='price-and-discounted-price']",
    "review_scores": "div[data-testid='review-score'] div",
    "hotel_links": "a[data-testid='title-link']",
    "property_types": "span[data-testid='recommended-units']"
  }
}

7.Handling Akamai bot management on Booking.com

Akamai Bot Manager on Booking.com operates in several modes depending on the request path and traffic pattern. Hotel detail pages with a residential proxy and mode auto typically resolve without a visible challenge — Akamai's sensor data collection runs client-side and the OmniScrape Web Unlocker handles the resulting cookie and header requirements. Search result pages and pagination are more aggressive and benefit from enable_solver: true to resolve interstitials.

The most common failure mode is not an HTTP error but a silently degraded response: the rate table renders but shows prices that are 20–40% higher than real rates, or shows only the most expensive room categories. Detect this by maintaining a baseline of known prices for a set of sentinel properties and alerting when scraped values deviate significantly from the baseline.

If the rate table selector (table.hprt-table) is not found after js_wait_timeout, the session likely received a CAPTCHA or a date-prompt page. Check body.data.content for the string 'robot' or 'verify' to distinguish a bot challenge from a legitimate empty-availability response. For detailed Akamai challenge patterns and header strategies, see Akamai bypass.

Rotate session_id between hotel detail requests rather than reusing a single session across many properties. A session that visits dozens of hotel pages in sequence accumulates behavioral signals that Akamai scores as bot-like. Fresh sessions per property — or per small batch — keep the fingerprint clean.

8.Rate parity monitoring across OTAs

Rate parity monitoring compares a hotel's Booking.com rate against the same property's rate on Expedia, Hotels.com, and the hotel's own direct booking site — for identical dates, occupancy, and room type, captured within the same UTC minute. Even a two-minute gap between OTA scrapes can introduce rate drift from dynamic pricing updates.

Structure your parity pipeline around a canonical room type identifier. Booking.com room type names are free text and vary by property; normalize them to a canonical category (standard double, deluxe king, suite) using fuzzy matching or a lookup table maintained per property. Without normalization, you will compare a 'Superior Room with Garden View' on Booking against a 'Deluxe Room' on Expedia and produce meaningless parity alerts.

Store the proxy country and currency code with every rate record. A rate captured via residential:us in USD is not directly comparable to one captured via residential:gb in GBP — convert to a common currency at the exchange rate at scrape time, not at analysis time. For alerting infrastructure and storage patterns, see price monitoring web scraping.

Parity violations fall into two categories: the hotel is selling cheaper on Booking than on its own site (a terms violation in most OTA contracts), or a third-party reseller is undercutting the hotel's own Booking rate. The second case requires scraping not just Booking's standard search but also Booking's 'Deals' and 'Genius' rate surfaces, which require authenticated sessions.

9.Legal and contractual considerations

Booking.com's terms of service explicitly prohibit unauthorized automated access and the commercial redistribution of scraped rate data. Building a public rate API that republishes Booking prices is high legal and contractual risk. Metasearch operators and OTA aggregators that display Booking rates commercially do so under content partnership agreements, not through scraping.

Internal revenue management use cases — a hotel monitoring its own rates and competitors on the platform it sells through — occupy a different risk profile. The data subject is your own property's pricing, and the use is operational rather than redistributive. That said, Booking.com does not formally carve out this use case in its terms, so the legal exposure is not zero.

Academic research and journalism involving Booking.com pricing have proceeded under fair use arguments in some jurisdictions. The EU's Digital Markets Act and related regulations are creating ongoing legal uncertainty around OTA data access rights. Consult qualified legal counsel before building any commercial system that depends on Booking.com scraped data.

Frequently asked questions

Why do Booking.com rates change between scrapes of the same hotel?

Booking.com uses dynamic pricing that responds to demand signals in near real time. Beyond genuine demand changes, rates are personalized by the geographic origin of the request IP, the session's cookie history, the device type inferred from the user agent, and whether the session carries a Genius loyalty cookie. To get comparable rates across scrapes, fix all of these variables: use the same proxy country, the same user agent category, fresh sessions without loyalty cookies, and scrape at consistent UTC times. Even then, expect 1–3% variance from demand-driven updates.

Does Booking.com use Cloudflare?

No. Booking.com uses Akamai Bot Manager, not Cloudflare. The challenge mechanisms, sensor scripts, and cookie patterns are different. Use the patterns described in Akamai bypass — specifically residential proxies and mode auto with enable_solver: true for search pages. Cloudflare bypass techniques do not apply here.

Can I scrape Booking.com rates without including dates in the URL?

You can retrieve property metadata — hotel name, address, star rating, review score, amenities, and property description — without date parameters. However, the rate table will not render; Booking shows a date picker prompt instead of room prices. For any rate intelligence use case, always include checkin, checkout, group_adults, and no_rooms in the URL. Use js_rendering with js_wait_selector on the rate table element to ensure prices have loaded before extraction.

What is the best mode for Booking.com hotel detail pages?

Use mode js_rendering with a residential proxy. The rate table is JavaScript-rendered and will not be present in a fast HTTP response. Set js_wait_selector to 'table.hprt-table' and js_wait_timeout to at least 12000 milliseconds to give the page time to load and populate rates. For search result pages, mode auto with enable_solver: true is sufficient for the first page; deeper pagination may require js_rendering.

How do I detect when Booking.com has silently served wrong rates?

Silent rate distortion is the hardest failure mode — the response is HTTP 200 and the DOM looks correct, but prices are inflated or only expensive room categories are shown. Maintain a set of 10–20 sentinel properties with known baseline rates scraped from verified sessions. After each scrape run, compare results for sentinel properties against the baseline. A deviation of more than 15–20% across multiple sentinels indicates silent distortion rather than genuine demand change. Also check body.data.content for strings like 'robot', 'verify you are human', or 'access denied' to catch interstitial pages that rendered partial content.

How should I handle the Booking.com rate table when a room type is sold out?

When a room type is sold out, the price and cancellation cells in the rate table row are replaced with a 'Sold out' label or are absent entirely. Your CSS extractor will return empty arrays or shorter arrays than expected for those selectors. Parse the room_types and prices arrays in parallel by index — if prices[i] is empty or missing, mark that room type as unavailable rather than throwing a parse error. Some sold-out rows retain the room type name and bed configuration, which is still useful for tracking which room categories a property offers.

Is it possible to scrape Genius discount rates without a logged-in account?

Genius rates are only visible to sessions authenticated with a Booking.com account that has reached Genius tier. An unauthenticated session will see the standard public rate. If your rate parity monitoring needs to capture Genius rates — relevant because some hotels price Genius rates below their direct site rate, which is a parity violation — you need to pass a valid authenticated session cookie in custom_headers. Managing authenticated sessions at scale involves additional operational complexity and higher terms-of-service risk.

Related guides

  • Travel Web Scraping: Hotel Rates, Flight Fares & Parity Monitoring
  • How to Bypass Akamai Bot Manager When Web Scraping
  • Price Monitoring with Web Scraping: A Practical Developer Guide
  • Web Scraping with Python

Ready to scrape without blocks?

Get your API key in minutes. Test protected URLs from the dashboard — no credit card required to start.

Ready to get started?

Start scraping protected sites today — no credit card required.

OmniScrape

Web scraping infrastructure for developers. One API call to bypass any protection.

All systems operational

Product

  • Web Unlocker
  • Browser-as-a-Service
  • Residential Proxies
  • Pricing

Developers

  • API Reference ↗
  • Quickstart ↗
  • All Guides
  • Use Cases
  • Status

Company

  • About
  • Contact

Legal

  • Privacy Policy
  • Terms of Service
  • Refund Policy
  • Cookie Policy
  • Acceptable Use

Solutions

  • E-commerce Web Scraping: Catalog Intelligence at Production Scale
  • Real Estate Web Scraping: Listings, Comps, and Market Data
  • SERP Web Scraping: Agency Rank Tracking Workflow
  • Job Board Web Scraping: HR Tech Pipeline for Labor Market Intelligence
  • Price Monitoring with Web Scraping: A Practical Developer Guide
  • Lead Generation Web Scraping: Compliant Inbound Enrichment for Sales Teams
  • Market Research Web Scraping: Multi-Geo Data Collection for Research Firms
  • Sentiment Analysis Web Scraping: Build a Production Review Pipeline
  • Logistics Web Scraping: Carrier Rates, Port ETAs, and Sailing Schedules
  • Social Media Web Scraping: Brand Mention Monitoring from Public Pages
  • LLM Training Data Scraping: Building Clean Web Corpora
  • Travel Web Scraping: Hotel Rates, Flight Fares & Parity Monitoring

Web Scraping by Language

  • Web Scraping with Python
  • Web Scraping with Node.js: fetch, Cheerio, and the OmniScrape API
  • Web Scraping with Java: HttpClient, Jsoup, and OmniScrape API
  • Web Scraping with PHP
  • Web Scraping with Go (Golang)
  • Web Scraping with Ruby: Faraday, Nokogiri, Sidekiq & OmniScrape
  • Web Scraping with C#: HttpClient, AngleSharp, and OmniScrape API
  • Web Scraping with Rust
  • Web Scraping with R: httr2, rvest, and the OmniScrape API
  • Web Scraping with C++
  • Web Scraping with Elixir
  • Web Scraping with Perl: Mojo::UserAgent, Mojo::DOM, and OmniScrape

Anti-Bot Bypass

  • How to Bypass Cloudflare When Web Scraping
  • How to Bypass DataDome When Web Scraping
  • How to Bypass Akamai Bot Manager When Web Scraping
  • How to Bypass PerimeterX (HUMAN Security) When Web Scraping
  • Bypassing AWS WAF When Web Scraping: Rate Rules, Bot Control, and Residential Proxies
  • How to Bypass Imperva (Incapsula) When Web Scraping
  • How to Bypass Kasada Bot Protection When Web Scraping
  • How to Bypass F5 BIG-IP Bot Defense When Web Scraping
  • How to Bypass Distil Networks When Web Scraping
  • How to Bypass reCAPTCHA When Web Scraping

Scraping Tools

  • Playwright Web Scraping: Practical Patterns for Protected Sites
  • Puppeteer Web Scraping: Patterns, Anti-Bot Limits, and BaaS Integration
  • Selenium Web Scraping: Practical Patterns for Real-World Projects
  • Scrapy Web Scraping with OmniScrape: Download Middleware, Pipelines, and Scale
  • Beautiful Soup Web Scraping: A Practical Guide
  • cURL Web Scraping: Shell-Native Patterns with OmniScrape
  • HTTPX Web Scraping: Async Python with OmniScrape
  • Cheerio Web Scraping: A Practical Guide

Site-Specific Scrapers

  • Amazon Scraper: Product Data, Buy Box, Reviews, and Multi-Marketplace
  • Google Search Scraper: Extract SERP Rankings and Features
  • Google Maps Scraper: Extract Business Listings and Place Data
  • LinkedIn Scraper: Companies, Jobs, and Public Profiles
  • Walmart Scraper: Prices, Stock, Rollback Deals, and Fulfillment Data
  • eBay Scraper: Extract Listings, Auctions, and Sold Prices
  • Shopify Scraper: Products, Variants, and JSON Endpoints
  • Indeed Scraper: Extract Job Listings, Salaries, and Company Data
  • Zillow Scraper: Extract Listings, Zestimates, and Price History
  • Reddit Scraper: Posts, Comments, and Subreddit Data
  • X (Twitter) Scraper: Tweets, Profiles, and Hashtags
  • Instagram Scraper: Posts, Reels, and Profile Metrics
  • TikTok Scraper: Extract Videos, Hashtags, and Trend Data
  • YouTube Scraper: Extract Video Metadata, Comments, and Channel Stats
  • Booking.com Scraper: Hotel Rates, Room Types, and Availability
  • Airbnb Scraper: Listings, Calendars, and Nightly Rates
  • Crunchbase Scraper: Extract Funding Rounds, Companies, and Investors
  • Yelp Scraper: Extract Business Listings, Ratings, and Reviews
  • Glassdoor Scraper: Employer Ratings, Salaries, and Review Data
  • Trustpilot Scraper: TrustScore, Star Distribution, and Review Monitoring

How We Compare

  • OmniScrape vs ScrapingBee
  • OmniScrape vs ZenRows
  • OmniScrape vs ScraperAPI: A Practical Developer Comparison
  • OmniScrape vs Bright Data: Which Web Scraping Platform Fits Your Team?
  • OmniScrape vs Oxylabs
  • OmniScrape vs Smartproxy
  • OmniScrape vs Crawlbase: API Design, Observability, and Migration Guide
  • OmniScrape vs Apify

Web Scraping Guides

  • Web Scraping Without Getting Blocked
  • Web Scraping Proxy Guide: Types, Sessions, Geo, and OmniScrape Integration
  • Solve CAPTCHAs While Web Scraping
  • Web Scraping vs Web Crawling: Architecture, Patterns, and When to Use Each
  • Headless Browser Scraping: When to Use It and How to Do It Right
  • Web Scraping API: Endpoint, Modes, Output Formats & Integration Patterns
  • Rotating Proxies for Web Scraping: Policies, Session Binding, and Geo Pools
  • Scrape JavaScript-Rendered Pages: SPAs, Hydration, and Hidden APIs

© 2026 OmniScrape. All rights reserved.

PrivacyTermsRefundsAcceptable Use