# Changelog of Booking.com Hotel Details Scraper: Rooms & Prices (`myth84/booking-hotel-details-scraper`) Actor

- **URL**: https://apify.com/myth84/booking-hotel-details-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/myth84/booking-hotel-details-scraper.md

### Changelog

History of `booking-hotel-details-scraper` (folder `actors/booking-hotel-details`). Versions are the Apify build numbers.

#### Unreleased (all-in price: `taxesIncluded` and `priceTotalAllIn`)

- Brief `docs/cloud-tasks/2026-10-23_travel-prices-all-in.md` (2026-10-23): rows are **`travel-listing/1.6`** (the detail schema on top of the search schema `travel-listing/1.5`), two columns after `taxesAndFees`, nothing else changes (`priceTotal` keeps its meaning: the cheapest offer before the charges Booking.com shows as not included).
- **`taxesIncluded`** (read by `parseOfferResponse`, new `OfferPrice.taxesIncluded`): `false` when the offer shows an excluded amount above 0 (both priced offers of the committed captures), `true` for an excluded amount of 0, `null` without that amount, with one in another currency, or without an offer.
- **`priceTotalAllIn`** = `priceTotal` + `taxesAndFees` when `taxesIncluded` is `false`, `priceTotal` when it is `true`, `null` otherwise (`allInPriceTotal` of `@scraper-studio/core/schema`): €289.81 + €41.39 = €331.20 for the README example, $484.40 + $85.05 = $569.45 for the aparthotel.
- Dataset schema: both columns documented; *Overview* shows `priceTotalAllIn` next to `priceTotal`, *Prices* shows both after `taxesAndFees`. README: *Which price to compare* paragraph, sample output with `priceTotalAllIn` (instead of `checkOut`), FAQ *Which price is in the row?*, the strengths worth knowing when switching (hard `maxResults` cap never charged beyond, unknown pages not charged), *More scrapers* pointing at `priceTotalAllIn`.

#### Unreleased (quality score: input documented for AI agents)

