Vivino Wine Scraper $1.2💰 Ratings, Prices, Reviews & Offers avatar

Vivino Wine Scraper $1.2💰 Ratings, Prices, Reviews & Offers

Pricing

from $1.20 / 1,000 wine results

Go to Apify Store
Vivino Wine Scraper $1.2💰 Ratings, Prices, Reviews & Offers

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

Abot API

Maintained by Community

Actor stats

1

Bookmarked

5

Total users

1

Monthly active users

14 days ago

Last modified

Share

Vivino Wine Data Scraper

Pull structured wine data from Vivino: ratings, prices, taste profiles, food pairings, grapes, value scores, and user reviews. Look up a list of wine names or paste Vivino URLs, or skip the list entirely and discover wines by type, price, rating, origin country, and grape, with full sorting. Fast, returns clean ready-to-use fields, and runs on any Apify plan.

Why this scraper

  • Two ways to work: a mixed list of wine names and URLs (one record each), or a filter-and-sort discovery mode that walks the catalog with no list at all.
  • 50+ fields per wine, including a full taste profile, multi-merchant price offers, and Vivino value and competitiveness scores.
  • Real filters and real sort: wine type, minimum rating, price range, origin country, grape, sorted by rating, price, or popularity.
  • Optional taste profile and user reviews per wine (reviews keep the language, reviewer alias, and tagged note).
  • Market aware: choose the pricing country and currency, and echo a ship-to country on every record.
  • Low cost and reliable: runs on every Apify plan, with automatic retries for large jobs.
  • Resume & recurring updates: turn on Incremental mode to get only NEW, UPDATED, and REAPPEARED wines on every scheduled run, or resume one specific interrupted run with resumeFromRunId.

Data you get

Sample shape, values are illustrative placeholders, not from a live listing.

FieldExample
wineId1234567
vintageId89012345
nameSample Winery Reserve Red 2019
winerySample Winery
vintage2019
wine_typeRed
regionSample Region
countryFrance
country_codefr
appellationSample Appellation
grape_varieties["Cabernet Sauvignon", "Merlot"]
average_rating4.3
ratings_count1200
wine_average_rating4.2
wine_ratings_count25000
price49.9
currencyEUR
merchant_urlhttps://www.vivino.com/checkout/...
discount_percent10
bottle_volume_ml750
vfm_score4.1
vfm_categorygreat
cmp_score3.8
is_naturalfalse
image_urlhttps://images.vivino.com/thumbs/000000000_pb_x960.png
label_image_urlhttps://images.vivino.com/thumbs/000000000_pl_375x500.png
food_pairings["Beef", "Lamb", "Game"]
descriptionStyle description text appears here.
taste_profile{ body, acidity, tannins, sweetness, fizziness, intensity, flavor_notes, flavor_groups }
reviews[ { rating, note, language, user_name, created_at } ]
prices[ { amount, currency, merchant_url, discount_percent } ]
vivino_urlhttps://www.vivino.com/sample-winery-reserve-red/w/1234567?year=2019

How to use

Look up wines by name (one record per wine you list):

