ScreenshotNeo

BlogHow-to

How to Scrape Hotel Data from Booking.com

Learn the compliant way to collect Booking.com hotel data, avoid blocked or unlawful scraping, and build a reliable hotel-data pipeline.

By the ScreenshotNeo team1 October 20267 min read

Direct answer: Do not scrape or copy Booking.com pages with Selenium, Playwright, curl, or another automated tool unless Booking.com has given you prior express written permission. Booking.com’s customer terms prohibit automated access, monitoring, copying, downloading, crawling, and scraping, regardless of whether the purpose is commercial. The maintainable route for a real product is an approved Booking.com Demand API or Connectivity API integration, subject to eligibility, contracts, credentials, usage rules, and security requirements.

If you only need a visual image of a page for QA or documentation, capture it separately. A screenshot is not a substitute for permission to extract hotel prices, availability, room details, or reviews.

1. What Booking.com permits and why ordinary scraping fails

Booking.com states that automated systems may be blocked when they perform an unreasonable number of searches, gather prices or other information automatically, place undue load on the platform, or use automated assistants without express permission. A scraper can therefore fail even when a page is publicly viewable.

Typical failure modes include:

  • HTTP 403 or 429 responses after a small number of requests.
  • CAPTCHAs, bot checks, or challenge pages instead of hotel results.
  • Prices that change when dates, occupancy, currency, locale, or login state changes.
  • Incomplete results caused by lazy loading, pagination, experiments, or personalized ranking.
  • Terms, contract, privacy, and data-retention problems when records are redistributed.

Changing IP addresses, rotating user agents, solving CAPTCHAs, or reverse-engineering private endpoints does not create permission. Do not bypass controls while waiting for partner approval.

2. The compliant architecture

For an application that needs hotel inventory, availability, or prices, use an approved official interface or a third-party feed whose license explicitly covers your use case. Booking.com’s Demand API exposes accommodation inventory and identifier mappings. Connectivity integrations use machine-account credentials and onboarding through the Connectivity Portal. Data Portability uses OAuth, application registration, and explicit user authorization.

  1. Define the contract. List destinations, property IDs, check-in and check-out dates, occupancy, room and rate fields, currency, taxes, cancellation terms, review fields, and refresh frequency.
  2. Apply for access. Confirm which Booking.com partner API fits your product, then complete registration, contract review, onboarding, and credential issuance.
  3. Authenticate as documented. Store machine-account credentials or OAuth tokens in a secret manager. Never commit them to source control.
  4. Query narrowly. Request only the properties, dates, occupancies, and fields your product needs. Follow documented rate limits.
  5. Normalize records. Keep stable IDs for property, room, rate plan, occupancy, and stay dates. Preserve raw responses separately so schema changes can be audited.
  6. Record provenance. Store retrieval time, endpoint, geography, currency, occupancy, and the permission or contract governing each field.
  7. Handle lifecycle updates. Build refresh and deletion jobs. Closed-property data must be removed from your websites, apps, and databases according to the applicable usage rules.
  8. Protect sensitive data. Do not collect guest credentials or payment details unless the approved booking flow and security controls support it. Booking flows that handle payment details require PCI DSS compliance.
  9. Control redistribution. Do not forward data to another company unless your agreement permits it.

3. Define a useful hotel-data schema

Hotel prices are observations tied to a search context, not permanent hotel attributes. A normalized record should retain the inputs that produced the result.

Field group Examples Why it matters
Property property_id, name, address, latitude, longitude Stable joins and deduplication
Stay check_in, check_out, nights, occupancy Prices and availability depend on dates and guests
Rate room_id, rate_plan_id, meal_plan, cancellation Two prices may have different conditions
Money amount, currency, taxes, fees Prevents misleading comparisons
Freshness observed_at, source_endpoint, request_id Shows when a price was valid
Lifecycle status, last_seen_at, closed_at Supports removals and stale-record cleanup

4. Python: a safe integration template

The following example is a client skeleton for an approved API. Replace the placeholder URL and field names with the endpoint and schema supplied under your contract. It does not scrape Booking.com HTML or bypass access controls.

import json
import os
from datetime import date

import requests

API_URL = os.environ["BOOKING_API_URL"]
API_TOKEN = os.environ["BOOKING_API_TOKEN"]

query = {
    "destination": "PAR",
    "check_in": "2027-05-10",
    "check_out": "2027-05-13",
    "adults": 2,
    "rooms": 1,
    "currency": "EUR",
}

