# Vinted Scraper (`s-r/vinted-scraper`) Actor

A Vinted scraper that returns second-hand listings with brand, size, condition, the asking price and the price a buyer actually pays including buyer protection. Nine country markets, 96 listings per request, no browser and no login.

- **URL**: https://apify.com/s-r/vinted-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** E-commerce, Business
- **Stats:** 4 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 run start fees

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

## Vinted Scraper

A Vinted scraper that returns second-hand listings with brand, size, condition, the asking price and the price a buyer actually pays including buyer protection. Nine country markets, 96 listings per request, no browser and no login.

### What you get

- **96 listings per page**, which is unusually generous and makes a thousand rows cost about eleven requests
- **Brand, size and condition as separate fields**, parsed from the listing summary in the market's own language rather than left in one string
- **Two prices**: the asking price and the price including Vinted's buyer protection fee. The second is what the buyer is charged, and it is the number that matters for market analysis
- **Nine markets**: Netherlands, Belgium, Germany, France, Spain, Italy, Poland, United Kingdom and United States, each fetched from an exit in its own country
- **The raw summary string** kept on every row, so a locale this actor has not been taught yet is recoverable rather than lost
- **Stable item ids**, so scheduled runs deduplicate exactly and price changes are a clean join
- Charged per listing, plus a flat $0,002 start fee

### Why scrape Vinted

Vinted is the largest second-hand fashion marketplace in Europe and the clearest available picture of what used clothing actually sells for. Resale prices are almost entirely undocumented: new goods have RRPs and comparison sites, used goods have whatever a stranger is asking today. For anyone in resale, brand analytics or sustainability research, this is the market data.

There is no public API. The private one, `/api/v2/catalog/items`, answers 401 without a session. What Vinted does do is server-render its entire grid, and each item carries a complete summary in the link's title attribute: name, brand, condition, size and both prices. That is a better source than the visible card, because the card's class names are CSS-module hashes that change on every deploy while the summary attribute does not.

### Input

| Field | Type | Required | Default | What it does |
|---|---|---|---|---|
| `query` | string | yes | `jas` | What to search for, in the market's language |
| `market` | select | no | `nl` | Which country site, and therefore currency and label language |
| `url` | string | no | – | A Vinted catalog URL to read instead, filters included |
| `sort` | select | no | `relevance` | Relevance, newest, or price ascending/descending |
| `price_min` / `price_max` | integer | no | – | Price bounds in the market's currency |
| `limit` | integer | no | `96` | Listings to return, 1 to 1440 |
| `retries` | integer | no | `4` | Retry attempts per page |

### Output

```json
{
  "position": 1,
  "item_id": "9852116345",
  "url": "https://www.vinted.nl/items/9852116345-tussen-jas",
  "title": "Mantel h&m Gr 50 neu",
  "brand": "H&M",
  "size": "5XL / 50 / 22",
  "condition": "Heel goed",
  "price": 35.0,
  "price_with_protection": 37.45,
  "currency": "€",
  "image": "https://images1.vinted.net/...",
  "market": "nl",
  "query": "jas"
}
```

### Use cases

**Resale price research.** Run a brand as the query and read the distribution. Because `price` and `price_with_protection` are separate, you can see both what sellers ask and what buyers are charged, and the gap is Vinted's take. A run across three markets tells you where the same brand holds value best.

**Sourcing for resellers.** Sort by newest with a price ceiling and check `brand` and `condition`. New listings from known brands under a threshold are the whole job, and at 96 per request a scheduled run covers a category cheaply.

**Brand and sustainability analytics.** How much of a brand's inventory is on the second-hand market, at what fraction of retail, in which sizes, is a question brands increasingly need answered and cannot answer themselves. `brand`, `size` and `price` on every row is enough to build it.

**Size and demand analysis.** `size` is a clean field rather than a substring of the title, so aggregating supply by size across a category is a group-by rather than a parsing project.

### How it compares

| | this actor | `apify/e-commerce-scraping-tool` |
|---|---|---|
| Per 1.000 listings | **$1,20** | $6,00 |
| Covers Vinted | **yes** | generic, needs configuring |
| Listings per request | **96** | varies |
| Brand, size, condition split out | **yes** | no |
| Price with buyer protection | **yes** | no |
| Markets | **9** | n/a |
| Needs a login or browser | **no** | no |