{
"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 (collects up to maxItems):

{
"mode": "discovery",
"wineTypes": ["Red"],
"originCountries": ["fr"],
"minRating": 4,
"priceMin": 50,
"priceMax": 150,
"sortBy": "rating_desc",
"countryCode": "US",
"currencyCode": "USD",
"maxItems": 50
}

Input parameters

ParameterTypeDefaultDescription
modestringlookuplookup: scrape the wines you list. discovery: find wines by filter + sort.
winesarraysampleLookup mode: mixed list of wine names and Vivino URLs (one record each).
searchModestringautoVintage handling for name lookups: auto, name_and_vintage, name_only.
matchingModestringbasicbasic takes the top match; advanced also surfaces one alternative candidate. The alternative is a normal record: it counts toward maxItems, gets the same taste/reviews enrichment, and is billed the same as any other row.
wineTypesarray[]Discovery filter: Red, White, Sparkling, Rosé, Dessert, Fortified.
minRatinginteger(none)Discovery filter: minimum Vivino average rating (1 to 4.5).
priceMin / priceMaxinteger(none)Discovery price range in the selected currency.
originCountriesarray[]Discovery filter by wine origin (ISO alpha-2 codes, e.g. fr, it, us).
grapesarray[]Discovery filter by Vivino grape IDs.
sortBystringrelevancerelevance, rating_desc, rating_asc, price_asc, price_desc, popularity.
includeTasteProfilebooleantrueFetch body, acidity, tannins, sweetness, fizziness, intensity, flavor notes.
includeReviewsbooleanfalseFetch user reviews per wine.
maxReviewsPerWineinteger10Maximum reviews per wine (1 to 100).
countryCodestringFRMarket country for pricing (ISO alpha-2).
currencyCodestringEURCurrency for prices (ISO 4217).
shipTostring(none)Optional ship-to country, echoed on each record.
maxItemsinteger20The only cap on records. Set 0 for unlimited.
maxPagesinteger(none)Discovery mode only: optional bound on pages walked. Leave empty to walk every result page; the run still stops at Max wines.
proxyobjectApify ProxyProxy settings. Works on all plans; Residential is recommended for large runs.
resumeFromRunIdstring(none)Continue one specific previous run/dataset: wines already collected there are skipped, so this run only appends new ones. For recurring daily monitoring of the same wine list or filters, use Incremental mode instead, see "Resume & recurring updates" below.
incrementalModebooleanfalseDaily/recurring monitoring of the same wine list or discovery filters. First run returns everything as NEW; later runs return only NEW/UPDATED/REAPPEARED by default. See "Resume & recurring updates" below.
stateKeystring(none)Optional name for a monitoring campaign, so its incremental state stays stable or is deliberately shared. Auto-derived from your wine list / discovery filters and enrichment settings when left empty.
emitUnchangedbooleanfalseIncremental mode only. Also return wines unchanged since the last run, marked UNCHANGED. Adds and bills extra rows you already have.
emitExpiredbooleanfalseIncremental mode only. Also return wines from a previous run no longer found, marked EXPIRED, once a run has fully scanned the tracked wines/filters (not capped, not a resume). Adds and bills extra synthetic rows.

Resume & recurring updates

There are two different things here, pick the one that matches what you're doing:

NeedUse
A run stopped and should continueresumeFromRunId (or the automatic same-run checkpoint, no input needed)
Run the same wine list or discovery filters every day and receive only changesincrementalMode
Keep separate daily campaigns for similar searchesdistinct stateKey values
Run a normal full snapshotleave both off

Resume (resumeFromRunId) continues one specific interrupted or previous large 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/Resurrects without any input needed.

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, UPDATED, and REAPPEARED wines by default, unchanged wines are suppressed (and not charged). Turn on emitUnchanged or emitExpired only when you also want those rows returned (and billed for). State is isolated per wine list / discovery filter and enrichment setup automatically; set stateKey to name or deliberately share a monitoring campaign.

Every record returned in incremental mode also carries:

FieldDescription
changeTypeNEW, UPDATED, UNCHANGED, REAPPEARED, or EXPIRED
changedFieldsTop-level fields that changed since last seen; non-empty only for UPDATED
firstSeenAtWhen this wine was first observed by this monitoring campaign
lastSeenAtWhen this wine was last observed

Scheduled-run example, same wine list, run daily:

Day 1 (first run ever for this list):

{ "mode": "lookup", "wines": ["Opus One 2019"], "incrementalMode": true }

Every wine comes back with "changeType": "NEW".

Day 2 (the schedule fires again, identical input):

{ "mode": "lookup", "wines": ["Opus One 2019"], "incrementalMode": true }

A wine whose price/rating/availability changed comes back as "changeType": "UPDATED" with changedFields listing what changed; a wine that vanished and came back comes back as "changeType": "REAPPEARED"; a wine that is still there, unchanged, is not returned at all (suppressed, not charged) unless emitUnchanged is on.

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, and both were measured on this actor with three back to back identical runs of a maxItems: 3 US/USD red wine discovery walk, minutes apart:

  1. The discovery result set itself moves. The three runs returned three different sets of wines. Only one wine out of three appeared in all three runs.
  2. A wine that does appear twice can come back as a different vintage from a different merchant. That one repeated wine was reported UPDATED on runs 2 and 3, with changedFields listing average_rating, cmp_score, cmp_tier, discounted_from, merchant_url, name, price, prices, ratings_count, vintage and vintageId. On run 3 it flipped straight back to the vintage and the price it had on run 1.

So a scheduled discovery run reports a substantial share of NEW and UPDATED rows every time, and those rows are returned and billed. 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.

Nothing is excluded from change detection except scrapedAt. Excluding the price fields was considered and measured to be ineffective: on the repeated wine above, vintage, vintageId, name, average_rating and ratings_count moved too, so dropping price, prices and merchant_url from the comparison would still have produced UPDATED, while permanently hiding the real price drops that are the main reason to monitor a wine on a schedule.

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. A pinned vintage removes the whole vintage/vintageId/name/average_rating/ratings_count churn above. A separate measurement of one wine in lookup mode two minutes apart moved only price, prices and merchant_url.
  • Set countryCode and currencyCode explicitly and keep them identical on every run of a campaign, so every run asks for the same market.
  • Run on Apify Residential proxy with the proxy country pinned to that same countryCode, so exits stay inside one market instead of moving between markets.
  • Read changedFields before acting on a row. A row whose changedFields names vintage, vintageId or name is a different vintage of the same wine, not a change to the wine you were watching. A row that names only price, prices, merchant_url and the offer fields derived from them (currency, discounted_from, discount_percent, is_on_sale, discount_amount, bottle_volume_ml, vfm_score, vfm_category, cmp_score, cmp_tier) was most likely quoted by a different merchant rather than repriced.
  • Leave emitUnchanged off (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. Authorize a connector under Apify, Settings, API & Integrations, then select it in the input. For Notion, also set the parent page URL. The connector receives a condensed, human-readable summary per wine (a title plus key fields as plain text), not the full JSON; the complete record always stays in the Apify dataset. Leave the connectors field empty to skip this entirely; it never changes the dataset output.

Output example

Sample shape, values are illustrative placeholders, not from a live listing.

{
"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": 5,
"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?year=2019",
"scrapedAt": "2026-01-01T00:00:00.000Z",
"inputSource": "search"
}

Plan requirement

The actor runs on every Apify plan, including Free. For large jobs, the Residential proxy option gives the most consistent results; it is included on the Apify Starter plan and above. Select it in the proxy input when you need maximum reliability.