response = requests.get(
    API_URL,
    params=query,
    headers={"Authorization": f"Bearer {API_TOKEN}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()

record = {
    "observed_at": date.today().isoformat(),
    "query": query,
    "raw": data,
}

with open("booking-response.json", "w", encoding="utf-8") as file:
    json.dump(record, file, ensure_ascii=False, indent=2)

print("Saved approved API response")

Use the authentication method, request body, pagination rules, and rate limits in your partner documentation. Do not guess private endpoint names from browser network traffic.

5. cURL: inspect an approved endpoint

curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $BOOKING_API_TOKEN" \
  --get "$BOOKING_API_URL" \
  --data-urlencode "destination=PAR" \
  --data-urlencode "check_in=2027-05-10" \
  --data-urlencode "check_out=2027-05-13" \
  --data-urlencode "adults=2" \
  --data-urlencode "rooms=1" \
  --data-urlencode "currency=EUR"

6. Node.js: retry carefully and preserve provenance

const apiUrl = process.env.BOOKING_API_URL;
const token = process.env.BOOKING_API_TOKEN;

const params = new URLSearchParams({
  destination: 'PAR',
  check_in: '2027-05-10',
  check_out: '2027-05-13',
  adults: '2',
  rooms: '1',
  currency: 'EUR'
});

const response = await fetch(`${apiUrl}?${params}`, {
  headers: { Authorization: `Bearer ${token}` }
});

if (!response.ok) {
  const body = await response.text();
  throw new Error(`API ${response.status}: ${body}`);
}

const result = {
  observed_at: new Date().toISOString(),
  query: Object.fromEntries(params),
  raw: await response.json()
};

console.log(JSON.stringify(result, null, 2));

7. Pagination, caching, and refresh strategy

Pagination

Read every page using the API’s documented cursor or page token. Persist the token and request ID so a failed run can resume without duplicating records. Set a maximum page count and alert when the API returns an unexpectedly large result.

Caching

Cache stable metadata such as names and coordinates longer than volatile availability and price data. Cache keys must include destination, dates, occupancy, currency, filters, and any other input that changes the result. Never present a cached price without its observation timestamp.

Refresh and deletion

Use the change feeds or lifecycle signals supplied by your approved integration. Remove closed properties from every downstream copy, including search indexes and exports. Keep an audit log of when the deletion was received and completed.

8. Performance, reliability, and cost

  • Performance: Narrow queries reduce latency and quota use. Batch only where the API contract permits it; do not parallelize until you understand rate limits.
  • Reliability: Retry transient 429 and 5xx responses with exponential backoff and jitter. Do not retry authentication errors or validation failures blindly.
  • Idempotency: Use a deterministic key such as property, room, rate plan, dates, occupancy, and currency. Upsert records instead of appending duplicates.
  • Monitoring: Track status codes, latency, result counts, stale-record age, schema changes, and deletion backlog.
  • Cost: Compare partner fees, engineering time, storage, refresh frequency, and compliance work. A browser scraper can look cheap but carries blocking, maintenance, contractual, and data-quality costs.
  • Security: Rotate credentials, restrict access by service, redact tokens from logs, and encrypt stored responses when they contain sensitive information.

9. Common errors and fixes

Error Likely cause Fix
403 Forbidden Missing permission, invalid account, or blocked automation Verify partner access and credentials. Do not rotate IPs or bypass controls.
401 Unauthorized Expired or malformed token Refresh or rotate the credential using the documented flow.
429 Too Many Requests Rate limit exceeded Honor retry headers, reduce concurrency, and cache repeated queries.
Empty results Invalid dates, occupancy, destination ID, or no inventory Validate inputs and distinguish no availability from an API failure.
Prices differ between runs Dates, occupancy, taxes, currency, or freshness changed Persist the complete search context and observation timestamp.
Missing properties Pagination or filters were incomplete Follow cursors until completion and log page counts and totals.
Schema parse failure Provider changed a field or returned an error object Validate content type, preserve the raw response, and alert on schema drift.
Closed hotel remains visible Deletion job did not reach a downstream store Process lifecycle feeds and run reconciliation jobs.

10. When a screenshot is the actual requirement

If your goal is visual regression testing, documentation, or a record of what a page looked like, use a screenshot workflow rather than extracting hotel data. A screenshot still does not grant permission to copy Booking.com content into a database.

11. Or skip the browser setup

For permitted visual capture work, ScreenshotNeo returns a clean PNG, JPEG, WebP, or PDF from one GET request. See the ScreenshotNeo API documentation for all options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://www.booking.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://www.booking.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://www.booking.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie banners, newsletter popups, and chat widgets are removed before the shot.
  • Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed; response headers identify the page verdict and billing status.
  • An MCP server lets Claude, Cursor, and other MCP clients call take_screenshot, get_page_info, and capture_pdf.
  • The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots.

Create a free ScreenshotNeo account to start with 1,000 screenshots per month and no card.

12. FAQ

Public visibility does not equal permission. Booking.com’s current customer terms prohibit automated copying and scraping without prior express written permission, including for non-commercial purposes.

Can I use Selenium or Playwright with a proxy?

Those tools and a proxy do not change the contractual rules. Use browser automation only for an expressly permitted purpose and within written limits.

Is there an official Booking.com hotel API?

Approved partners can use Booking.com Demand API or Connectivity API interfaces, subject to contracts, onboarding, credentials, and applicable usage requirements.

Can I store prices indefinitely?

Retention and redistribution depend on your agreement. Treat prices as time-bound observations, follow lifecycle rules, and remove data when required.

Do I need PCI DSS?

Booking flows that collect payment details require PCI DSS compliance. A read-only availability integration may have different obligations, which your contract and security review should confirm.

What should I do while partner approval is pending?

Build against fixtures or a licensed feed, define your normalized schema, and implement rate limiting, provenance, deletion, and monitoring. Do not reverse-engineer private endpoints or bypass bot controls.