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

Vivino scraper for wine data: ratings, rating counts, merchant prices, regions, wineries, vintages and taste structure. Filter by wine type, country market, price band and minimum rating. One clean row per wine vintage, ready for price comparison and recommenders.

- **URL**: https://apify.com/devilscrapes/vivino-wines-scraper.md
- **Developed by:** [DevilScrapes](https://apify.com/devilscrapes) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

<div align="center">
  <img src=".actor/icon.svg" width="160" alt="Devil Scrapes mark" />

## Vivino Wines Scraper: Ratings, Prices & Wine Data

**💰 $3.20 / 1 000 results**  ·  pay only for results  ·  no credit card to try

*We do the dirty work so your dataset stays clean.* 😈

Vivino scraper for wine data: filter by wine type, country market, price band and minimum rating, and get one clean row per wine vintage with rating, rating count, merchant price, region, winery, taste structure and image.

</div>

***

### 🎯 What this scrapes

Wine retailers, price-comparison builders, recommender apps and market analysts all want Vivino's catalogue, and Vivino offers no public data API. This Actor reads the same explore feed the Vivino site uses and returns structured rows: vintage and wine ids, winery, region and country, average rating and rating count, the featured merchant price with currency and merchant link, bottle size, taste structure (acidity, intensity, sweetness, tannin) and the bottle image. Pick wine types, a market country, a price band and a minimum rating, and page through as many wines as you need.

### 🔥 What we handle for you

- 🛡️ **We send real-browser TLS fingerprints** so Vivino sees a browser, not Python.
- 🔁 **We retry with exponential backoff** on `408 / 429 / 503` and honour `Retry-After`, up to 5 attempts per page.
- 🌐 **We pin and rotate Apify proxy sessions** when you enable the proxy: your market country stays fixed, the session changes on every block.
- 🧱 **We recompute the page limit from every response**, so shifting match counts never cut a run short or loop it past the end.
- 🧊 **We keep the dataset clean** - Pydantic-validated rows, deduped by vintage id, ISO-8601 timestamps.
- 💰 **You pay only for results that land.** No data, no charge - only the small actor-start warm-up fee.

### 💡 Use cases

- **Price comparison** - track the featured merchant price and any discount for the same vintage over time.
- **Recommender and sommelier apps** - seed a catalogue with ratings, rating counts, style and taste structure.
- **Retail assortment research** - find highly rated wines inside a price band for a given market.
- **Market analysis** - compare regions, wineries and wine types by rating volume and price.

### ⚙️ How to use it

1. Click **Try for free** at the top of the page.
2. Fill in the input form — most fields have sensible defaults.
3. Click **Start**. Output streams into the run's dataset.
4. Export from **Storage → Dataset** as JSON, CSV, or Excel — or fetch via the API.

### 📥 Input

| Field | Type | Required | Default | Notes |
|---|---|:--:|---|---|
| `wineTypes` | `array` | no | \['red'] | Wine styles to include. Leave empty for all types. |
| `countryCode` | `string` | no | 'US' | Two-letter Vivino market, e.g. US, FR, GB. Steers merchants and prices. |
| `currencyCode` | `string` | no | 'USD' | Three-letter price currency, e.g. USD, EUR, GBP. |
| `minRating` | `number` | no | 1.0 | Minimum average rating, 1.0 to 5.0. |
| `priceMin` | `number` | no | 0 | Lower price bound in the chosen currency. |
| `priceMax` | `number` | no | 500 | Upper price bound in the chosen currency. Must be at least the minimum price. |
| `orderBy` | `string` | no | 'ratings_count' | Sort field: most-rated wines (default) or highest Vivino average rating. |
| `order` | `string` | no | 'desc' | Ascending or descending. |
| `maxItems` | `integer` | no | 100 | Hard cap on dataset rows for the whole run (24 wines per page). |
| `proxyConfiguration` | `object` | no | {'useApifyProxy': False} | Optional Apify Proxy. When enabled, the exit country is pinned to the market country code unless you set one. |

#### Example input

```json
{
  "wineTypes": [
    "red",
    "white"
  ],
  "countryCode": "US",
  "currencyCode": "USD",
  "minRating": 1.0,
  "priceMin": 0,
  "priceMax": 500,
  "orderBy": "ratings_count",
  "order": "desc",
  "maxItems": 60
}
```

### 📤 Output

Every row is one dataset item.

| Field | Type | Notes |
|---|---|---|
| `vintageId` | `integer` | Vivino vintage id. |
| `wineId` | `['integer', 'null']` | Vivino wine id. |
| `name` | `['string', 'null']` | Full vintage name. |
| `wineName` | `['string', 'null']` | Wine name without winery. |
| `year` | `['string', 'null']` | Vintage year, or N.V. for non-vintage. |
| `wineryId` | `['integer', 'null']` | Winery id. |
| `wineryName` | `['string', 'null']` | Winery name. |
| `wineTypeId` | `['integer', 'null']` | Vivino wine type id. |
| `wineType` | `['string', 'null']` | Wine type label (red, white, ...). |
| `regionName` | `['string', 'null']` | Wine region. |
| `countryCode` | `['string', 'null']` | Wine origin country code, upper-case. |
| `countryName` | `['string', 'null']` | Wine origin country name. |
| `styleName` | `['string', 'null']` | Wine style name. |
| `ratingAverage` | `['number', 'null']` | Average rating, 1 to 5. |
| `ratingsCount` | `['integer', 'null']` | Number of ratings. |
| `price` | `['number', 'null']` | Featured merchant price. |
| `currency` | `['string', 'null']` | Price currency code. |
| `discountedFrom` | `['number', 'null']` | Original price when discounted. |
| `merchantId` | `['integer', 'null']` | Merchant id. |
| `merchantUrl` | `['string', 'null']` | Merchant product URL. |
| `bottleVolumeMl` | `['integer', 'null']` | Bottle volume in millilitres. |
| `acidity` | `['number', 'null']` | Taste structure: acidity. |
| `intensity` | `['number', 'null']` | Taste structure: intensity. |
| `sweetness` | `['number', 'null']` | Taste structure: sweetness. |
| `tannin` | `['number', 'null']` | Taste structure: tannin. |
| `imageUrl` | `['string', 'null']` | Bottle image URL. |
| `marketCountry` | `['string', 'null']` | Market country Vivino served (follows exit IP). |
| `url` | `string` | Vivino vintage page URL. |
| `scrapedAt` | `string` | Run time, ISO 8601 UTC. |

#### Example output

```json
{
  "vintageId": 1469676,
  "wineId": 21646,
  "name": "Fantini Edizione Cinque Autoctoni",
  "wineName": "Edizione Cinque Autoctoni",
  "year": "N.V.",
  "wineryId": 7892,
  "wineryName": "Fantini",
  "wineTypeId": 1,
  "wineType": "red",
  "regionName": "Abruzzo",
  "countryCode": "IT",
  "countryName": "Italy",
  "styleName": "Central Italy Red",
  "ratingAverage": 4.3,
  "ratingsCount": 78709,
  "price": 33.49,
  "currency": "USD",
  "discountedFrom": null,
  "merchantId": 2863,
  "merchantUrl": "https://www.vynomeka.lt/vynas-farnese-edizione-cinque-autoctoni-vdt-075-l",
  "bottleVolumeMl": 750,
  "acidity": 2.56,
  "intensity": 4.13,
  "sweetness": 2.55,
  "tannin": 2.85,
  "imageUrl": "https://images.vivino.com/thumbs/MDrZtUCHR4eQ3L8xFS0scA_pl_480x640.png",
  "marketCountry": "LT",
  "url": "https://www.vivino.com/wines/1469676",
  "scrapedAt": "2026-10-08T09:00:00Z"
}
```

### 💰 Pricing

Pay-Per-Event — you pay only when these events fire:

| Event | USD | What it is |
|---|---:|---|
| `actor-start` | $0.20 | One-off warm-up charge per run |
| `result` | $0.003 | Per dataset item |

Example: 1 000 results at the rates above ≈ **$3.20**. No subscription, no minimum, no card to start — Apify gives every new account $5 of free credit.

### 🚧 Limitations

v1 is filter-driven: wine type, market, price band, minimum rating and sort order. Keyword search, wine detail pages, reviews, winery pages and grape or region filters are not included. Each row carries the featured merchant offer only, not the full merchant list. Rows are large, so maxItems defaults to 100. Merchants and prices follow the market Vivino serves; use the proxy option to pin the exit country to your countryCode.

### ❓ FAQ

**How much does a run cost?**

$3.00 per 1 000 results ($0.003 per wine row) plus a one-off $0.20 start fee per run. If nothing matches your filters you pay only the start fee.

**Do I need a Vivino account or API key?**

No. Choose your filters and we do the rest.

**Why does marketCountry sometimes differ from my countryCode?**

Vivino reports the country it served, which follows the network exit the request came from. Turn on the proxy option and we pin the exit country to your countryCode so the merchants and prices match the market you asked for. Every row carries marketCountry so you can verify it.

**What happens when no wines match?**

The run finishes successfully with zero rows and a status message naming your filters.

**Which sort orders are supported?**

Number of ratings and average rating. Further orders are added once verified.

**How many wines can I fetch?**

Up to 10 000 per run, 24 wines per page. The default is 100. Vivino's match counts drift between calls, so we recompute the page limit from every response.

### 💬 Your feedback

Spotted a bug, hit a weird edge case, or need a new field? Open an
issue on the Actor's **Issues** tab on Apify Console — we ship
fixes weekly and we read every report.

***

<div align="center">

Built by **[Devil Scrapes](https://apify.com/DevilScrapes)** 😈 — a small fleet of
opinionated public-data Actors. Honest pricing, real engineering, zero fine print.

</div>

# Changelog

This Actor's version history is a separate document: https://apify.com/devilscrapes/vivino-wines-scraper/changelog.md

# Actor input Schema

## `wineTypes` (type: `array`):

Wine styles to include. Leave empty for all types.

## `countryCode` (type: `string`):

Two-letter Vivino market, e.g. US, FR, GB. Steers merchants and prices.

## `currencyCode` (type: `string`):

Three-letter price currency, e.g. USD, EUR, GBP.

## `minRating` (type: `number`):

Minimum average rating, 1.0 to 5.0.

## `priceMin` (type: `number`):

Lower price bound in the chosen currency.

## `priceMax` (type: `number`):

Upper price bound in the chosen currency. Must be at least the minimum price.

## `orderBy` (type: `string`):

Sort field: most-rated wines (default) or highest Vivino average rating.

## `order` (type: `string`):

Ascending or descending.

## `maxItems` (type: `integer`):

Hard cap on dataset rows for the whole run (24 wines per page).

## `proxyConfiguration` (type: `object`):

Optional Apify Proxy. When enabled, the exit country is pinned to the market country code unless you set one.

## Actor input object example

```json
{
  "wineTypes": [
    "red",
    "white"
  ],
  "countryCode": "US",
  "currencyCode": "USD",
  "minRating": 1,
  "priceMin": 0,
  "priceMax": 500,
  "orderBy": "ratings_count",
  "order": "desc",
  "maxItems": 60,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `output` (type: `string`):

No description

## `datasetItems` (type: `string`):

All dataset items as JSON.

## `datasetItemsCsv` (type: `string`):

Same data exported to CSV.

## `datasetView` (type: `string`):

Open the run dataset in the Console.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "wineTypes": [
        "red",
        "white"
    ],
    "countryCode": "US",
    "currencyCode": "USD",
    "minRating": 1,
    "priceMin": 0,
    "priceMax": 500,
    "orderBy": "ratings_count",
    "order": "desc",
    "maxItems": 60,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("devilscrapes/vivino-wines-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "wineTypes": [
        "red",
        "white",
    ],
    "countryCode": "US",
    "currencyCode": "USD",
    "minRating": 1,
    "priceMin": 0,
    "priceMax": 500,
    "orderBy": "ratings_count",
    "order": "desc",
    "maxItems": 60,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("devilscrapes/vivino-wines-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "wineTypes": [
    "red",
    "white"
  ],
  "countryCode": "US",
  "currencyCode": "USD",
  "minRating": 1,
  "priceMin": 0,
  "priceMax": 500,
  "orderBy": "ratings_count",
  "order": "desc",
  "maxItems": 60,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call devilscrapes/vivino-wines-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,devilscrapes/vivino-wines-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/oB3WPV4RdQHyyTChO/builds/OIWTiThCEuKjRdT1F/openapi.json
