# Changelog of Vivino data scraper: wine rating and wine reviews (`mrbridge/vivino-wine-data-scraper`) Actor

- **URL**: https://apify.com/mrbridge/vivino-wine-data-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/mrbridge/vivino-wine-data-scraper.md

## Changelog

All notable changes to **Vivino Wine Data Scraper** are documented here.

### v0.5.16 (2026-09-21)

Everything below is **verified locally**, against recorded captures and synthetic test fixtures. None of
it has been measured on a live run yet, so the effect on your own requests is not established here.

#### Fixed

- **Producer identity is checked before comparing cuvées.** Asking for "Rayas blanc" could come back
  unanswered because three wines from an unrelated Spanish estate, Cuatro Rayas, were compared as if they
  were other cuvées of Château Rayas. The same happened to "Pierre Peters L'Esprit"
  against Peter Michael and Castel Peter. Deciding which estate you named now comes **before** deciding
  which of its wines answers, so a namesake from another house no longer makes your request unanswerable.
- **A producer you write out in full outranks a near-spelling.** Two estates whose names differ by one
  letter were treated as equally named, so a request naming one of them exactly came back unanswered. A
  name written word for word now wins over a lookalike. Two houses that really do reduce to the same name
  still leave the request unanswered, and so do two lookalikes when neither is written exactly.
- **The wine that is billed is the wine the proof was about.** When the ranking put a wine from another
  estate first, the identity proof established for one house could be applied to that other wine. The
  proof and the published line are now inseparable: without a proof covering the wine itself, nothing is
  billed.
- **A vineyard name inside an appellation label is no longer ignored.** "Morgeot Les Brussonnes" was
  treated as no more specific than "Morgeot", because Vivino carries the climat inside the wine's region.
  A word is now only discounted as shared context when a competing candidate actually carries it, checked
  on the competing candidates whose context is available. When a competitor's context is missing, the
  cautious reading stands and the word keeps counting as shared, so an absent field never turns into a
  reason to bill.

#### Changed

- **When two houses answer the request equally well, neither is billed.** If the request names one estate
  in full and another only in part, but both have a wine matching the requested cuvée word for word,
  there is nothing in the request to choose between them. Both candidates are returned, unbilled. Naming
  the estate explicitly resolves it as before.
- **Requests that name only a producer, and requests where no estate is named in full, are unchanged.**

#### Notes

- This release moves RESOLVER\_CACHE\_VERSION from 13 to 14. Existing entries are retained in the old
  namespace. Nothing is deleted.
- The 115-case guard suite combines unit tests and runActor scenarios checking published rows and
  simulated charges, including reversed candidate orders, swapped ratings, missing identifiers and
  missing region data. What a live run will produce is not known from that.

### v0.5.15 (2026-09-20)

#### Changed

- **A request that several of an estate's wines answer equally well is no longer billed.** When an estate makes "Réserve Merlot", "Merlot - Syrah" and "Réserve Merlot Syrah", a request for that estate's "Merlot" is satisfied by all three and names none of them. Until now one was picked and billed, and which one it was could change with the ratings of the day or with the order the catalogue happened to return. Such a request now comes back with `resolution_status: "ambiguous"`, it is not billed, and the competing candidates are published alongside it as unbilled rows so you can choose. Naming what you want still resolves and is still billed, including a distinctive qualifier: "Réserve Merlot" returns Réserve Merlot.
- **The decision rests on names only, never on ratings or popularity.** A better-rated wine is no longer treated as the answer to a request that does not name it. Ratings still order results, they no longer decide identity.
- **Two colours of the same cuvée stay flagged for the rest of the run.** A request that does not say the colour, for a cuvée the estate makes in both, was already returned unbilled when both colours appeared in the same response. Vivino does not always return both. When a later request in the same run asks for another year of that cuvée and only one colour comes back, it is now still flagged and still unbilled. Nothing is invented for the colour that is missing: no year, no rating, no price. Asking for the colour resolves the request as before, and this memory lasts only for the run.
- **Resolutions cached by earlier versions are no longer replayed.** The rules above change which requests have a single answer, so a cached result from a previous version could serve an answer these rules would now decline. Cached entries are simply ignored, nothing is deleted.

