Every column this Actor can return, by mode, as the deployed build emits it.
Describes build 1.0.173 of rl1987/booking-api-scraper, deployed 2026-10-29. The column set last changed 2026-10-29. Earlier builds can return a different one.
Every column this Actor can return, by mode, as the deployed build emits it.
120 columns documented across 6 row kinds.
| Row kind | Modes | Columns |
|---|---|---|
| Accommodations | search, rooms, details, surroundings | 38 |
| Reviews & scores | reviews, reviewScores, or search with the review toggles | 13 |
| Watched rates | rates | 27 |
| Attractions | attractions | 31 |
| Attraction details | attractionDetails | 57 |
| Attraction availability | attractionAvailability | 20 |
None of these is a property of a single column, so none of them is generated — and they are where most questions actually get answered.
| page | answers |
|---|---|
| Input reference | every input, what it does, and which ones add a charge event |
| Recipes | eight worked runs with the input that produces each |
| The price stack | what is inside the amount the guest pays, what sits on top, and what is outside it entirely |
| What each mode bills | mode to charge event, and what one unit is |
| Known limitations | what this surface cannot give, with the measurement that says so |
Numeric ids — accommodation type, room type, bed type, charge type, payment card — are tabled separately in the integer ID reference .
Annotated screenshots of the app, with each number on screen joined to the field that produced it, are on the screenshots page - the place to look when you want to know which column matches a price a buyer can see.
One dataset can hold several kinds of row. A run produces one kind, but if you combine datasets, read recordType first: it is absent on property rows and rate, attraction, attractionDetail or attractionAvailability otherwise.
A column absent from a row is normal. Most columns belong to one mode. Nothing in the schema is required, and no row is ever rejected for shape.
The objects inside a row are documented too. A column carrying an object or a list of objects — rooms[], products[], price — has a table per level under Inside the nested columns on its page, with a tree of the nesting, a parent chain on each table, and a pointer from a parent row to the table it continues in. That is where rooms[].areas[].beds[] and products[].policies.meal_plan.offers[] are described field by field.
A few column names mean different things by row kind, and the descriptions say which:
price is an object on a property row and a number on a rate or attraction row.latitude / longitude are the property’s own on a property row and the attraction’s own on an attraction-details row. The destination centroid is named cityLatitude / cityLongitude and is the only coordinate a catalogue row carries.name is the property name or the attraction name.price.total_with_charges, not price.total. Not because total is always wrong - on a room-list rate it is exactly the figure on the app’s price sheet - but because it is only sometimes right. When Booking excludes taxes from its display price, total understates what the guest pays; when the taxes are already inside it, the two columns are the same number. total_with_charges is correct either way, so reading it costs nothing and removes the branch.starRating does not say whether the stars are official. Booking lets some properties self-estimate, and the mobile surface does not distinguish them.amountDueNow is null, not 0, when a rate states no payment stage. Treating null as zero turns every such rate into a false “pays nothing at booking”.dueDate is not the cancellation deadline, and it is absent on some no_prepayment_until rates — Booking simply does not state one.cityLatitude / cityLongitude are the destination centroid, so every product in a city shares one point - plotting them puts the whole city on one pin. attractionDetails carries the product’s own latitude / longitude, filled on about half of products.mealPlan: no_plan does not mean no breakfast. It means none is included in the rate, and 40% of rate blocks measured sell one for a fee. breakfastAvailableForFee says so and breakfastPrice says what it costs, per person per night.breakfastPrice with breakfastCurrency: a Cape Town property quotes breakfast at 120 ZAR on a run priced in EUR, so pairing the amount with the row’s currency overstates it twentyfold.rooms[].areas places beds; it does not inventory rooms. Two entries of one type can describe a single room, which is why there is a hasLivingRoom flag and no living-room count. bedCount stays the one bed number to trust - areas[].beds and bedLayouts are the same beds from different angles.scrapedAt is ISO-8601 UTC to the millisecond and scrapedAtUnix the same instant in epoch seconds, both stamped from the response that priced the row rather than from the end of the run - a 60-row run spanned 16 seconds over 12 distinct values. Prices are live; a dataset read a week later is not.provenance says which market priced the row — on every row kind. The point of sale follows the proxy exit IP, not an input: taxes come back inside the display price from an EU exit and excluded through a US one. provenance.exitCountry, proxyGeneration, currencyRequested and surface record what produced each row. The old bookerCountry input promised this and was read by nothing, so it is gone. Attraction rows carry it too since build 1.0.161, error rows included: a row that records a failure still says when it was fetched and which operation served it.conditional bucket any more, and a deposit line would be the damage deposit. conditional[] and conditionalTotal were removed on 28 October 2026 after proving empty on every surface this Actor reads - 0 of 4,934 room-list lines and 0 of 405 search lines. A charge line’s own inclusion still reads conditional where Booking says so, and such a line groups with excluded rather than unknown, which would claim Booking said nothing. deposit keeps its bucket because grouping a refundable deposit into excluded would overstate the bill - and if one ever appears it is the same money as details.damageDeposit, not a second charge to add to it.A field description is a claim about a surface a buyer can look at, so it is worth saying which surface. The Actor calls Booking’s mobile app endpoints, and the app and the website are different points of sale that legitimately disagree about the same rate - measured on one property on one night, the app struck through MYR 173 and badged “MYR 46 off” where the web page struck through EUR 31 and badged “9% off”. The app is the reference here; a disagreement with the website is not a defect in these columns.
Accommodation claims rest on three arms that could have disagreed: the app driven in an instrumented emulator, which is where the MYR figures above were read off the screen; an independent third-party dataset, which matched on 27 of 27 prices and 15 of 15 bed configurations; and Booking’s own connector, which matched one property to the cent. A screen-by-screen table pairing every on-screen value to the response field behind it does not exist yet - the price claim above is the one that has been checked that way.
Attraction claims have no app surface to check against. The Attractions tab is reachable in the app and its destination search is native, but selecting a destination hands off to a WebView on the booking.com web surface - there is no native product page or availability calendar to screenshot. For attractions the web page is therefore the only rendered surface, and the right one. Where a column is empty on every product measured, the page says so rather than implying it will fill.
One row per property. The search modes produce the whole row; the enrichment modes produce the id, the stay and the block you asked for, so join those back on id.
Read it →Day-level bookability over a window, optionally with timeslots. Each timeslot date is a separate upstream request, capped at 14.
Read it →The full attraction record. Several columns are empty on every product measured because the upstream does not fill them — each says so.
Read it →One row per attraction in the catalogue search.
Read it →Every input the Booking.com scraper takes, what it does, and which ones add a charge event - the part a generated field description cannot carry.
Read it →Every numeric vocabulary this Actor maps to a name, how complete each map is, and how we know.
Read it →What this surface cannot give you, with the measurement that says so - starting with roomList returning bookable room types rather than the property catalogue.
Read it →Eight worked Booking.com runs, each with the exact input that produces it: family stays, price monitoring, cheapest well-rated hotels, apartments only, reviews, radius search, full enrichment, and sold-out detection.
Read it →Guest reviews and the per-category subscores. In the enrichment modes the row carries only id, the stay and the review block.
Read it →What is inside the amount a guest pays, what Booking adds on top, and what sits outside it entirely - with the field holding each, and the one column to reconcile against.
Read it →One row per watched product id: whether that exact rate is still on sale for your stay, and at what price. A rate that has gone still occupies a full row, with status and reason saying why.
Read it →Mode to charge event for all ten Booking.com scraper modes, what one unit is, and which events are not priced yet. No figures - the Pricing tab is generated.
Read it →Captured from the Booking Android app on 2026-10-23, driven in an instrumented emulator with the traffic recorded alongside, so each number on screen is joined to the response it came from rather than matched by eye.
Read it →