Wine-Searcher Scraper | Wine Prices, Scores, Offers & LWIN
Pricing
from $1.50 / 1,000 wine results
Wine-Searcher Scraper | Wine Prices, Scores, Offers & LWIN
Look up wines on wine-searcher.com by name, URL, or LWIN code. Returns 30+ fields, including critic scores, prices, grape, region, appellation, producer, label image, user ratings, food pairing, live offer counts, cheapest merchant offer, and optional critic review breakdown.
Pricing
from $1.50 / 1,000 wine results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
2
Bookmarked
29
Total users
5
Monthly active users
4.4 hours
Issues response
15 hours ago
Last modified
Categories
Share
Wine-Searcher Scraper: Scores, Prices & Popularity
Look up any wine on Wine-Searcher and get a clean, structured record back. Give the actor a list of wine names, Wine-Searcher links, or LWIN codes and it returns critic scores, average and market prices, grape, region, appellation, producer, label image, user ratings and live offer counts as JSON or CSV. Built for merchants, collectors, sommeliers and market analysts who need Wine-Searcher data in a spreadsheet or pipeline instead of a browser tab.
Why this scraper
- Three input styles in one actor: wine names, Wine-Searcher URLs, or LWIN codes (LWIN7 / 11 / 16 / 18), with automatic detection so you can mix them.
- Richer output than a plain price lookup: 30+ fields per wine, including user ratings, food pairing, region and origin, that other tools drop.
- Cheapest live offer with the merchant name when you enable offer extraction, plus the total number of offers worldwide.
- Optional per-critic review breakdown (reviewer name and score) when you enable review collection.
- Looks up several wines in parallel, over several connections at once on long lists, so a few-hundred-wine list finishes in minutes rather than hours.
- Long lists keep going: the actor re-establishes its connection as often as it needs to, and a wine that could not be read on one connection is retried on the next instead of being abandoned with the rest of the list.
- Pay only for wines actually found. Not-found and unavailable items are flagged separately and do not count.
- Currency context follows the proxy country (France / EUR by default), so prices match the market you care about.
- Optional one-click export of every result into Notion, Linear, Airtable or Apify through MCP connectors.
Data you get
Sample shape, values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
wineName | 2015 Sample Wine, Pomerol, France |
vintage | 2015 |
appellation | Pomerol, France |
region | Pomerol |
grapeVariety | Merlot |
style | Red - Savoury and Classic |
producer | Sample Producer |
description | Short producer / wine description text. |
score | 97 |
scoreBestRating | 100 |
criticReviewsCount | 20 |
criticReviews | [{ "author": "Sample Critic", "score": 95, "bestRating": 100, "tastingNote": "..." }] |
avgPrice | 5076 |
avgPriceCurrency | EUR |
cheapestPriceAmount | 3400.00 |
cheapestPriceCurrency | EUR |
cheapestPriceMerchant | Sample Merchant |
cheapestPriceMerchantUrl | https://www.example.com/wine/0000 |
bottlesPerUnit | 1 |
offers | [{ "price": 3400.0, "priceCurrency": "EUR", "merchant": "Sample Merchant", "merchantUrl": "...", "unitDescription": "Bottle (750ml)", "bottlesPerUnit": 1, "availability": "InStock" }] |
offersCount | 13 |
highestPriceAmount | 4500.00 |
highestPriceCurrency | EUR |
medianPriceAmount | 3800.00 |
merchantCount | 11 |
labelImageUrl | https://www.wine-searcher.com/images/labels/00/00/000000000.jpg |
wineSearcherUrl | https://www.wine-searcher.com/find/sample/2015 |
searchLocation | France |
scrapedAt | 2026-01-01T00:00:00.000Z |
The full record, including the complete offers array (every merchant, price and link) and the criticReviews breakdown with tasting notes, is always kept in the Apify dataset.
Specials, was-price & discount
Wine-Searcher is a price-comparison site, not a retail store. It lists merchant offers at face value and does not have a specials, deals, or clearance taxonomy, nor a was/original/list price or discount field on any offer. The price spread between merchants is not a discount: it reflects different merchants, bottle sizes, vintages, and stock conditions.
No wasPrice, savingsAmount, savingsPercent, isOnSpecial, or specialsCategory field is emitted, because none exists on the site. Wine-Searcher's "best value" and critic scores are ratings, not discounts.
Instead, the actor ships merchant-price-spread statistics computed from the already-fetched offers list:
| Field | Description |
|---|---|
cheapestPriceAmount | Lowest offer price exactly as a merchant lists it (long-standing field, meaning unchanged). |
highestPriceAmount | Highest price per standard 750ml bottle (see the basis note below). |
highestPriceCurrency | Currency of that highest per-bottle price. |
medianPriceAmount | Median price per standard 750ml bottle, same basis as highestPriceAmount. |
merchantCount | Number of distinct merchants offering this wine. |
offersCount | Total number of merchant offers (already shipped). |
Basis note (important). A wine's offers mix formats: single bottles, magnums, half bottles, and multi-bottle cases, and a case offer's listed price is the case total. Comparing those numbers at face value is meaningless, so highestPriceAmount and medianPriceAmount are normalised to one standard 750ml bottle: a case is divided by its bottle count (a case of 6 listed at 30,204 counts as 5,034 per bottle, not 30,204), and non-750ml formats such as magnums are left out of the comparison entirely. These two fields are therefore a like-for-like per-bottle comparison, not necessarily a price you can click and buy. If a wine has no standard-bottle offer at all, both are null. cheapestPriceAmount is untouched and keeps its original meaning (the lowest listed offer price).
These are price-spread fields for comparison across merchants, not discount fields. They are populated when fetchOffers is on and null otherwise.
How to use
Look up by wine name (auto-detected):
{"inputType": "auto","wineNames": ["Petrus 2015", "Dom Perignon 2013"],"maxItems": 20}
Look up by LWIN code:
{"inputType": "lwins","lwins": ["11316442021", "11084042019"]}
Look up by Wine-Searcher URL, fastest mode (no offer extraction):
{"inputType": "urls","urls": ["https://www.wine-searcher.com/find/sassicaia/2019"],"fetchOffers": false}
Pin a different currency market (United Kingdom / GBP):
{"inputType": "auto","wineNames": ["Sassicaia 2019"],"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "GB" }}
Resume & recurring tracking
Resume from a previous run (resumeFromRunId) is a one-off delta: give it a previous run or dataset ID and this run skips wines already collected there, looking up only the rest of your list. Useful for finishing a large list across several runs without re-paying for wines you already have.
Incremental mode (incrementalMode) is for a wine list you run on a schedule (daily/weekly) to track changes over time - critic score moved, price shifted, a merchant added or dropped an offer. Every wine is classified:
changeType | Meaning |
|---|---|
NEW | Never seen under this State key before. |
UPDATED | Something changed since last time - changedFields names which top-level fields. |
UNCHANGED | Identical to last time. Suppressed (not pushed, not billed) unless emitUnchanged is on. |
REAPPEARED | Was EXPIRED, now found again. |
EXPIRED | Tracked before, not found this run. Only reported when emitExpired is on AND this run completed a full scan of your list (no Resume, no cap, no connection ceiling cut it short). |
State is kept in a separate key-value store, keyed by stateKey (or an auto-derived hash of your exact wine list when left empty) - it never re-visits wine-searcher.com, so checking state costs no extra proxy/solver spend. A page-order-only difference in offers/criticReviews never counts as a change (see the code comments in src/incremental.py for what is and isn't proven about field volatility here).
⚠️ The auto-derived key is built from your wine list itself, so editing the list (adding or removing a wine) also changes the auto key and starts a fresh baseline - convenient if you always re-run the identical list, but it means emitExpired can never report a wine you removed as EXPIRED under the auto key. If you intend to grow/shrink your tracked list over time and still want removed wines reported, set your own fixed stateKey so every run shares one baseline regardless of list edits.
{"inputType": "auto","wineNames": ["Petrus 2015", "Opus One 2019"],"incrementalMode": true,"emitExpired": true}
Long runs (large lists) also survive a platform migration or a manual Resurrect automatically: progress is checkpointed periodically, so a resumed attempt of the same run does not re-look-up (or re-charge for) wines it already extracted.
Send results into your apps (MCP connectors)
Optionally pipe every result into the tools you already use, no code required:
- Authorize a connector under Apify, Settings, API & Integrations (Notion, Linear, Airtable or Apify).
- Select it in the
mcpConnectorsinput. For Notion, also setnotionParentPageUrl. - Run the actor. Results are written to the connector after the dataset is saved.
The connector receives a condensed, human-readable summary per wine (a title plus the key fields). The complete record always stays in the Apify dataset. Leaving mcpConnectors empty skips this entirely and never changes the dataset output.
Input parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputType | string | auto | auto, wineNames, urls, or lwins. Auto-detect routes each item by its shape. |
wineNames | array | (none) | Wine names, ideally with vintage year. Up to 1000. |
urls | array | (none) | Wine-Searcher find URLs. Up to 1000. |
lwins | array | (none) | LWIN codes (7 / 11 / 16 / 18 digit). Up to 1000. |
fetchOffers | boolean | false | Also extract the cheapest offer, the full offers list and popularity. Slightly slower per wine. |
fetchReviews | boolean | false | Also collect the per-critic review breakdown (reviewer name and score). |
concurrency | integer | 3 | Deprecated and ignored. Lookup parallelism is managed automatically. |
maxItems | integer | 20 | The single cap: process at most this many wines. 0 means no limit. |
proxy | object | Residential FR | Residential proxy required. Country sets the price-currency context. |
mcpConnectors | array | (none) | Optional MCP connectors to export results to. |
notionParentPageUrl | string | (none) | Parent Notion page for the Notion export. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run. |
Output example
Sample shape, values are illustrative placeholders, not from a live listing.
{"inputValue": "Petrus 2015","inputType": "wineNames","wineSearcherUrl": "https://www.wine-searcher.com/find/sample/2015","wineName": "2015 Sample Wine, Pomerol, France","vintage": 2015,"appellation": "Pomerol, France","region": "Pomerol","grapeVariety": "Merlot","style": "Red - Savoury and Classic","producer": "Sample Producer","description": "Short producer / wine description text.","score": 97,"scoreBestRating": 100,"criticReviewsCount": 20,"criticReviews": [{ "author": "Sample Critic", "score": 95, "bestRating": 100, "tastingNote": "Tasted: Jan 2018. ..." }],"avgPrice": 5076,"avgPriceCurrency": "EUR","cheapestPriceAmount": 3400.0,"cheapestPriceCurrency": "EUR","cheapestPriceMerchant": "Sample Merchant","cheapestPriceMerchantUrl": "https://www.example.com/wine/0000","bottlesPerUnit": 1,"offers": [{ "price": 3400.0, "priceCurrency": "EUR", "merchant": "Sample Merchant", "merchantUrl": "https://www.example.com/wine/0000", "unitDescription": "Bottle (750ml)", "bottlesPerUnit": 1, "availability": "InStock" }],"offersCount": 13,"highestPriceAmount": 4500.0,"highestPriceCurrency": "EUR","medianPriceAmount": 3800.0,"merchantCount": 11,"labelImageUrl": "https://www.wine-searcher.com/images/labels/00/00/000000000.jpg","searchLocation": "France","scrapedAt": "2026-01-01T00:00:00.000Z"}
Long lists
There is no separate setting for this: set maxItems to the size of your list and the actor sizes
itself. It reads a batch of wines per connection, then opens a fresh one and carries on, running up
to three connections at once once it has confirmed the site is reachable. A run that genuinely
cannot reach the site still stops within a few seconds and reports a connection problem rather than
an empty result, so a total block never looks like "your list matched nothing".
Plan requirement
Wine-Searcher only accepts residential connections, so this actor needs Apify Residential proxy (Starter plan or higher). On a free plan without residential access the run will return no data. The default pins France for EUR pricing; change the proxy country to switch the price-currency market. Critic scores and average price are always included; the full offers list and popularity rank are included when you enable offer fetching, and the per-critic review breakdown with tasting notes is included when you enable review collection.