#### Fixed

- **A request that names its cuvée now selects that wine on every search path.** The right wine was already loaded, but on the paths that read Vivino's pages rather than its search API the best-ranked candidate was kept, and a request naming another of the estate's wines came back as ambiguous instead of resolving. "Domaine des Tours Réserve Merlot" and "Domaine des Tours Merlot Syrah" now return their own wine, whatever order the catalogue returns, on the search page, on the estate's own list, on the shortened retry and on recovery.
- **A name that matches word for word now outranks a lookalike.** Spelling tolerance is what lets "Vieilles Vignes" find "Vieille Vigne" and "St Joseph" find "Saint-Joseph". It was also making a cuvée whose name differs by one letter count as an equal match, so a request for "Charmes" at an estate that also makes "Chaumes" had two answers instead of one. A name that matches exactly now wins. Approximate matching still applies when nothing matches exactly, and two candidates that only resemble the request still leave it unanswered, which is the honest outcome.
- **Qualifiers that name a different wine are no longer dropped.** "Bordeaux Supérieur" is an appellation of its own and is no longer treated as "Bordeaux", and the same holds for a "Villages" bottling. The classification wording Vivino adds to a wine's own name is still ignored, so "Chambertin Grand Cru" still answers a request for "Chambertin".
- **Requests that name only a producer are unaffected by all of the above.** Asking for an estate, with or without a year, returns and bills exactly what it did before. A request names a cuvée or it does not, and the rules above apply only when it does.

### v0.5.14 (2026-09-19)

#### Fixed

- **Asking for an appellation no longer returns a single-vineyard bottling of the same estate.** "Jamet Cote Rotie" could come back as Côte-Rôtie Côte Brune, the estate's named parcel, because that name contains every word of the request and so scored the same as the plain Côte-Rôtie, with the better-rated parcel winning the tie. A candidate that adds a vineyard or cuvée name the request never mentioned is now ranked behind the wine that matches the request exactly. Naming the parcel still works: "Jamet Cote Rotie Cote Brune" and "Jamet Cote Rotie Landonne" return those wines, and the runner-up is still offered as an unbilled alternative.
- **The requested year no longer changes which wine you get.** A year tells us which vintage of a wine to serve. It was also lifting any bottle that happened to carry that year to the front of the results, whatever it was, so the answer depended on which cuvée the catalogue stocked for that year rather than on what was asked. In one case a Côtes du Rhône was promoted over a Côte-Rôtie request and the whole result set was then thrown away. The year now only orders vintages among the candidates that match the request equally well, so the requested vintage is still pinned on the wine you asked for.
- **A misspelled producer name no longer hides that producer's catalogue.** "chat. Lafite rotchild" resolved to Château Lafite Rothschild correctly, then discarded all 79 of its wines because "rotchild" is two letters away from "rothschild" and the relevance check allowed only one. The search fell through to a single obscure bottling with five ratings, and billed it. The relevance check and the producer-only check now read the same spelling variants the rest of the matching already did, so the request reaches the estate's flagship. Requests that name a second wine keep it: "Carruades de Lafite" still returns Carruades.

### v0.5.13 (2026-09-18)

#### Fixed

