Vivino Wine Scraper $1.2💰 Ratings, Prices, Reviews & Offers
Pricing
from $1.20 / 1,000 wine results
Vivino Wine Scraper $1.2💰 Ratings, Prices, Reviews & Offers
From $1.2/1K. Scrape Vivino.com for wine ratings, prices, taste profiles, food pairings, grapes, and reviews. Search by wine names or URLs, or discover wines by type, price, rating, country, and grape. Returns 50+ fields, including multi-merchant offers and value scores.
Pricing
from $1.20 / 1,000 wine results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
5
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Vivino Scraper: Wine Ratings, Prices and Tasting Notes
Vivino Scraper turns Vivino into structured wine data you can pull on demand. Look up wines by name or paste Vivino links, or skip the list entirely and discover wines by type, price, rating, origin country and grape with full sorting. Records carry ratings, multi merchant prices, Vivino's value and competitiveness scores where Vivino lists offers, plus a taste profile by default and optional reviews, then export to JSON, CSV or Excel, or read the results straight through the API.
Why This Scraper?
- Two ways to find wines. Paste an exact list of names and/or Vivino URLs (one record each), or set filters and a sort order and let the actor walk the catalog for you.
- 50+ fields per wine, including a full taste profile, multi merchant price offers, and Vivino's value and competitiveness scores.
- Real discovery filters and sort. Wine type, minimum rating, price range, origin country and grape, sorted by rating, price, popularity or biggest discount first.
- Enrichment on demand. Taste profile (acidity, tannins, sweetness, intensity, flavor notes) is fetched by default and can be turned off; user reviews are off by default and can be turned on. Any wine that gets either adds one combined enrichment charge, not two.
- Market aware. Choose the pricing country and currency, and echo a ship-to country on every record.
- Resume and recurring updates. One interrupted run resumes automatically, and Incremental mode returns only new and updated wines by default on every scheduled run.
- Resilient connections. A refused request is retried on a different connection automatically, and repeated refusals escalate to a more reliable connection for the rest of the run, no extra setup needed.
Use Cases
- Wine shops and marketplaces: track competitor pricing, discounts and merchant offers for the wines you carry.
- Wine apps and recommendation engines: build a searchable catalog with ratings, taste profiles and food pairings.
- Price and deal monitoring: schedule Incremental mode against a watch list and get only the wines whose price, rating or availability changed.
- Sommeliers and content teams: pull tasting notes, food pairings and reviews to write wine guides and shelf talkers.
- Market research and data science: build historical rating and pricing datasets across countries and currencies.
Data You Get
Sample shape: values are illustrative placeholders, not from a live record.
| Field | Example |
|---|---|
wineId | 1234567 |
vintageId | 89012345 |
name | "Sample Winery Reserve Red 2019" |
winery | "Sample Winery" |
vintage | 2019 |
wine_type | "Red" |
region | "Sample Region" |
country | "France" |
country_code | "fr" |
appellation | "Sample Appellation" |
grape_varieties | ["Cabernet Sauvignon", "Merlot"] |
average_rating | 4.3 |
ratings_count | 1200 |
price | 49.9 |
currency | "EUR" |
merchant_url | Vivino checkout link for the matched merchant offer |
vfm_score / vfm_category | 4.1 / "great" (Vivino's value-for-money score and label) |
is_natural | false |
image_url | "https://images.vivino.com/thumbs/000000000_pb_x960.png" |
food_pairings | ["Beef", "Lamb", "Game"] |
description | Style description text |
taste_profile | { body, acidity, tannins, sweetness, fizziness, intensity, flavor_notes, flavor_groups } (when enabled) |
reviews | [ { rating, note, language, user_name, created_at } ] (when enabled) |
prices | [ { amount, currency, merchant_url, discount_percent } ], every merchant offer for this vintage |
vivino_url | "https://www.vivino.com/sample-winery-reserve-red/w/1234567" |
Every record also carries the wine's overall, all-vintage rating separately from this vintage's rating (wine_average_rating, wine_ratings_count), the full pricing detail behind the headline price (discounted_from, discount_percent, discount_amount, is_on_sale, bottle_volume_ml), Vivino's competitiveness score and tier (cmp_score, cmp_tier), a larger label image (label_image_url), winery identity and status (winery_id, winery_seo_name, winery_status), region identity (region_id, region_name_en), style copy (style_name, body_description, acidity_description, varietal_name, regional_name, interesting_facts, blurb), Vivino's own wine rank (vivino_rank), and provenance fields describing how the row was produced rather than the wine itself (matchScore, isAlternative, requested_vintage, searchQuery, shipTo, inputSource, scrapedAt). Three fields, alcohol, lwin and lwin_canonical, are reserved for data not yet populated and are currently always empty.
How to Use
- Pick a Mode:
lookup(exact wines by name or URL) ordiscovery(find wines by filter and sort). - In lookup mode, list wine names and/or Vivino URLs. In discovery mode, set your filters and sort order instead.
- Turn on taste profile and/or reviews if you want them, set the market country and currency, and set Max wines to control run size and cost.
- Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.
Look up wines by name:
{"mode": "lookup","wines": ["Opus One 2019", "Dom Pérignon", "Cloudy Bay Sauvignon Blanc"],"countryCode": "US","currencyCode": "USD"}
Look up wines by URL, with taste profile and reviews:
{"mode": "lookup","wines": ["https://www.vivino.com/cloudy-bay-sauvignon-blanc/w/18978","https://www.vivino.com/chateau-margaux-premier-grand-cru-classe/w/1127795?year=2015"],"includeTasteProfile": true,"includeReviews": true,"maxReviewsPerWine": 20}
Discover top rated French reds between 50 and 150, sorted by rating:
{"mode": "discovery","wineTypes": ["Red"],"originCountries": ["fr"],"minRating": 4,"priceMin": 50,"priceMax": 150,"sortBy": "rating_desc","countryCode": "US","currencyCode": "USD","maxItems": 50}
Recurring monitoring of a watch list (schedule this daily):
{"mode": "lookup","wines": ["https://www.vivino.com/cloudy-bay-sauvignon-blanc/w/18978?year=2022"],"incrementalMode": true,"stateKey": "my-watchlist"}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/vivino-wine-data-scraper").call(run_input={"mode": "lookup", "wines": ["Opus One 2019"]})for wine in client.dataset(run["defaultDatasetId"]).iterate_items():print(wine["name"], wine["average_rating"], wine["price"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/vivino-wine-data-scraper').call({ mode: 'lookup', wines: ['Opus One 2019'] });const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Resume and recurring updates
There are two different things here, pick the one that matches what you're doing:
| Need | Use |
|---|---|
| A run stopped and should continue | resumeFromRunId (or the automatic same-run checkpoint, no input needed) |
| Run the same wine list or discovery filters on a schedule and receive only changes | incrementalMode |
| Keep separate monitoring campaigns for similar searches | distinct stateKey values |
| Run a normal full snapshot | leave both off |
Resume (resumeFromRunId) continues one specific interrupted or previous run: paste a run ID or dataset ID and this run skips wines already collected there, returning only the remaining new ones. An automatic same-run checkpoint also protects against platform migrations, so a run that is restarted by the platform continues from where it left off with no extra input.
Incremental mode (incrementalMode) is for a schedule, for example daily: the actor remembers the previous run of the same wine list or discovery filters by itself, so you never paste a run ID. The first run returns everything as NEW. Later runs return only NEW and UPDATED wines by default; unchanged wines are suppressed and not billed. REAPPEARED only appears after an earlier run with emitExpired on and a complete scan tombstoned the wine as gone. Turn on emitUnchanged or emitExpired only when you also want those rows returned, and billed for. State is isolated per wine list, discovery filter set and enrichment setup automatically; set stateKey to name or deliberately share a monitoring campaign.
Every record returned in incremental mode also carries:
| Field | Description |
|---|---|
changeType | NEW, UPDATED, UNCHANGED, REAPPEARED, or EXPIRED |
changedFields | Top-level fields that changed since last seen; non-empty only for UPDATED |
firstSeenAt | When this wine was first observed by this monitoring campaign |
lastSeenAt | When this wine was last observed |
REAPPEARED and EXPIRED are not everyday outcomes. EXPIRED is only produced once a run has completely scanned its tracked wines or filters, meaning nothing was capped by maxItems, no resumeFromRunId was used, and every list entry or catalog page was actually reached. A capped run, a resumed run, or a run where even one wine could not be resolved leaves EXPIRED detection switched off for that run, so a wine that was merely unreachable this time is never wrongly reported as gone. REAPPEARED only follows an earlier run that genuinely marked a wine EXPIRED.
Read this before you schedule a discovery run: Vivino's answers vary per request
Vivino tailors what it returns to where the request appears to come from, and that location is not guaranteed to be identical from one run to the next. Two things follow, both measured on this actor across several back to back identical runs of a small discovery walk minutes apart:
- The discovery result set itself can move. Repeated identical runs can return different sets of wines.
- A wine that does appear on two runs can come back as a different vintage from a different merchant, reported
UPDATEDwithchangedFieldsnaming price and identity fields together, then flip back on a later run.
So a scheduled discovery run can report, and bill, a real share of NEW and UPDATED rows every time. That is variance in what Vivino serves, not a fault in change detection: the actor is correctly reporting that the record it just received is not the record it stored.
For stable, low noise scheduled monitoring:
- Prefer lookup mode over discovery mode. Give an explicit wine list, and ideally paste Vivino URLs carrying a
?year=, which pins the vintage and removes most of the churn above. - Set
countryCodeandcurrencyCodeexplicitly and keep them identical on every run of a campaign. - Choose the Residential connection option and pin its country to that same
countryCode, so requests stay inside one market instead of moving between markets. - Read
changedFieldsbefore acting on a row. A row whosechangedFieldsnamesvintage,vintageIdornameis a different vintage of the same wine, not a change to the wine you were watching. - Leave
emitUnchangedoff, the default, so wines that genuinely did not move are neither returned nor billed.
Send results into your apps (MCP connectors)
Optionally pipe each record into the apps you already use, through Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each wine, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify, Settings, API & Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. If the picker is empty, you haven't authorized a connector yet.
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | lookup | lookup: scrape the exact wines you list. discovery: find wines by filter and sort. |
wines | array | none (prefill: ["Dom Pérignon", "Opus One 2019", "https://www.vivino.com/cloudy-bay-sauvignon-blanc/w/18978"]) | Lookup mode: mixed list of wine names and Vivino URLs, one record each. |
searchMode | string | auto | Vintage handling for name lookups: auto, name_and_vintage, name_only. |
matchingMode | string | basic | basic takes the top match. advanced also surfaces one alternative candidate, a normal row that counts toward Max wines, gets the same enrichment, and is billed the same as any other row. |
wineTypes | array | [] (all types) | Discovery filter: Red, White, Sparkling, Rosé, Dessert, Fortified. |
minRating | integer | none | Discovery filter: minimum Vivino average rating (1 to 5). |
priceMin | integer | none | Discovery filter: lowest price in the selected currency. |
priceMax | integer | none | Discovery filter: highest price in the selected currency. |
originCountries | array | [] (all) | Discovery filter by wine origin, ISO alpha-2 codes, e.g. fr, it, us. |
grapes | array | [] (all) | Discovery filter by Vivino grape IDs. |
sortBy | string | relevance | relevance, rating_desc, rating_asc, price_asc, price_desc, popularity, discount_desc. |
countryCode | string | FR | Market country for pricing and availability, ISO alpha-2. |
currencyCode | string | EUR | Currency for prices, ISO 4217. |
shipTo | string | none | Optional ship-to country, echoed on each record. |
includeTasteProfile | boolean | true | Fetch acidity, tannins, sweetness, fizziness, intensity and flavor notes (body is currently always empty). |
includeReviews | boolean | false | Fetch user reviews per wine. Increases run time and cost. |
maxReviewsPerWine | integer | 10 | Maximum reviews per wine when reviews are enabled (1 to 100). |
maxItems | integer | 20 | Caps the total wine records returned. Set 0 for unlimited. |
maxPages | integer | none (unlimited, walks every result page) | Discovery mode only: optional bound on pages walked. The run still stops at Max wines. |
proxy | object | Apify Proxy (default group) | Connection settings. Choose Residential for higher reliability on large or frequent runs. |
mcpConnectors | array | none | Optional: send a summary of each record to apps you authorized under Integrations. |
notionParentPageUrl | string | none | Notion connector only: page under which records are created. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run. Does not affect the dataset. |
resumeFromRunId | string | none | Continue one specific previous run or dataset: wines already collected there are skipped, so this run only appends new ones. |
incrementalMode | boolean | false | Daily or recurring monitoring of the same wine list or discovery filters. Returns only new and updated wines on later runs by default; reappeared wines only after an earlier emitExpired run has marked one gone. |
stateKey | string | none | Optional name for a monitoring campaign, so its incremental state stays stable or is deliberately shared. Auto-derived when left empty. |
emitUnchanged | boolean | false | Incremental mode only. Also return wines unchanged since the last run, marked UNCHANGED. Adds and bills extra rows you already have. |
emitExpired | boolean | false | Incremental mode only. Also return wines from a previous run no longer found, marked EXPIRED, once a run has fully scanned the tracked wines or filters. Adds and bills extra synthetic rows. |
Output Example
Sample shape: values are illustrative placeholders, not from a live record.
{"wineId": 1234567,"vintageId": 89012345,"name": "Sample Winery Reserve Red 2019","winery": "Sample Winery","vintage": 2019,"wine_type": "Red","region": "Sample Region","country": "France","country_code": "fr","grape_varieties": ["Cabernet Sauvignon", "Merlot"],"average_rating": 4.3,"ratings_count": 1200,"price": 49.9,"currency": "EUR","vfm_category": "great","is_natural": false,"food_pairings": ["Beef", "Lamb"],"taste_profile": {"body": null,"acidity": 3.1,"tannins": 3.8,"sweetness": 1.6,"fizziness": null,"intensity": 3.7,"flavor_notes": ["black fruit", "oak", "leather"]},"reviews": [{ "rating": 4.5, "note": "Sample review text.", "language": "en", "user_name": "reviewer", "created_at": "2026-01-01T00:00:00.000Z" }],"vivino_url": "https://www.vivino.com/sample-winery-reserve-red/w/1234567","scrapedAt": "2026-01-01T00:00:00.000Z","inputSource": "search"}
Plan Requirement
The default connection setting works without any extra configuration, and the actor automatically switches to a different connection when a request is refused. For large or frequent discovery runs, choosing the Residential option under Connection gives the most consistent pricing and match results.
FAQ
How much does it cost?
You pay per record returned, plus one combined enrichment charge for any wine that gets taste profile (on by default) or reviews (off by default). The Pricing tab shows the current rates. Use Max wines to cap the cost of any run.
Is it legal to scrape Vivino?
This actor collects only publicly available wine data. You are responsible for how you use it: follow Vivino's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Ratings and prices are generally facts, but labels, photos and review text may be subject to third-party rights.
Can I get only new or changed wines on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated wines by default, plus reappeared wines once an earlier run with Emit expired on has marked one gone, and unchanged ones are not billed. Lookup mode with pinned-vintage URLs gives the most stable results; see "Read this before you schedule a discovery run" above if you're scheduling discovery mode.
Why does a scheduled discovery run keep reporting changes even when nothing looks different?
Vivino answers from the location a request appears to come from, so a discovery walk run minutes apart can return a different set of wines, or quote the same wine as a different vintage from a different merchant. That reads as UPDATED because the record genuinely differs from what was stored, not because change detection is wrong. Pin your market with countryCode/currencyCode and a Residential connection, or switch to lookup mode with ?year= URLs, to reduce it.
Why did my run fail instead of returning an empty dataset?
A run fails only when it cannot even get started correctly, for example an invalid resumeFromRunId that cannot be resolved, or combining incrementalMode with resumeFromRunId once that campaign already has saved state. A wine that simply could not be matched, or a discovery page that could not be fetched, does not fail the run: it is skipped, logged, and reported in the run's status message and log, while every other wine is still returned.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.
🔗 Want more wine and drinks data?
Pair this actor with these related scrapers from the same team:
| 🍷 Wine-Searcher Scraper Look up wines on wine-searcher.com by name, URL, or LWIN code. Returns 30+ fields... | 🍷 Dan Murphy’s Scraper Scrape Dan Murphy’s products by category, keyword, or specials. Extract 45+ fields... |
| 🍷 Untappd Beer, Brewery and Check-in Scraper Scrape Untappd beers, breweries, venues and check-ins by keyword, brewery, Top Rated... | 🥦 ResQ Club Scraper Scrape ResQ Club surplus food offers in Finland, Sweden and Estonia: name, price, current... |
| 🥦 Coles AU Scraper Scrape Coles.com.au grocery products and customer reviews. Search by keyword, browse... | 🥦 FoodHero Scraper Scrape FoodHero surplus grocery deals across Canada by area, store or offer ID. Extract... |
💬 Support
- 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- 🛠️ Need another site, extra fields or a private build? Email contact@abotapi.com.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.