- Brief `docs/cloud-tasks/2026-10-20_studio-quality-score-insights.md`: the input form passes the shared Store checks (`runInputQualityChecks`, `runSearchTextChecks` of `packages/core/src/testing/store-check.ts`).
- **Descriptions rewritten as a tool documentation** (what the field does, format with an example, default and its reason, bounds): `checkIn`, `checkOut`, `adults`, `children`, `childrenAges`, `rooms`, `includeOffer`, `maxPhotos`, `currency`, `language`, `maxResults`, `proxyConfiguration`, `maxRequests`, `delayMs`, `debugStoreResponses`.
- **`maxResults` prefilled with 50** (default still 100): Apify's daily test of the public Actor runs the prefilled form, a 3-hotel run (the three prefilled URLs); 50 rather than 3 so that a form user who pastes their own list is not cut at three hotels.
- **`inputs/daily-check.json` = the prefilled form**: the same 3 Lisbon hotel URLs and `maxResults` 50 (was 3: same three rows; the row count of the daily check is not checked by `scripts/release-actor.mjs`); `maxPhotos` 10 removed (the form's 45 applies: same requests, longer photo lists), keys equal to the defaults removed (`adults` 2, `includeOffer` true, `currency` EUR, `language` en-us). `store.json › dailyCheck.what` updated; the live daily-check task follows when the pilot re-sends it.
- Store texts carry "Booking.com hotel details": `actor.json` description ("Scrape Booking.com hotel details from hotel URLs: …") and `store.json` SEO description ("Scrape Booking.com hotel details by URL: …"); title and README line 1 unchanged. `store.json › searchSynonyms`: Booking.com scraper, room prices, room types. README input table: `maxResults`, `maxRequests` rows.
- **Example tasks**: the 8 SEO titles now carry the long-tail search "… – Booking.com hotel details" instead of "… – Booking.com details" (e.g. "Lisbon hotel prices next month – Booking.com hotel details"); published with `scripts/publish-tasks.mjs` at the publication of the Actor.
- No code change: rows, logs and charges are identical.

#### Unreleased (README visibility)

- **README first screen and links** (brief `docs/cloud-tasks/2026-10-20_studio-readme-visibility-new-actors.md`, 2026-10-21), same layout as the public Actors (PR #50). The Store search indexes only the first ~3,000 README characters, so they now hold: an opening sentence with the phrases agents search ("Booking.com hotel details", "room prices", competitor benchmarking, room price tracking with scheduled runs), a "No login, no cookies, no personal data" line, the Free-plan price in figures in *How much* ($4.21 per 1,000 hotels; Apify's $5 monthly credit covers about 1,187), computed from `pricing/2026-10-20_pay-per-event.autopilot.json` (Free tier of the primary event, one `apify-actor-start` event deducted), and a real output snippet (12 key columns of the README example row, the cheapest room in `highlights`). Further down: *Use it from your AI assistant* (MCP URL `https://mcp.apify.com?tools=myth84/booking-hotel-details-scraper` and a ready-to-copy prompt with a minimal input that never expires), *Alternatives and switching* (official API, home-made scraper, input-name mapping table, no competitor named), *More scrapers by Flatrow Data Studio* (Store links to the travel Actors already public, the Booking.com search first) with an invitation to rate the Actor (no counterpart), and the non-affiliation line at the very bottom. The cost section and the MCP cost bullet quote the same figures; the line 1 heading is unchanged. Checked by `runStoreChecks` (`readmeVisibility`). No code change: rows, logs and charges are identical.

#### Unreleased

- **Output schema `travel-listing/1.3`** (additive, follows `docs/cloud-tasks/2026-10-20_travel-extend-monitor.md`, PR #34): the search schema of the travel studio gained the price-monitoring block (`changeType`, `previousPrice`, `priceDelta`, `priceDeltaPercent`) and took the tag `travel-listing/1.2`; the detail schema this Actor shares follows as `1.3` so that one tag means one column set. The four columns sit after `scrapedAt`, before the detail columns, and are always `null` for this Actor (no monitoring mode). Dataset schema regenerated, README example and column table, output schema description and tests updated; no other change in the rows.
- **Release fix** (brief `docs/cloud-tasks/2026-10-20_booking-fix-release.md`): the first release stopped at the control step (run `ZavxrNOc583Z1E8OD`: 28 rows, 29 expected) because `inputs/control-scale.json` listed `pestana-palace-lisboa`, a hotel page guessed in the Booking audit (probe input `booking-run3.json`, label `hotel-page-guess`, never answered) and not a page name returned by Booking.com; an unknown page gives no row by design (`HotelPageNotFound`: not charged, not an error). The control input now lists the 28 pages returned by Booking.com in the captures (`maxResults` 28); the five example tasks that carried the same guess use a confirmed page instead (`almirante`, `vip-executive-suites-do-marques`, `family-refuge-lisbon`) or one page less (upscale hotels: 7, facilities audit: 28). No code change.
- Test (`src/tasks.test.ts`): known pages come only from Booking.com responses (city landing page, search results), no longer from probe inputs; every file of `inputs/` lists known pages only, without duplicates (except the deliberately unknown page of `validation.json`), and its `maxResults` equals their count — the exact row count `scripts/release-actor.mjs` checks.

#### 0.1 — 2026-10-20

- First version, written offline on the fixtures captured by the probe on 2026-10-20 (audit `docs/audits/booking-details.md`, brief `docs/cloud-tasks/2026-10-20_booking-details-build.md`): two calls per hotel to Booking.com's internal GraphQL API (`POST /dml/graphql`, query texts sent as is, no cookie, no token) — `PropertyPage` (`hotelPageByPageName`) for the hotel page, then a one-row `FullSearch` on the hotel itself (`destType: HOTEL`) for the cheapest offer of the dates and guests, asked once more after a cold answer (no block, no price, or an `irene` error), as measured by the probe.
- Output schema `travel-listing/1.2` with `ratingMax: 10`: description, facilities by group with their payment notes (`amenityGroups`), facility titles (`amenities`), one line per room type with its amenities (`sleepingArrangements`), gallery photos (`maxPhotos`, 45 by default), short and full address (`neighborhood`, `neighborhoodDescription`), district (`region`), coordinates, review score and count, stars, accessibility, Booking.com's generated summary (`locationSummary`), DSA trader status (`listedBy`); offer: `priceTotal`, `pricePerNight`, `priceBeforeDiscount`, `taxesAndFees`, `cancellationPolicy` (`free_cancellation_until:<date>`), `isAvailable`, badges (`meal_plan_included`, `third_party_offer`, deal badges). Spoken languages, location flags, programmes, certifications and the room type of the cheapest offer go to `highlights`.
- Decisions: one sticky datacenter session for the whole run (four hotels at a time), replaced once on an unusable response, then the hotel is given up; `HotelPageNotFound` gives no row, is not charged and is not an error of the run; a GraphQL validation error (schema change) fails the run at once instead of rotating through every hotel; an offer still empty after the second call gives `isAvailable: false`, an offer that could not be read (request failed or errors twice) gives `isAvailable: null` with empty prices (unknown is not "unavailable"); `propertyTypeCode` is Booking's accommodation type (`HOTEL`, `APARTHOTEL`), `roomType` is `entire_place` for apartments and aparthotels, `hotel_room` for hotels; facilities whose group is not described on the page go under "Other"; dates default to a check-in 30 days from the run date for 3 nights so that schedules and example tasks never expire.
- Not included in v1 (audit § 3, documented in the README): the per-room rate table, house rules and check-in / check-out times, category scores, availability calendar, reviews and anything about hosts.
- Pay-per-event `result` per hotel pushed; explicit failure when no row is produced; `RUN_STATS` with hotel pages, offers, empty and failed offers, second offer calls and unknown pages.