- **A short query is now checked for the producer it names.** "Chave St Joseph" could come back as a wine from an unrelated estate whose name differs by one letter, because the producer check only ran on queries of three words or more. It now runs from two words on, which is the common "producer plus appellation" shape and the one most exposed: the appellation is shared by every neighbour, so the producer is the only thing identifying the wine. Searching by wine alone is unaffected: "Grange Shiraz" or "Grange Bin 95" name a cuvée and a grape rather than an estate, and nothing is required of the producer there.
- **A one-letter resemblance to a generic word no longer counts as the producer.** Words like "cave", "domaine" or "fils" describe a kind of estate, not an estate, so a near-match on them is noise. Spelling tolerance still works where it identifies someone, as in "Petrux" for Pétrus.
- **A vintage rating now comes from the vintage's own page.** Vivino's search API returns a rating in the vintage's slot that sometimes describes the whole wine instead, and nothing in that response tells the two apart: rows could announce a vintage rating of 4.2 out of 475 ratings for a year that in fact has 5 and no published average. The Actor no longer takes a vintage rating from search results. It reads the vintage's own page, which states each level separately, and only accepts it when the year and the vintage identifier match the row it is filling. On the rows this affects that page was already being loaded, so nothing extra is fetched there. Where a row already has everything else it needs, reading the year can now cost one page, and the run summary reports how often that happens. When no page confirms the year, the rating comes back as an all-vintages figure with the matching count and scope, rather than a vintage figure that cannot be backed.

### v0.5.12 (2026-09-16)

#### Fixed

- **A vintage with too few ratings is no longer reported as "not found".** Vivino stops publishing an average for a vintage until it has enough ratings, and it serves those pages in a different format. The Actor could not read the year off them, so it concluded the vintage did not exist and returned an error. Real vintages were lost this way: 13 of the 32 errors in a 175-wine reference run were wines the Actor had actually found. Those rows now come back complete, with the year, the wine's data and a rating you can use.
- **Ratings never borrow another wine's figures.** When a wine had no published average at all, the Actor could fall back to the average of its PRODUCER - a 4.7 from the estate presented as the rating of a wine Vivino rates at nothing. An average that Vivino does not publish is now simply absent, and a `ratings_average` of 0 is read as "no average", never as a rating of zero.
- **Misspelled and abbreviated inputs resolve.** Catalogue spellings that follow the sound ("reignard" for Reynard, "rotchild" for Rothschild) and estate abbreviations ("ch. Margaux", "dom. Leflaive") are understood. Your original wording is still what appears in `searchQuery`.
- **A blocked search is no longer reported as an absent wine.** "Not found" now requires that a search actually answered and that its answer was read. Rate limits, unreachable pages and anti-bot interstitials are reported as technical failures instead, so a batch worth replaying can be told apart from a wine Vivino does not have.
- Searches that returned no results stopped the whole lookup, cancelling the fallback strategies meant for exactly those queries. They now continue.

#### Added

- **`display_rating`, `display_ratings_count` and `display_rating_scope`.** A ready-to-show rating and its scope: the vintage's average when Vivino publishes one, otherwise the wine's average across all vintages. `display_rating_scope` tells you which of the two you got, so a 4.2 is never silently the wrong year's. The existing `average_rating` (vintage) and `wine_average_rating` (all vintages) columns keep their meaning.
- **`vintage_rating_status`.** Whether Vivino publishes an average for that vintage: `published`, `below_threshold` (the vintage exists, too few ratings) or `unavailable`. `below_threshold` is normal data, not an error.
- **`resolution_status` and `failure_reason`.** How your request was resolved - `matched`, `wine_only_fallback`, `ambiguous`, `not_found`, `fetch_failed` - and why, when it is not a match. Only `matched` rows are billed.
- **Wine-level results when a vintage cannot be confirmed.** If the wine is identified but the year you asked for cannot be confirmed, you now get the wine's information with `resolution_status: wine_only_fallback` and your year kept in `requested_vintage`, instead of an empty row. It does not mean Vivino lacks that year - the Actor also lands there when it has no usable page to check. These rows are never billed.
- **Ambiguous requests are flagged, not guessed.** A query naming only an appellation ("Margaux"), or a cuvee that exists in two colours when you did not specify one, returns the candidates unbilled and flagged `ambiguous` rather than silently picking one.
- `vintageId` is now populated on results resolved from a wine page.

