# Changelog of Booking.com Reviews Scraper: Anonymous Scores (`myth84/booking-reviews-scraper`) Actor

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

### Changelog

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

#### Unreleased (agent-facing polish: field order, first screen)

- Brief `docs/cloud-tasks/2026-10-24_studio-agent-facing-polish.md` (2026-10-24): what an AI agent reads first. No change to the code, the defaults, the prices or the output.
- **Input field order** (the Apify MCP search card lists the first 20 fields): unchanged: every field is among the first 20 and the proxy and crawl settings already close the form. Nothing renamed or removed.
- **README first screen**: under the title, "Verified daily by an automated run on Apify with the default input", the Free-plan and Business-plan prices per 1,000 results of the pricing file in force and the $0.00005 start fee per run (Apify's minimum); a one-line review request before the legal note. A test binds these figures to the pricing file and forbids "to confirm" and "no start fee" in the input schema and the README.

#### 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): `maxReviewsPerHotel`, `maxResults`, `reviewsSince`, `languages`, `topic`, `language`, `proxyConfiguration`, `maxRequests`, `delayMs`, `debugStoreResponses`.
- **`maxResults` prefilled with 20** (default still 1,000): Apify's daily test of the public Actor runs the prefilled form, now a 20-review run.
- **`inputs/daily-check.json` = the prefilled form**: the same Lisbon hotel and `maxResults` 20; `maxReviewsPerHotel` 20 removed (the default 100 applies; with one hotel the run cap of 20 stops first: same requests and rows), keys equal to the defaults removed (`sortBy` NEWEST_FIRST, `language` en-us). `store.json › dailyCheck.what` unchanged (still true); the live daily-check task follows when the pilot re-sends it.
- Store texts carry "Booking.com reviews": `actor.json` description ("Scrape Booking.com reviews from hotel URLs: …") and `store.json` SEO description ("Scrape Booking.com reviews by hotel URL: …"); title and README line 1 unchanged. README opening sentence: "Use it as a Booking reviews scraper for …". `store.json › searchSynonyms`: Booking reviews, hotel review analysis, sentiment analysis, competitor benchmarking. README input table: `maxResults`, `languages` rows.
- 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 phrase agents search ("Booking.com reviews scraper — anonymous, no reviewer names", hotel review analysis, sentiment analysis, competitor benchmarking, monitoring new reviews), the "No login, no cookies, no personal data" line joined to the anonymity sentence of 0.1, the Free-plan price in figures in *How much* ($4.21 per 1,000 reviews; 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, nothing that looks like an identity: no `reviewKey`, no URL). Further down: *Use it from your AI assistant* (MCP URL `https://mcp.apify.com?tools=myth84/booking-reviews-scraper` and a ready-to-copy prompt with a minimal input), *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`) and by a snippet-columns test. No code change: rows, logs and charges are identical.

#### 0.1 — 2026-10-20

- First version, written offline on the fixtures captured by the probe on 2026-10-20 (audit `docs/audits/booking-reviews.md`, brief `docs/cloud-tasks/2026-10-20_booking-reviews-build.md`): each hotel URL resolved once by Booking.com's `PropertyPage` GraphQL operation (hotel id, city id `ufi`, overall score, review count), then `ReviewList` read 25 reviews per request, paginated by `skip` to the end of the hotel; five sort orders; Booking.com's own filters (`languages`, `tripType` → `customerType`, `season` → `timeOfYear`, `scoreBand` → `scoreRange`, `searchQuery` → `text`, `topic` → `selectedTopics` looked up per hotel in its topic list, with one small extra request); `reviewsSince` (early stop when sorted newest first); per-hotel and run caps; deduplication by `reviewKey`, and of hotels whose page names resolve to the same id; 4 hotels at a time in one sticky session; interface language `language` (room types, topic names, most-relevant order).
- Output schema `travel-review/1.1` (shared with the Airbnb reviews): this build adds four Booking.com sub-score columns (`listingRatingStaff`, `listingRatingComfort`, `listingRatingFacilities`, `listingRatingWifi`) to `packages/core/src/schema/travel-reviews.ts`; the 7 hotel sub-scores are rounded to 2 decimals and repeated on every row.
- Anonymous by design (user decision of 2026-10-20): the reviews query never selects `guestDetails`, `photos`, the reply text, `checkoutDate`, `editUrl` nor the highlights (tested); `customerType` and `customerTypeFilter` are aliased, the property reply is reduced to its presence (`hasHostResponse`); rows built from a whitelist; HTML and `<mark>` tags removed, links → `[link]`, e-mails and phone numbers → `[redacted]`; months only; `reviewKey` = first 16 hex characters of SHA-256("booking:<reviewUrl>"). `debugStoreResponses` stores the responses as they are, since they hold no identity.
- Errors: unknown page → counted as not found, the run goes on; unknown hotel id or no matching review → counted as without reviews; topic absent from a hotel → counted, its topics listed in the log; rejected query or input (`VALIDATION_INVALID_TYPE_VARIABLE`, `GRAPHQL_VALIDATION_FAILED`) → no retry, "Booking changed its reviews API; the Actor needs an update"; unusable response (status, challenge page, not JSON, `ReviewsFrontendError`) → one session rotation, then give-up. A 200 JSON answer is accepted even when a review text trips a block marker. Explicit failure on empty output, naming the cause.
- Store title shortened to "Booking.com Reviews Scraper: Anonymous Scores" (45 characters): the brief's "…Anonymous Scores, Texts & Stay Types" (66) exceeds the 50-character limit checked by the Store tests.
- Control run input capped at 2,200 reviews (`maxResults`) for two hotels of 870 and 1,428 reviews, so that the release script, which expects exactly `maxResults` rows, can check the count while the pagination runs close to the end of both histories (the brief's 5,000 could never be reached).
- Example tasks: 50 to 60 reviews each on hotel pages Booking.com returned in the committed captures.
