Booking.com Hotel Scraper avatar

Booking.com Hotel Scraper

Pricing

from $2.00 / 1,000 hotel scrapeds

Go to Apify Store
Booking.com Hotel Scraper

Booking.com Hotel Scraper

Scrape Booking.com hotel prices, availability, ratings, rooms, policies, facilities, photos, and review summaries. Export CSV, JSON, Excel, or use the API.

Pricing

from $2.00 / 1,000 hotel scrapeds

Rating

0.0

(0)

Developer

Hanna Nosova

Hanna Nosova

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

15 days ago

Last modified

Share

Scrape Booking.com hotel listings for travel research, price monitoring, and structured hotel datasets.

What does this Actor do?

Booking.com Hotel Scraper returns structured hotel listings by destination or direct hotel URL. The default output is deliberately lean: identity, canonical URL, property type, location, rating, availability, and price context. Rooms, policies, facility highlights, photos, and review details are optional per-hotel enrichments.

Use it for hotel supply research, price snapshots, destination comparisons, lead lists, and travel-data pipelines. It does not sign in, reserve rooms, solve challenges, or collect private traveler data.

Who is it for?

  • Travel and hospitality analysts comparing public hotel supply and prices.
  • Revenue and market-research teams building repeatable destination snapshots.
  • Data engineers feeding hotel identity, availability, and price context into internal pipelines.
  • AI-agent builders who need schema-described Booking.com listing data through API or MCP.

Input example

{
"destination": "Lisbon",
"checkIn": "2026-08-15",
"checkOut": "2026-08-17",
"adults": 2,
"children": 1,
"childrenAges": [5],
"rooms": 1,
"currency": "USD",
"language": "en-us",
"maxHotelsPerSearch": 10,
"maxCandidatesPerSearch": 50,
"maxHotelsPerRun": 10
}

This saves at most 10 lean hotel rows. No per-hotel enrichment is requested.

Ready-to-run examples

Choose the product surface

Lean listing/search data is the default. Enable only the extra surfaces your workflow needs:

{
"hotelUrls": [
"https://www.booking.com/hotel/pt/chiado-arty-flats.html"
],
"checkIn": "2026-08-15",
"checkOut": "2026-08-17",
"adults": 2,
"children": 0,
"childrenAges": [],
"rooms": 1,
"enrichRooms": true,
"enrichPolicies": true,
"enrichFacilities": true,
"enrichPhotos": true,
"enrichReviews": true,
"maxHotelsPerRun": 1
}

Each selected enrichment runs independently. If rooms fail but photos succeed, the actor keeps the base hotel row, reports the rooms warning on that row, and keeps the successful photos. There is no enrichment-specific charge event, so a failed enrichment is never charged separately.

enrichReviews returns the review score/count, labels, secondary score, and available summary metadata. It does not return individual guest review text.

Dates for scheduled runs

Use fixed checkIn and checkOut dates for one-off snapshots. For schedules, use a relative pair that resolves once when each run starts:

{
"destination": "Paris",
"checkInOffsetDays": 14,
"stayNights": 3,
"currency": "EUR",
"sortBy": "PRICE_ASC",
"maxHotelsPerSearch": 5,
"maxCandidatesPerSearch": 50,
"maxHotelsPerRun": 5
}

Do not combine the two date modes. Every row records the mode, relative values, resolved dates, and resolution time in provenance.

Search targets

Provide at least one of:

  • destination: one city, region, landmark, or hotel phrase.
  • destinations: multiple independent destination searches.
  • hotelUrls: direct Booking.com /hotel/{country}/{slug}.html URLs.

Direct hotel URLs can be more deterministic than broad destination searches because the actor resolves and matches the stable hotel ID before accepting a row. Neither direct URLs nor destination searches should be treated as immune to Booking.com blocking, challenges, redirects, inventory changes, or schema changes.

Input settings

InputTypeMeaning
destinationstringOne destination search phrase.
destinationsstring[]Multiple destination searches.
hotelUrlsstring[]Direct Booking.com hotel URLs; each can return at most one hotel.
checkIn, checkOutstringOptional YYYY-MM-DD range. Supply both or neither.
checkInOffsetDays, stayNightsintegerRelative date pair for schedules: offset 0–365 and stay 1–30 nights.
adultsintegerAdult guests; default 2.
childrenintegerChild guests; default 0.
childrenAgesinteger[]Exactly one age, 0–17, for every child.
roomsintegerRooms requested; default 1.
currencystringRequested three-letter currency. Returned currency is recorded separately.
languagestringRequested Booking.com locale, such as en-us or de-de.
countryCodestringOptional country for the existing residential proxy route. It is not a blocking guarantee.
propertyTypesstring[]Optional categories such as HOTEL, APARTMENT, or HOSTEL.
minReviewScoreintegerOptional minimum of 6, 7, 8, or 9.
starRatingsinteger[]Optional exact star ratings from 1 to 5.
freeCancellationOnlybooleanKeep listings exposing free cancellation in the requested stay context.
minPricePerNight, maxPricePerNightnumberOptional bounds calculated from displayed stay total ÷ nights; dates are required.
sortBystringRECOMMENDED, PRICE_ASC, TOP_REVIEWED, STARS_DESC, or STARS_ASC.
maxCandidatesPerSearchintegerUnpaid candidate rows evaluated per destination; 1–500 and at least the saved per-search cap.
maxHotelsPerSearchintegerMaximum rows from each destination search; 1–100.
maxHotelsPerRunintegerHard saved-and-charged row cap across the whole run; 1–100.
enrichRoomsbooleanRoom configurations and matched offer data.
enrichPoliciesbooleanCancellation, prepayment, pet, and meal-plan signals.
enrichFacilitiesbooleanFacility and property-USP highlights.
enrichPhotosbooleanAvailable hotel photos.
enrichReviewsbooleanReview labels, secondary score, and summary metadata.