#### Changed

- Requests that name a producer whose name the candidate does not carry ("Domaine des Tours" against "Baron des Tours") are refused instead of billed.
- Pages already downloaded during a search are reused rather than skipped, so a candidate is no longer lost because an earlier step had looked at it.
- The run summary reports the rating scopes, resolution statuses and failure reasons of the rows it produced.

### v0.5.11 (2026-08-11)

#### Fixed

- **You are no longer charged for a vintage you did not ask for.** When a request named a year, the Actor could return a different vintage of the same wine and bill it as a result. Three wines in our reference list did exactly that: a 2022 request came back as a 2004, a 2006 and a 2021, each with a price and a merchant link for the substituted year. Every path that resolves a wine now confirms the year before the row can be billed, and a request whose year cannot be confirmed returns an error row that costs nothing.
- **When another vintage exists, it is shown free of charge.** Vivino's answer for that wine is returned as an alternative row, flagged `isAlternative` and never billed. `requested_vintage` keeps the year you asked for, `vintage` is the year that row really describes. Price and merchant links are kept only when they can be attributed to that same year with certainty, and are `null` otherwise: a wine page can show one year in its title while pricing a different one, so we return no price rather than a price belonging to another vintage. When no coherent substitute year can be established, no alternative is added. A direct URL input never produces an alternative, it returns at most one row.
- **A cached result can no longer claim the wrong year.** Repeat runs replayed a stored resolution and labelled the row with the requested year without checking the page, so a substitution looked like an exact match. Cached rows now carry the year the page really shows, and the cache is only written for a confirmed year.

#### Changed

- A request without a year behaves exactly as before, and a wine whose year is already correct is returned without any extra page fetch.
- The run summary now reports how many requests were refused for an unconfirmed vintage and how many alternatives were returned.

### v0.5.10 (2026-08-03)

#### Changed

- **Runs now respect the timeout you set.** The Actor reads the run's deadline and keeps a reserve to write its results and its run summary before the platform stops the container. Requests, retries and waits are all capped by the time actually left: a request is never started with a longer timeout than the time remaining, and a retry whose full cooldown would not fit is skipped rather than shortened. Optional enrichment (taste profile, reviews) is skipped near the deadline so the wine itself is still returned. This is a best-effort improvement, not an absolute guarantee: an operation already in flight can still overrun.
- Previously the Actor assumed the default 3-hour timeout, so a run started with a shorter one could be cut off mid-flight, losing the unbilled skipped rows and the run summary.

### v0.5.9 (2026-08-03)

#### Fixed

- A wine is no longer matched to a different grape variety. A search for "Sauvignon Blanc" no longer returns a Cabernet Sauvignon, "Pinot Gris" no longer returns a Pinot Noir, and Sémillon is now recognised as a variety. Compound variety names are compared as a whole, so the shared word ("Pinot", "Sauvignon", "Cabernet") no longer makes two different grapes look like a match. Previously cached resolutions of this kind are invalidated.
- Entries such as "Patritti Fortified Shiraz 2018 - 500ml" no longer carry leftover punctuation into the search.
- When a producer name matches a winery in another country, the **Country Code** field now steers the search to the right producer. For example, with `AU` a search for Patritti reaches the Australian producer instead of its Argentinian namesake. Set Country Code to the wine's country of origin to benefit from this: the field defaults to `FR`, and the Ship To market is deliberately never used as a hint, since where you buy says nothing about where the wine is made. Leaving the default costs at most one extra lookup on searches that were already failing; it cannot produce a wrong match.

### v0.5.8 (2026-08-03)

#### Fixed