Honest about the other side: `apify/e-commerce-scraping-tool` has 575 monthly users and works on many shops. It is a breadth tool. Nothing on the Store covers Vinted search at all.

### Pricing

Two events. A flat `run_start` of $0,002 covers the run, and `item` costs $0,0012 per listing returned, which is $1,20 per 1.000. Beyond the start fee you only pay for listings you actually receive.

### Limits and gotchas

- **Prices use different decimal separators in different places on the same page.** The card writes "5,00" and the summary attribute writes "5.00" for the same item. This actor parses by separator position rather than assuming, because getting it wrong turns a €10 coat into a €1.000 one with nothing in the output to show it.
- **`brand` is empty on roughly one listing in twenty**, where the seller did not set one. That is a real absence.
- **Condition and size are in the market's own language.** A Dutch listing says "Heel goed", a German one "Sehr gut". `summary_raw` keeps the original string if you need to normalise differently.
- **1440 listings per run** across 15 pages. Beyond that, narrow the query or add a price band.
- **The private API is not used.** `/api/v2/catalog/items` requires a session and returns 401 anonymously, so everything here comes from the rendered page.
- **Sold items disappear from search.** Vinted does not keep a public sold archive, so this measures asking prices and supply, not realised sales.

### FAQ

**Can I scrape Vinted without an API key or login?**
Yes. Vinted server-renders its full grid for anonymous visitors, 96 items per page, and that is what this actor reads.

**What is `price_with_protection`?**
Vinted charges a buyer-protection fee on top of the asking price. That field is what the buyer is actually charged, and it is the more honest figure for market comparisons.

**Which countries are supported?**
Nine: NL, BE, DE, FR, ES, IT, PL, UK and US, each fetched through an exit in its own country so prices and currency match.

**Can I filter by category rather than search?**
Yes. Apply the filters on the site and paste the resulting catalog URL into `url`.

**Does it return sold items?**
No. Vinted removes sold listings from search, so this reflects live supply and asking prices.

### Related Actors

- [Marktplaats Scraper](https://apify.com/s-r/marktplaats-scraper) — Dutch general classifieds
- [AutoScout24 Scraper](https://apify.com/s-r/autoscout24-scraper) — cars across nine European markets
- [Skroutz Scraper](https://apify.com/s-r/skroutz-scraper) — Greek price comparison

# Actor input Schema

## `query` (type: `string`):

What to search for. Use the market's own language for the best results.

## `market` (type: `string`):

Which Vinted country site to read. The exit is pinned to that country and the field labels are read in that language.

## `url` (type: `string`):

A Vinted catalog URL to read instead of a search term. Paste it from your browser after applying filters.

## `sort` (type: `string`):

Vinted's own ordering.

## `price_min` (type: `integer`):

Lower price bound in the market's currency.

## `price_max` (type: `integer`):

Upper price bound in the market's currency.

## `limit` (type: `integer`):

How many listings to return, 1 to 1440. A page carries 96, which is unusually generous.

## `retries` (type: `integer`):

Retry attempts per page, each with a rotated TLS fingerprint.

## Actor input object example

```json
{
  "query": "jas",
  "market": "nl",
  "url": "https://www.vinted.nl/catalog?catalog[]=1904",
  "sort": "relevance",
  "limit": 96,
  "retries": 4
}
```

# Actor output Schema

## `results` (type: `string`):

One row per Vinted listing.

## `summary` (type: `string`):

Market, pages served, and how many rows carried a price, a brand and a size.

## `errors` (type: `string`):

Per-page failures with a code and a redacted message.

# 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 = {
    "query": "jas",
    "limit": 96,
    "retries": 4
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/vinted-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 = {
    "query": "jas",
    "limit": 96,
    "retries": 4,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/vinted-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 '{
  "query": "jas",
  "limit": 96,
  "retries": 4
}' |
apify call s-r/vinted-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/vinted-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/NtK7vO8J51udfDbuo/builds/asQUaQI75onSc3Hha/openapi.json
