# Changelog of Vivino Wines Scraper: Ratings, Prices & Wine Data (`devilscrapes/vivino-wines-scraper`) Actor

- **URL**: https://apify.com/devilscrapes/vivino-wines-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/devilscrapes/vivino-wines-scraper.md

## Changelog

### 0.1.0 (unreleased)

First implementation. Captures taken 2026-10-08 (local, direct, Lithuanian exit).

- Explore feed scraper: `GET /api/explore/explore` via curl-cffi (`chrome131`), always sending
  `Accept: application/json` (without it the endpoint answers 415 text/html).
- Pagination: 24 wines per page, page ceiling recomputed from each response's `records_matched`
  (it drifts: 6,510 on 10-07 vs 6,101 on 10-08 for the same query). Stops at `maxItems`, an empty
  `matches`, or the ceiling. Rows deduped on `vintageId`; the last page is truncated at `maxItems`.
- Retry: 408/429/503 and network errors, exponential backoff 2s to 30s, 5 attempts, `Retry-After`
  honoured. 403/429 rotate the proxy `session_id` when a proxy is configured. 415 and other 4xx are
  not retried. A 200 that is not an explore payload is a failure, never an empty result.
- Proxy is OFF by default; when on, `apifyProxyCountry` is pinned to `countryCode`
  (`explore_vintage.market.country` follows the exit IP, emitted per row as `marketCountry`).
- PPE: `actor-start` $0.02 once, `result` $0.003 per row. Zero rows charge only the start event.
- Fixtures: first 3 `matches` (and the duplicate `records` list) of two real captures
  (US red, FR white page 1); every other key untouched. See `tools/trim_fixtures.py`.

#### Verified sort mapping

Pre-registered rule: a sort is exposed only if the response is 200 JSON, the 24 rows are monotone in
the sorted field, and the order differs from the `ratings_count` baseline. Probed 2026-10-08,
US red, 1 request each, no proxy:

| Input `orderBy` | API `order_by` | Result |
|---|---|---|
| `ratings_count` | `ratings_count` | VERIFIED (default; baseline captures) |
| `rating` | `ratings_average` | VERIFIED: 200 JSON, 24 rows, `ratings_average` non-increasing (desc), order differs from baseline |
| `price` (not exposed) | `price` | UNVERIFIED: 200 JSON but `price.amount` NOT monotone for `order=asc` (20.13, 14.09, 33.44, 100.53, ...). Left out of the schema. |

Vintage URL: `HEAD https://www.vivino.com/wines/1469676` returns 302 to
`https://www.vivino.com/en/wines/1469676`, so `https://www.vivino.com/wines/<vintageId>` resolves
and is used for `url`.