- Long name lists no longer stop matching part-way through. A safeguard meant to save time on lists that are mostly not wines could switch off the deeper search after the first few misses, so the rest of a legitimate list came back as "not found". The safeguard is gone: run length is now bounded only by the run's time budget, which already stops unproductive runs.
- A name that Vivino's search index did not immediately recognise is now searched in full instead of being declared "not found" straight away. That early exit also cached its verdict for a week, so the same wine kept failing on later runs. Both the early exit and the negative cache are removed. Wines listed under a slightly different producer spelling (for example "Peter Teakle" for a catalogue entry reading "Teakle Wines") are found again.

#### Changed

- **Error rows are never charged, whatever the cause.** Until now, a not-found that appeared confirmed by Vivino's search index counted as a billed result. A review of live runs showed some of those wines do exist under a different producer spelling, so that case has been removed. You pay only for wines actually returned.

### v0.5.7 (2026-07-20)

#### Fixed

- Alcohol content is now returned for wines resolved through Vivino's catalog search, not only for wines fetched by URL. When the catalog data lacks a detail the wine page displays (alcohol, images, food pairings, grape varieties, description), the Actor now reads it from the wine page and fills only the missing fields. Thanks to the user who reported the alcohol gap.

#### Changed

- Large name-search runs may take slightly longer, since filling the missing details requires one extra page read per wine that needs it. Wines that already carry their details are unaffected.

### v0.5.6 (2026-07-20)

#### Fixed

- When a requested vintage is not available for purchase and Vivino offers a different vintage instead ("The 2015 vintage is not available for purchase right now. But we have this 2016 vintage instead."), the `price` field is now `null` for the requested vintage rather than showing the substitute vintage's price. Ratings and the other wine details are unaffected. Thanks to the user who reported this with a precise reproduction.

### v0.5.5 (2026-07-15)

#### Fixed

- Searching for an estate whose flagship wine carries the estate's own name (for example `Antinori Guado al Tasso`) now returns that flagship instead of a rarer sibling cuvee from the same estate. Previously cached resolutions of this kind are invalidated.
- A producer search that includes a vintage year (for example `Chateau Palmer 2016`) now returns that producer's flagship wine as the single billed result, with other bottlings as unbilled alternative suggestions. Producer searches without a year keep returning the flagship plus its most popular bottlings, as documented.

### v0.5.4 (2026-07-08)

#### Fixed

- Long runs that keep returning wines are no longer stopped by the 60-minute safety cap: the cap now extends as results are delivered (up to a hard ceiling that still protects against runaway runs), so large Advanced batches complete. Runs that stop producing results are still cut short.
- Late-run recoveries of rate-limited names now pass the same strict matching gates as every other search path and honor the requested vintage: an uncertain recovery returns an unbilled error row, never a different (billed) wine.
- Rare blank pages served during anti-bot checks can no longer appear as billed near-empty results.
- A malformed entry in the legacy `wineNames` / `wineUrls` fields (for example a number instead of text) no longer fails the whole run: numbers are read as text and anything else is skipped with a warning.
- Requesting a proxy group your account cannot use no longer fails the run at startup: the Actor falls back to its direct IP, and the run summary now shows the requested group plus a `fallbackReason` so the degradation is visible.
- Error rows now report `ratings_count` as empty instead of 0, and reaching your run cost cap is no longer logged as a charge failure.
- Run summary counters are now exact when a run stops early (no more double-counted errors on a watchdog stop, and the number of processed inputs is reported truthfully when the cost cap is reached).
- Rate-limit detection got slightly sharper: the final retry attempt now counts toward the run's rate-limit statistics, improving both retry routing and the early-stop safeguard.
- Dependency security updates ship with this release.

#### Added

- The `OUTPUT` record documented in the storage schema (total wines, split by URL vs name input) is now actually written to the key-value store at the end of each run.

### v0.5.3 (2026-07-07)

#### Changed

