Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do not scrape Booking.com unless you have its prior express written permission. Booking.com’s terms prohibit automated access—including scraping, crawling, copying, and downloading—whether or not it is for commercial use. For a production integration, use an authorized Booking.com API or partner arrangement. If you have written authorization to automate a browser, Playwright can extract fields from a rendered page; the example below demonstrates that technique on a local fixture, not on Booking.com.

First decide whether you are allowed to access the data

Browser automation explains how JavaScript can read a page; it does not grant permission to collect that page’s content. Booking.com’s Terms, section A15.2, prohibit using robots, spiders, scrapers, other automated means, or automated assistants to access, monitor, copy, scrape, crawl, download, reproduce, or otherwise use platform content without prior express written permission. The restriction applies regardless of commercial purpose. Booking.com also says it monitors unreasonable searches and activity that gathers prices or stresses the platform.

Accordingly, do not run the sample against Booking.com, and do not use automation to get around a CAPTCHA, bot check, rate limit, access control, or other safeguard. Stop if you encounter an access-denied or challenge page. A tutorial about selectors is not authorization. Use the local fixture below, a site you own, a test environment whose owner has authorized you, or a Booking.com integration for which you have written permission.

For a production integration, start with the Booking.com developer program and confirm that the API or partner route covers your account, market, intended fields, and use. The official developer portal lists Demand, Connectivity, Metasearch Connect, and Data Portability APIs. Requirements vary by flow and can include registration, contracts, certification, security checks, or a self-assessment. For booking access, the legacy commercial API documentation says appropriate contracts and PCI DSS compliance are required. Do not assume a route is available to every developer or in every geography.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the right route for the job

Route When it fits Important constraints
Authorized Booking.com API or partner integration Production use of Booking.com data or booking flows Eligibility and requirements depend on the API and flow; confirm contracts, certification, security, and data-use rules with Booking.com.
Playwright against an authorized browser target A permitted page-rendering workflow, prototype, or site you control Selectors and page structure can change. Written permission still governs Booking.com access.
Screenshot API Capturing a visual image or PDF of a permitted page A screenshot is not structured hotel data, does not authorize access, and does not bypass a challenge.

Playwright is a practical choice for authorized browser extraction because its locator model provides auto-waiting and retryability, and its migration guidance recommends locators and web-first assertions. The documentation also describes cross-browser support. Do not mistake browser support for access permission or a guarantee that a third-party page will keep the same markup.

Set up Playwright for an authorized target

Install Node.js and create a small project. These commands install Playwright and its Chromium browser:

mkdir hotel-extractor
cd hotel-extractor
npm init -y
npm install playwright
npx playwright install chromium

Save the following as extract.mjs. It builds a fixture entirely in memory, then extracts hotel-like fields from that fixture. This makes the example runnable without contacting Booking.com or another website. The example uses semantic locators and explicit readiness checks rather than relying on a timeout.

import { chromium } from 'playwright';

const html = `
  <main aria-label="Hotel results">
    <article>
      <h2>Harbor House</h2>
      <p>Review score 8.7</p>
      <p>Review count 1,245</p>
      <p>Displayed price $180</p>
      <p>Free cancellation</p>
      <a href="/hotels/harbor-house">View property</a>
    </article>
  </main>`;

const browser = await chromium.launch({ headless: true });
try {
  const context = await browser.newContext({
    locale: 'en-US',
    timezoneId: 'UTC',
    viewport: { width: 1365, height: 900 }
  });
  const page = await context.newPage();
  await page.setContent(html);

  const cards = page.getByRole('article');
  await cards.first().waitFor({ state: 'visible' });

  const rows = [];
  for (const card of await cards.all()) {
    rows.push({
      name: (await card.getByRole('heading').innerText()).trim(),
      scoreText: (await card.getByText(/Review score/i).innerText()).trim(),
      reviewCountText: (await card.getByText(/Review count/i).innerText()).trim(),
      displayedPriceText: (await card.getByText(/Displayed price/i).innerText()).trim(),
      cancellationText: (await card.getByText(/cancellation/i).innerText()).trim(),
      detailPath: await card.getByRole('link').getAttribute('href')
    });
  }

  console.log(JSON.stringify(rows, null, 2));
  await context.close();
} finally {
  await browser.close();
}

Run it with node extract.mjs. It should print one record for Harbor House. The fixture’s labels and values are deliberately simple; they are not claims about Booking.com’s current page or DOM. For a permitted live target, replace the fixture with navigation to that target and adapt each locator to its documented or observed page contract.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Wait for the data, not an arbitrary delay

Pages often render an initial shell before their content appears. A completed navigation therefore does not prove that names, ratings, prices, or facilities are ready. In the sample, waitFor({ state: 'visible' }) waits for the first card. On a dynamic list, wait for a representative field or assert that the expected list count or text is present before iterating.

Playwright’s locator.all() returns the elements currently matched; it does not wait for a dynamic list to finish filling. Its locator API supports attached, detached, visible, and hidden states. Prefer a web-first assertion or a locator wait tied to the information you need. The load, domcontentloaded, and networkidle page states describe navigation or network activity, not the semantic readiness of a particular hotel card. Playwright labels networkidle discouraged for testing; assert the UI state you need instead of treating a generic load state as proof.