Backward compatibility: maxItems sets both limits and includeDetails enables all enrichments. Do not combine maxItems with either explicit limit. New integrations should use the explicit fields.

Limits and charging

The three limits have different scopes:

  • maxCandidatesPerSearch caps unpaid candidate rows evaluated for each destination while applying filters.
  • maxHotelsPerSearch stops each destination search independently.
  • maxHotelsPerRun is the total number of dataset rows that can be saved and charged across all destinations and direct hotel URLs.

Duplicate stable hotel IDs are saved once per run. Direct hotel URL targets return at most one row each. RUN_SUMMARY records all three limits plus candidatesEvaluated, filteredOutRows, saved, and chargedHotels. If filters consume the candidate allowance before any row can be saved, the run reports INPUT_CONFIGURATION_LIMIT_REACHED instead of a misleading empty success.

Pricing

Pricing uses these events:

EventPrice
Start$0.0005 once per run
Hotel scraped — Free$0.0029 per saved row
Hotel scraped — Bronze$0.0027 per saved row
Hotel scraped — Silver$0.0024 per saved row
Hotel scraped — Gold$0.0020 per saved row
Hotel scraped — Platinum$0.0015 per saved row
Hotel scraped — Diamond$0.0010 per saved row

The hotel-scraped event is emitted atomically with the base dataset row. Optional enrichments do not have separate charge events. Residential proxy traffic is part of the actor’s operating route.

Output fields

Each dataset item includes:

  • Stable identity when exposed: hotelId, bookingId, canonicalUrl, and legacy alias url.
  • Search provenance: requested/applied destination, fixed or relative date mode, resolved dates/time, adults, children, childrenAges, rooms, currency, language, filters, and sorting.
  • Base listing data: hotel name, property type, free-cancellation signal, address, city, country code, coordinates, stars, rating, and review count.
  • Field-level availability context: dates, occupancy, status, and Booking.com message.
  • Field-level price context: requested/returned currency, total-stay basis, nights, displayed total, transparently derived per-night price, original total, separately excluded taxes/fees, and inclusion status.
  • Optional rooms, policies, facilities, photos, and reviews data.
  • Per-enrichment status, row-level warnings, result rank, and scrapedAt.

Output example

Example dataset item excerpt:

{
"hotelName": "Chiado Arty Flats",
"hotelId": 1814397,
"canonicalUrl": "https://www.booking.com/hotel/pt/chiado-arty-flats.html",
"childrenAges": [5],
"price": "$400.03",
"currency": "USD",
"priceContext": {
"status": "AVAILABLE",
"basis": "TOTAL_STAY",
"checkIn": "2026-08-15",
"checkOut": "2026-08-17",
"nights": 2,
"requestedCurrency": "USD",
"returnedCurrency": "USD",
"total": { "amount": 400.03, "formatted": "$400.03", "currency": "USD" },
"pricePerNight": { "amount": 200.02, "formatted": null, "currency": "USD" },
"pricePerNightBasis": "DISPLAYED_TOTAL_DIVIDED_BY_NIGHTS",
"excludedTaxesAndFees": { "amount": 42.31, "formatted": "$42.31", "currency": "USD" },
"totalIncludesTaxesAndFees": false
},
"availabilityContext": {
"status": "AVAILABLE",
"adults": 2,
"children": 1,
"childrenAges": [5],
"rooms": 1
},
"enrichment": {
"rooms": { "requested": false, "status": "NOT_REQUESTED", "warning": null },
"policies": { "requested": false, "status": "NOT_REQUESTED", "warning": null },
"facilities": { "requested": false, "status": "NOT_REQUESTED", "warning": null },
"photos": { "requested": false, "status": "NOT_REQUESTED", "warning": null },
"reviews": { "requested": false, "status": "NOT_REQUESTED", "warning": null }
},
"warnings": [],
"scrapedAt": "2026-07-20T12:00:00.000Z"
}

priceContext.total is the total Booking.com displayed for the requested stay. pricePerNight is that displayed total divided by the number of nights and rounded to two decimals; it is not a separately quoted rate. excludedTaxesAndFees remains separate and is never silently added.

Run outcomes

Read RUN_SUMMARY from the default key-value store. The status is explicit:

StatusMeaning
SUCCEEDEDRequested base rows were saved without warnings.
NO_MATCHESThe target resolved but returned no matching hotels, or no destination/hotel could be resolved. A zero-row run fails instead of reporting success.
SOLD_OUTThe requested dates/occupancy produced only sold-out results or no availability.
TARGET_CHALLENGEBooking.com returned an access challenge.
PARTIALAt least one base row was saved, but a target or optional enrichment failed, or the safe deadline was reached.
INPUT_CONFIGURATION_LIMIT_REACHEDInput validation, a documented target/input limit, or the candidate allowance before the first filtered match was reached. Validation errors occur before the start event.
FAILEDAn unexpected target, transport, storage, or response error stopped the run.

When optional work fails, every retained row has a structured warning with scope, code, message, and retryable. Deadline-limited runs also write PENDING_WORK.

API usage

Node.js

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('fetch_cat/booking-com-hotels-scraper').call({
destination: 'Lisbon',
maxHotelsPerSearch: 10,
maxCandidatesPerSearch: 50,
maxHotelsPerRun: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Python

from apify_client import ApifyClient
client = ApifyClient("$APIFY_TOKEN")
run = client.actor("fetch_cat/booking-com-hotels-scraper").call(run_input={
"destination": "Lisbon",
"maxHotelsPerSearch": 10,
"maxCandidatesPerSearch": 50,
"maxHotelsPerRun": 10,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)

cURL

curl -X POST 'https://api.apify.com/v2/acts/fetch_cat~booking-com-hotels-scraper/runs?token=$APIFY_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"destination":"Lisbon","maxHotelsPerSearch":10,"maxCandidatesPerSearch":50,"maxHotelsPerRun":10}'

MCP and AI agents

The input, output, and dataset schemas are published for OpenAPI and Apify MCP use. Ask an agent to start with lean output and opt into only the enrichments it needs.

$claude mcp add apify -- npx -y @apify/actors-mcp-server --actors fetch_cat/booking-com-hotels-scraper

Equivalent MCP JSON configuration:

{
"mcpServers": {
"apify": {
"command": "npx",
"args": ["-y", "@apify/actors-mcp-server", "--actors", "fetch_cat/booking-com-hotels-scraper"],
"env": { "APIFY_TOKEN": "$APIFY_TOKEN" }
}
}
}

Example prompts:

  • “Collect 10 lean Booking.com hotel rows for Lisbon and preserve total-price/tax context.”
  • “Schedule a Paris snapshot 14 days ahead for a three-night stay, sorted by price.”
  • “Find 4- and 5-star Lisbon hotels rated 8+ and evaluate at most 50 candidates.”
  • “Resolve this direct Booking.com hotel URL and add rooms and policies.”
  • “Compare three destinations, cap each search at 5 hotels, and cap the whole charged run at 12 rows.”

Troubleshooting

  • TARGET_CHALLENGE: retry later or use a smaller target set. The actor does not solve target challenges or promise an unblock.
  • NO_MATCHES: verify spelling or use a direct hotel URL when you already know the property.
  • SOLD_OUT: verify dates, guest ages, and occupancy, or retry without dates to collect identity-only listings.
  • PARTIAL: inspect row warnings and each enrichment status; successful base data remains usable.
  • INPUT_CONFIGURATION_LIMIT_REACHED: check childrenAges, the chosen date mode, target count, price range, and all three explicit limits. With filters, raise maxCandidatesPerSearch or relax the filters.
  • Returned currency differs from requested currency: use provenance.requested.currency and priceContext.returnedCurrency rather than assuming conversion.

FAQ

Can I use this through the API or MCP? Yes. The Actor publishes input, output, and dataset schemas for Apify API, OpenAPI, and MCP clients.

Should I use a destination or a direct hotel URL? Use a destination to discover supply and a direct URL when you already know the property. Direct URLs are generally more deterministic, but both modes can be redirected, challenged, or blocked.

Are optional enrichments charged separately? No. The Actor charges the base row only when it is saved. There are no rooms, policies, facilities, photos, or reviews charge events.

Can scheduled runs keep dates current? Yes. Use checkInOffsetDays with stayNights; each run records the resolved dates and time. Fixed and relative date modes cannot be combined.

Does enrichReviews return guest review text? No. It returns listing-level review details and available summary metadata. Use the related reviews-specific Actor when individual public reviews are required.

Why can the returned currency differ from my input? Currency is controlled by Booking.com’s response context. The Actor preserves both the requested and returned values instead of claiming a conversion it did not perform.

What is the alternative when Booking.com challenges a run? Retry later with a smaller scope, or use Booking.com’s official partner APIs if you have the required commercial access. This Actor does not bypass challenges.

Legality and responsible use

Use this actor for lawful public-data research. Follow Booking.com’s terms, applicable laws, and privacy requirements. Do not use it for personal traveler data, reservations, account-only data, abusive traffic, or attempts to bypass access controls.

Support

For a reproducible issue, include the Apify run ID or run URL, exact input JSON, RUN_SUMMARY, expected output, actual output, and a reproducible public URL when one exists. Never post API tokens, cookies, or private traveler data.