- **Clearer, safer proxy behavior.** How the Actor reacts to Apify Proxy being enabled *without* an explicit proxy group has changed, so that turning proxy on can no longer quietly cost you or break a run:
  - **Proxy off (the default): unchanged.** The Actor uses its own IP, which is all a light or single run needs.
  - **Proxy on without choosing a group: now runs on the direct IP.** This is treated as an ambiguous setting. Previously such a run was routed through the premium residential pool automatically (paid bandwidth you did not ask for). Running on the direct IP is the same reliable path as leaving proxy off, so normal and solo runs succeed. (It is also why the Actor does not use Apify's default datacenter pool here: Vivino rejects datacenter IPs, so those runs could return no results.)
  - **Need real IP rotation for many runs in parallel?** Choose the Residential group explicitly with `apifyProxyGroups: ["RESIDENTIAL"]`. Residential proxy uses premium paid bandwidth, so reserve it for heavy or parallel runs.

### v0.5.1 (2026-07-07)

#### Fixed

- A run that hits a persistent rate-limit now stops early and cleanly instead of running until the platform timeout. The wines it could not reach are returned as unbilled rows (`WATCHDOG_SKIPPED`) to re-run later; you are never charged for a skipped wine.

### v0.5.0 (2026-07-02)

#### Added

- A search by a bare producer name (for example `Penfolds` with no specific wine) now returns the producer's flagship wine plus its most popular bottlings, up to three, instead of a single arbitrary wine. Each returned wine is a billed result. Searching for a specific wine (a producer plus a cuvee) is unchanged and returns that one wine.

### v0.4.98 (2026-07-01)

#### Fixed

- A wine query that repeats a word - most often a producer name entered twice (e.g. exported as "Gaja Gaja") - no longer fails to find the wine. Repeated words are collapsed before searching, so the query resolves the same as its clean form.

### v0.4.97 (2026-06-30)

#### Fixed

- Searching by a bare estate/producer name (for example `"Lafite"`) now returns the flagship Grand Vin instead of a more common second wine; the second wine is still included as an alternative result. Searching for a specific cuvée by name is unchanged.

### v0.4.96 (2026-06-30)

#### Fixed

- A query sent via the older single-query `searchQuery` field (for example `"Lafite 2020"`) was silently ignored, so the run finished with no results. The field is read again and the query is searched.

#### Changed

- The older `wineNames` / `wineUrls` / `searchQuery` input fields are deprecated in favour of the single `wines` field. Runs that still use only the old fields now use a faster, lighter "economy" search (it skips the deep retry passes), so they finish quicker and cheaper. Switch to `wines` for the full multi-strategy search.

### v0.4.95 (2026-06-29)

#### Changed

- Runs where most of the input doesn't match any Vivino wine now finish faster and cheaper: once a run is clearly dominated by no-match entries, the extra deep-search retries are skipped for the rest of that run. Lists that mostly match Vivino are unaffected - they keep the full search.

### v0.4.93 (2026-06-28)

#### Changed

- Repeated runs of the same wine list are now much faster and cheaper: once a name has been resolved, the result is cached, so a later run fetches the wine directly instead of repeating the multi-step search. Prices and ratings are still fetched fresh on every run.

### v0.4.92 (2026-06-28)

#### Fixed

- Inputs are now hard-capped at 250 entries total - across the wine list **and** the legacy name/URL fields - matching the documented limit. This prevents an oversized saved task from running an unbounded search. When an input exceeds the cap it is truncated to the first 250 and the run summary reports `received` / `processed` / `dropped` / `truncated`.

### v0.4.91 (2026-06-27)

#### Changed

- A name search that Vivino's own catalog confirms has no matching wine - a definitive "not on Vivino" answer (typically a non-wine query) - is now billed as one result, since the search work is performed and a conclusive answer is delivered. All other error rows remain free: a rate-limited search, an unmatched name that required the full fallback search, an invalid URL, or a fetch failure.

### v0.4.90 (2026-06-27)

#### Changed

- Name searches now detect up-front, with a single lookup, when a queried wine isn't on Vivino - instead of running the full search cascade - so those queries return faster. Wines that are on Vivino resolve exactly as before.

### v0.4.89 (2026-06-26)

#### Fixed

- Large batches of wines no longer risk running out of memory mid-run. Memory is now bounded during big runs, so lists that previously failed on larger inputs complete reliably.

### v0.4.88 (2026-06-26)

#### Fixed

- Saved tasks and API/integration runs that still send the older `wineNames` or `wineUrls` input fields now return results again. They were being silently ignored, producing an empty run. The single `wines` field remains the recommended input.

### v0.4.87 (2026-06-25)

#### Changed

- Rows for inputs with no Vivino match now show `name` and `winery` as "Not found" instead of appearing blank, and the default Overview table surfaces the error reason. These rows are still never billed.

### v0.4.86 (2026-06-25)

#### Fixed

- Bottle and label image URLs now populate reliably, including wines for which Vivino omits the standard share image.

### v0.4.85 (2026-06-25)

#### Fixed

- `average_rating` now reflects the specific wine rather than the producer's catalog-wide average.

### v0.4.84 (2026-06-25)

#### Fixed

- `ratings_count` now reflects the specific wine instead of the producer's total across all of their wines. Vintage-level figures (`average_rating` / `ratings_count`) and wine-level figures (`wine_average_rating` / `wine_ratings_count`) are now clearly distinct.

### v0.4.83 (2026-06-24)

#### Fixed

- Better recovery of estate wines that Vivino lists under the producer's name without the "Domaine" prefix (for example Paul Pillot or Ramonet), with the same guarantee that an uncertain name never bills a different wine.

### v0.4.80 (2026-06-24)

#### Added

- Name matching now recovers confidential cuvées from well-known estates (a grower's Bourgogne Aligoté, a single-vineyard bottling, and similar) that Vivino's search and browse pages bury. An unresolved or ambiguous name still returns an unbilled error row, never a mismatched wine.

### v0.4.74 (2026-06-17)

#### Added

- When a Basic name search finds nothing, the Actor now automatically retries in Advanced mode, recovering more grower and micro-domaine wines without a manual re-run.

### v0.4.73 (2026-06-16)

#### Added

- Optional proxy configuration, so several batches can run in parallel without sharing a single IP (which Vivino rate-limits).

### v0.4.72 (2026-06-14)

#### Added

- Vintage fidelity on name searches: when you request a specific year, the price, rating, and image are pinned to that vintage whenever Vivino confirms it, and never mislabeled.

### v0.4.71 (2026-06-14)

#### Fixed

- More precise name matching: grape conflicts (such as Riesling vs Pinot Gris) and hyphenated producer names (such as Jean-Marie) no longer cause mismatches.

### v0.4.68 (2026-06-13)

#### Added

- Second-pass recovery for difficult names: a producer-index lookup and a rate-limit retry recover wines the first search pass misses.

### v0.4.45 – v0.4.67 (June 2026)

#### Changed

- Matching-engine overhaul: a multi-strategy name-search cascade (winery slug, producer page, and search-entry fallbacks) with shared anti-mismatch gates, so an uncertain name becomes an unbilled error row rather than a wrong (billed) wine.
- Localization: `shipTo`, `countryCode`, and `currencyCode` deliver market-specific prices and availability.
- Output expanded with grape varieties, food pairings, alcohol, market price and discount fields, and a value-for-money score.

### v0.4.12 – v0.4.18 (June 2026)

#### Fixed

- Billing accuracy: error rows (no match, invalid URL, fetch failure) and alternative candidates are never charged; you pay only for one primary result per input.
- `image_url` is always returned as a string, and empty values are normalized to `null`.

### v0.2 – v0.4 (March – June 2026)

#### Added

- Initial release: HTTP-only Vivino extraction by wine name or URL (or a mix), returning ratings, prices, taste profiles, reviews, and full wine details in JSON, CSV, Excel, or XML.
- Pay-per-event pricing (per result returned), result caching, and a run summary written to the Key-Value Store.