Prefer getByRole, getByText, getByLabel, getByPlaceholder, getByAltText, or getByTestId when the target exposes a stable user-facing contract. Long CSS or XPath chains based on nesting order are brittle: a page redesign can change the chain while the visible information remains the same. If you control the page, add test IDs or accessible names specifically for the data contract you need.

Extract and normalize fields without losing meaning

Define the output schema before writing selectors. A hotel result may need a property name, destination, review score, review count, displayed price and currency, room label, cancellation text, and detail URL. Collect only fields your permission and use case allow. Do not collect guest payment details or personally identifying information unless the contract and applicable privacy basis permit it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Keep score and count separate. A score such as 8.7 is not a review count such as 1,245.
  • Preserve raw text. Store the displayed string alongside any normalized numeric value so you can investigate parsing errors.
  • Parse by locale and currency. Decimal and thousands separators vary. Do not strip punctuation or infer a currency from a symbol alone when the page context does not establish it.
  • Represent missing values as missing. A missing displayed price is not zero and should not become a fabricated estimate.
  • Retain provenance. Record the source URL, UTC retrieval time, locale, selector version, and parser version with each record.
  • Deduplicate cautiously. Use a stable property identifier or canonical URL when one is available; a display name alone may not uniquely identify a property.

Displayed prices can depend on dates, occupancy, currency, market, and selected room conditions. Preserve those parameters and context when they are part of the authorized workflow; do not present a displayed price as a universal or current price beyond the captured result.

Follow Booking.com API data-use rules

Access through an API is not permission to reuse data without limits. Booking.com’s legacy permitted-use guidance says data forwarding or forward distribution is forbidden. It says availability and prices must not be cached because they change rapidly, while static hotel content has separate caching guidance. It also says affiliates doing price comparison may not reuse Booking.com property descriptions, photos, facilities, or policies, and must use their own content. Check the rules attached to your actual agreement and API before storing, displaying, or redistributing any field.

The Data Portability API has a different authorization flow: its documentation requires an OAuth token, user authorization, and a registered application with client credentials. The legacy commercial API documentation also describes a hotel_url field for linking users to Booking.com. These details are not interchangeable; select the documented API that matches the job rather than treating all API access as a general-purpose scrape feed.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Keep browser automation reliable and respectful

  • Set an explicit context. Use a fixed locale, timezone, and viewport so formatting and rendering are reproducible. Record those settings with the result.
  • Protect credentials. Keep API keys and account secrets in environment variables or a secrets manager, not in source code, logs, or a repository.
  • Use a bounded request budget. Work within written permission and the applicable contractual limits. Stop on denial or challenge pages; do not add stealth plugins or CAPTCHA bypass logic.
  • Back off on errors. Avoid tight retry loops. For an authorized integration, honor the provider’s limits and retry guidance; stop rather than repeatedly stressing a failing target.
  • Keep the capture narrow. Fetch only the pages and fields necessary for the approved use. This lowers operational load and reduces the privacy and data-security burden.

Browser automation has more moving parts than a schema-based API: browser installation, rendering time, selectors, and layout changes all need maintenance. An official API may provide a more appropriate production contract, but access, field coverage, quotas, and certification depend on the particular program. The available documentation does not establish universal eligibility, a universal quota, or a single field set for every Booking.com API.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshoot common extraction failures

Symptom Likely cause Safe response
No cards are found The selector does not match the authorized page, or the results have not rendered. Inspect the permitted target’s accessible structure, choose a stable locator, and wait for the intended card or field. Do not guess selectors from a different page version.
The list is empty or incomplete The code enumerated a dynamic list before it finished populating. Wait for a specific card or assert the expected count/text before calling locator.all().
A field lookup times out The field is absent, hidden, labeled differently, or not permitted/available in this result. Check the page state and the target’s authorized schema; handle optional fields as missing instead of substituting a value.
Price parsing is wrong The displayed locale or currency differs from the parser’s assumptions. Retain raw text and parse with an explicit locale and currency context; validate decimal and grouping separators.
Navigation shows an access-denied or challenge page The target rejected or challenged the request. Stop. Do not attempt to bypass the safeguard. Use an authorized API or contact the provider about permitted access.
The API integration cannot go live The selected route may require registration, contracts, security review, certification, or a self-assessment. Check the requirements for that exact API and flow with Booking.com before building around it.

Or skip the browser setup

For a permitted target, ScreenshotNeo can return a screenshot or PDF with one GET request; it is a visual capture service, not a structured hotel-data extractor, and it does not grant permission to access Booking.com. Use it only for a page you are authorized to capture. Its clean-shot options can accept consent banners and remove known consent platforms, newsletter popups, and chat widgets before capture; these are cleanup options, not a way to defeat access controls or challenges. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses include X-Page-Verdict and X-Billed headers. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents and MCP clients. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.

cURL example, using a permitted test page; see the ScreenshotNeo API documentation for parameters and response details:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

ScreenshotNeo offers PNG, JPEG, or WebP screenshots and PDFs. It can capture full pages, selected elements, or PDFs with options such as paper size and margins; its broader options include viewport and device settings, dark mode, custom CSS or JavaScript, and wait conditions. It does not turn screenshot pixels into a compliant hotel-data feed. See ScreenshotNeo for the service and sign up free for 1,000 screenshots a month with no card.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.