# 🔥Vinted Scraper (`bebity/vinted-premium-actor`) Actor

🚀 Vinted Data Scraper: Fast & Robust! 🔥
🛒 Items and catalogs
👥 User profiles with stats and balances
🏷️ Brands
🌟 Seamlessly integrate with Apify for unparalleled performance & insights. Elevate your business now!🌟
🔥 Power of direct API access for ultra-fast data extraction in a flash! ⚡

- **URL**: https://apify.com/bebity/vinted-premium-actor.md
- **Developed by:** [Bebity](https://apify.com/bebity) (community)
- **Categories:** E-commerce
- **Stats:** 518 total users, 8 monthly users, 100.0% runs succeeded, 10 bookmarks
- **User rating**: 2.92 out of 5 stars

## Pricing

from $0.80 / 1,000 product scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 — items, sellers and deep collection](https://i.postimg.cc/vBTyz6bB/banner.png)

**Vinted Scraper** extracts listings and seller profiles from [Vinted](https://www.vinted.com) across **12 marketplaces** — search by keywords, paste a filtered Vinted URL, or point it at a seller's wardrobe. It returns **33 clean columns per listing, 54 with item details,** and **36 per seller** — pro sellers' public business contact included — at **$0.001 per item**: the most complete Vinted dataset on the Store, at half the market's median price.

> ### 🚀 Version 2 — a full rebuild
>
> This is not a patch. v2 is a ground-up rewrite of the engine, the input schema and the output contract, rebuilt around what Vinted sellers, resellers and price-monitoring teams actually asked for. **It breaks Vinted's ~813-result ceiling, runs 4.7× faster, returns more than twice the fields of the median actor, and is priced pay-per-event so AI agents can call it directly.** Everything below is measured, not claimed.

***

### What is Vinted Scraper?

Vinted has no public API. **Vinted Scraper is that missing API** — a fast, structured, pay-as-you-go interface to Vinted's catalogue and seller base.

Give it keywords, a Vinted search URL you built in your own browser, or a list of seller profiles. It returns a flat, typed dataset you can export as **JSON, CSV, Excel, XML or HTML**, push into Google Sheets, or read straight from the Apify API.

***

### What's new in v2

| | v1 | **v2** |
|---|---|---|
| Result ceiling | silently capped at ~813 | **5,146 unique measured** with Deep scan |
| Speed, 100 items | 104 s | **22 s** — 4.7× faster |
| Bandwidth per run | ~54 MB | **~0 MB** |
| Fields per listing | 12 | **33, up to 54 with item details** |
| Seller data | none | **36 fields, own dataset — pro sellers' public contact included** |
| Failed rows | silently dropped | **visible, with a reason** |
| Pricing | monthly subscription | **pay-per-event, from $0.001/item** |
| AI agents / MCP | not callable | **callable** |

**Breaking change:** the v1 input schema mirrored Vinted's raw API. v2's is built around tasks — search, filter, follow a seller — so you never have to look up an ID by hand again.

***

### Why Vinted Scraper beats Vinted's 813-result wall

This is the single thing every other Vinted scraper stops at, and most never mention.

Vinted's search API **refuses to paginate past page 10**. Ten pages × 96 rows is 960 raw results — about **813 unique** once the 15% page-overlap is removed. `pagination.total_pages` is a decoy: it always reports `ceil(960 / per_page)`, never the real volume. Ask for page 11 and the API errors; the public site answers *"Sorry, no results"*. Every scraper that pages naively stops there.

**That cap applies per query, not to the corpus.** Turn on **Deep scan** and the actor slices your price range into narrower bands, searches each independently, and recursively splits any band that comes back full — because a saturated band is proof there is more behind it.

| Strategy | Unique results |
|---|---:|
| Plain pagination | 778 |
| Fixed price slices | 2,628 |
| Price cursor | 1,634 |
| **Adaptive price partition (Deep scan)** | **5,146** |

*Measured 5 September 2026 on a broad query. A single band, `€0–5`, returns 749 uniques; split in half, its halves return 1,878 together — ×2.51, and still saturated.*

And when Deep scan is **off** while you asked for more than one search can deliver, the run says so in the log, with both numbers — instead of reporting a tidy success over truncated data.

***

### Unmatched speed: 22 seconds for 100 items

Speed here is measured, and the measurements are public.

| Metric | Result |
|---|---|
| 100 items, end to end | **22.0 s** median (was 104.4 s) |
| Throughput | **323 requests/minute** (was 56) |
| Bandwidth per run | **~0 MB** (was ~54 MB) |
| p99 request latency, through proxy | 8.3 s |

Where it came from: the bootstrap step used to download Vinted's 2 MB homepage ~25 times per run just to read nine `Set-Cookie` headers. A `HEAD` request returns the same nine headers and **zero bytes** — and gets refused less often, because a 2 MB body on a slow IP was blowing its own timeout and being logged as a block. Concurrency, session-pool sizing and autoscaler warm-up were then tuned against ~90 real runs.

You pay per event, not per second — but a faster actor still means fresher data and quicker feedback loops.

***

### What data can Vinted Scraper extract?

Every listing lands as one flat row. Nothing is nested in a raw API blob you have to dig through.

#### Listing fields — 54 columns

| Group | Fields |
|---|---|
| **Identity** | `id`, `url`, `title`, `brand`, `size`, `condition` |
| **Pricing** | `price`, `currency`, `totalPrice`, `serviceFee` |
| **Media** | `photo` (main image), `photos[]` (up to 20, each with `url`, `fullSizeUrl` up to 1600 px, `dominantColor`, `width`, `height`), `photoCount` |
| **Seller** | `sellerId`, `sellerLogin`, `sellerUrl`, `sellerPhoto`, `isBusinessSeller` |
| **Engagement** | `favouriteCount`, `viewCount`, `promoted` |
| **Availability** | `isReserved`, `isClosed`, `isVisible`, `isHidden`, `itemClosingAction`, `isHeavyBulky` |
| **Timing** | `listedAt`, `listedHoursAgo`, `scrapedAt` |
| **Demand signals** | `favsPerDay`, `favouriteRate` — computed here, served by no one |
| **Context** | `country` |
| 🔍 **Item details add-on** | `description`, `category`, `categoryId`, `brandId`, `sizeId`, `statusId`, `colors[]`, `attributes{}` |
| 🔍 **Shipping, from item details** | `shippingFrom`, `shippingOriginalPrice`, `shippingDiscount`, `shippingLowest30d`, `pickupOnly` |
| 🔍 **Seller, from item details** | `sellerFeedbackRating`, `sellerFeedbackCount`, `sellerItemCount`, `sellerCity`, `sellerCountry`, `sellerLastSeenAt`, `sellerBadges[]` |
| 🔍 **Honesty** | `detailError` — `null` when the product record arrived. Otherwise why it did not: the listing columns on that row are complete, the add-on columns are empty, and the row was not charged the detail rate |

One of those exists nowhere else on the Store:

- **`attributes{}`** — the attribute map Vinted attaches *per category*, flattened to `attributes/<key>` on export. `material` on furniture, `author` / `isbn_nav` / `language_book` on books, `battery_health` and `internal_memory_capacity` on phones. Whatever Vinted attaches to that category comes through. The two actors that get closest hard-code two clothing attributes and return `null` for everything else — which is what happens if you build the field from a single garment instead of from six categories.

#### Seller fields — 36 columns, in their own dataset

| Group | Fields |
|---|---|
| **Identity** | `sellerId`, `sellerLogin`, `sellerUrl`, `sellerPhoto`, `about`, `isBusinessSeller` |
| **Reputation** | `feedbackReputation`, `feedbackCount`, `positiveFeedbackCount`, `neutralFeedbackCount`, `negativeFeedbackCount` |
| **Trust** | `isEmailVerified`, `isGoogleVerified`, `isFacebookVerified` |
| **Trade history** | `totalItemsCount`, `soldItemCount`, `boughtItemCount`, `itemCount` |
| **Deals** | `bundleDiscounts[]` — the seller's bundle tiers, e.g. 10 % off from 3 items |
| **Audience** | `followersCount`, `followingCount`, `followingBrandsCount` |
| **Location** | `city`, `countryCode` |
| **Activity** | `isOnline`, `isOnHoliday`, `lastSeenAt`, `scrapedAt` |
| 💼 **Pro contact** | `businessName`, `businessEmail`, `businessPhone`, `businessAddress`, `businessCountryCode`, `businessLegalCode`, `businessRegistrar` |
| 📈 **Derived** | `sellThroughRate` — sold ÷ listed, as a percentage |

**Pro sellers' contact, exactly as Vinted shows it.** For a pro seller: the business name, email, phone, registration number and — for a company — the street address their public profile displays, in a *Pro sellers' contact* tab. What Vinted keeps private stays empty: a sole trader's personal email or phone is never returned, and private sellers leave all seven columns empty.

**`sellThroughRate` in a single call.** No snapshots, no scheduled diffing: the numbers are already in the profile response, so one request tells you whether a seller actually moves stock. The market leader bills this as a dedicated $0.10 event.

Seller rows go to a **separate `sellers` dataset**, so one row always means one entity — `maxItems: 100` returns 100 listings, not 198 mixed-shape rows.

#### How that compares

[![Vinted Scraper field coverage compared with 16 other Vinted actors on the Apify Store](https://i.postimg.cc/g0YYJTfc/output-fields-comparison.png)](https://i.postimg.cc/g0YYJTfc/output-fields-comparison.png)

<sub>✓ included · **+$** behind a paid add-on event · **~** present but buried in the raw API object · — absent · <b>\*</b> requires *Include item details* · <b>\*\*</b> requires *Enrich with seller details* · <b>new in 2.2 / 2.3</b> marks a row added since the first survey</sub>

**On the 47 fields charted, the 16 competing Vinted actors return a median of 18.5. The best of them returns 27; Vinted Scraper returns 46.** No competitor returns a pro seller's business contact, registration number or bundle discounts at all. Every cell was read from each actor's live dataset schema and README, not estimated: the rows up to 2.2 on 10 September 2026, the four rows new in 2.3 on 13 September 2026.

***

### How much does it cost to scrape Vinted?

Pay-per-event. You are billed for results, never for time, and never for a run that returns nothing.

| Event | Price | When it fires |
|---|---:|---|
| **Actor start** | $0.005 | once per run |
| **Item scraped** | **$0.001** | one unique listing in the dataset |
| **Seller enriched** | $0.002 | one seller profile, only with the add-on on |
| **Item detailed** | $0.002 | one listing page parsed, only with the add-on on |

**$0.001 per item is half the Store's median of $0.002** — and it's the same price on every Apify plan, including the free one. Several competitors advertise a lower headline number, but only from the Gold tier upward; on the free and entry plans they charge $0.002 to $0.0035. Vinted Scraper returns nearly twice the fields, at the same price for everyone.

#### Build your own price with add-ons

The two add-ons are **opt-in and billed only when used**, so you pay for the shape of data you actually need rather than a bundled price someone else chose:

| What you need | Add-ons | Cost per 1,000 items |
|---|---|---:|
| Price monitoring, catalogue snapshots | none | **$1.01** |
| Lead-gen, seller vetting | Seller details (≈300 unique sellers) | **$1.61** |
| Full product records with descriptions | Item details | **$3.01** |
| Everything | both | **$3.61** |

Actors that bundle descriptions into the base price sit **25% above the market median** on every row — including the rows you didn't want a description for. Keeping it as an add-on is what lets the base row stay at $0.001.

#### Cap what a run may cost you

Set **Maximum cost per run** in the run options and the actor plans its collection around that number *before it sends a single request* — it tells you upfront how many listings your cap covers, collects exactly that many, and stops. You are never handed rows past the cap, and never charged past it either.

The cap counts the add-ons too: with **Seller details** on, a listing is budgeted at the listing plus its seller, so a $1 cap yields the number of *complete* records it can pay for rather than a pile of listings and a truncated seller tab.

**On the Apify free plan** ($5 monthly credit) that's roughly **4,900 listings per month at no cost**.

***

### Built for AI agents

v2 is pay-per-event, which is what makes it callable over Apify's **MCP server** and usable by agents that pay per call. The v1 subscription model was excluded from that channel entirely.

Beyond billing, three design choices make the output safe to hand to a model:

- 🧱 **A declared dataset schema.** Every column has a type, and the column set is stable across both collection routes — missing values are `null`, never an absent key. An agent parsing the tenth row sees the shape of the first.
- 🚨 **No silent failures.** An input that can't be extracted produces a **failure row carrying its reason**, in a dedicated `failed_items` view — not a gap. An agent can count, retry or escalate. v1's `catch { break; }` is exactly how the 813-item ceiling stayed hidden for months.
- 🔢 **Pre-computed signals.** `favsPerDay`, `favouriteRate`, `listedHoursAgo` and `sellThroughRate` are derived in the actor, so an agent doesn't burn tokens doing arithmetic over a dataset.

Add the Apify platform on top — scheduling, webhooks, monitoring, integrations, proxy rotation, and a REST API over every dataset — and the whole thing is one HTTP call away.

***

### How to scrape Vinted data: step by step

1. **Click Try for free** at the top of this page.
2. **Choose how to search.** Type words into *Search keywords*, or filter on `vinted.fr` in your own browser and paste the resulting URL into *Vinted search URLs* — every filter in that URL is parsed automatically. For a specific seller, paste their profile URL into *Seller profile URLs*, under *Advanced filters*.
3. **Pick your country** — `com`, `fr`, `de`, `es`, `it`, `be`, `at`, `cz`, `pl`, `pt`, `ro` or `co.uk`.
4. **Set *Max items*.** Start at 100 to see the shape of the data.
5. **Need more than ~813 results?** Turn on **Deep scan**.
6. **Need descriptions or seller profiles?** Tick *Include item details* and *Enrich with seller details*.
7. **Click Start**, then download from the **Storage** tab as JSON, CSV, Excel, XML or HTML — or pull it from the API.

#### Input

Vinted Scraper has the following input options — click the **Input** tab for the full schema.

```json
{
  "query": "vintage track jacket",
  "country": "fr",
  "brands": ["Nike", "Stone Island"],
  "colors": ["black", "navy"],
  "priceMin": 10,
  "priceMax": 60,
  "sortBy": "newest_first",
  "maxItems": 1000,
  "deepScan": true,
  "includeItemDetails": false,
  "includeSellerDetails": false
}
```

**Brands take names.** Type `Nike` or `Stone Island` the way Vinted spells them, or a Vinted brand ID such as `53` if you have one. The actor looks each one up when the run starts, and the log lists the brands it will filter on — `🏷️ Filtering on 2 brands: Nike (53), Stone Island (73306)` — before it collects anything. A name that matches no brand exactly is never guessed: it is left out, the log names the closest brands Vinted has, and the *Failed items* tab keeps a row for it.

The power-user path is `startUrls`: build the search on Vinted with every facet you want — brand, size, colour, condition, category — paste the URL, and the actor turns it into API parameters for you.

#### Output example

Everything below is a **real row from a real run** — one seller's wardrobe collected with both add-ons on, **50 of the 54 columns populated**. Nothing is hand-written, and the four `null`s are explained where they sit: a field that is honestly empty is worth more than a field that is always plausible.

The comments mark who pays for what:

| Marker | Add-on | Charged as |
|---|---|---|
| *(none)* | always included | `item-scraped` — **$0.001** |
| `// + Item details` | **Include item details** | `item-detailed` — **$0.002** on top of the row |
| second block | **Include seller details** | `seller-enriched` — **$0.002** per *unique* seller |

```jsonc
{
  "id": 9543696765,
  "url": "https://www.vinted.fr/items/9543696765-on-performance-jacket-year-of-the-horse",
  "title": "On Performance Jacket Year of the Horse",
  "brand": "On Running",
  "size": "S",
  "condition": "Très bon état",          // Vinted's own wording, in the marketplace's language

  // ── What it actually costs a buyer ──────────────────────────────────────
  "price": 180,
  "currency": "EUR",
  "serviceFee": 9.7,
  "totalPrice": 189.7,                   // price + serviceFee, precomputed
  "shippingFrom": 3.28,                  // + Item details — absent from Vinted's API entirely
  "shippingOriginalPrice": 3.28,         // + Item details — before any seller-funded discount
  "shippingDiscount": 0,                 // + Item details — original minus final; 0 here
  "shippingLowest30d": 3.28,             // + Item details — this seller's lowest in 30 days

  // ── Images ──────────────────────────────────────────────────────────────
  "photo": "https://images1.vinted.net/t/05_00dcc_…/f800/1785574788.jpeg?s=1e0e39e7…",
  "photos": [                            // up to 20, main photo first
    {
      "url": "https://images1.vinted.net/t/05_00dcc_…/f800/1785574788.jpeg?s=1e0e39e7…",
      "fullSizeUrl": "https://images1.vinted.net/tc/05_00dcc_…/1785574788.jpeg?s=2f603228…",
                                         // the largest version Vinted keeps, up to 1600 px
      "dominantColor": "#C8C2B7",
      "width": 600,                     // dimensions of `url` only
      "height": 800
    },
    { "url": "https://images1.vinted.net/t/04_026e9_…/f800/1785574788.jpeg?s=4f7b715c…", "fullSizeUrl": "https://images1.vinted.net/tc/04_026e9_…/1785574788.jpeg?s=f0df8067…", "dominantColor": "#CAC6BC", "width": 600, "height": 800 }
    // …3 more
  ],
  "photoCount": 5,

  // ── Seller, on the listing row ──────────────────────────────────────────
  "sellerId": 29391665,
  "sellerLogin": "avuoyten",
  "sellerUrl": "https://www.vinted.fr/member/29391665-avuoyten",
  "sellerPhoto": "https://images1.vinted.net/t/01_002c9_…/f800/1788623824.jpeg?s=2f9435f4…",
                                         // the seller's avatar; null when they have none
  "isBusinessSeller": false,

  // ── Demand signals ──────────────────────────────────────────────────────
  "favouriteCount": 20,
  "viewCount": 0,                        // real 0 — wardrobe collection counts views, and
                                         // nobody has opened this one yet
  "favsPerDay": 0.47,                    // derived: favouriteCount × 24 ÷ listedHoursAgo
  "favouriteRate": null,                 // null: favourites per view, needs both non-zero —
                                         // viewCount is a real 0 here
  "isReserved": false,
  "isClosed": false,
  "isVisible": null,                     // null: keyword search only — this row is from a
                                         // seller's wardrobe, not a search
  "isHidden": false,                     // wardrobe collection; item details, when on, can
                                         // refine this same field from the product record
  "itemClosingAction": null,             // null: only a closed listing has a closing reason
  "promoted": false,
  "isHeavyBulky": false,

  // ── Freshness ───────────────────────────────────────────────────────────
  "listedAt": "2026-08-01T08:59:48.000Z",// derived from the main photo's upload timestamp:
                                         // replacing that photo moves this date. Still an
                                         // ISO date where the market publishes "il y a 6 semaines".
  "listedHoursAgo": 1012.56,

  // ── Item details add-on — the product record's own fields ────────────────
  "description": "Série limitée pour l’année du cheval.\nTrès peu portée.",
                                         // + Item details — the differentiator. Verbatim,
                                         // newlines included, no truncation in the dataset.
  "category": "Hommes Vestes coupe-vent",// + Item details — the full readable path
  "categoryId": 2551,                    // + Item details — the id behind that path
  "colors": ["Beige"],                   // + Item details — every colour. The page's own
                                         // structured data carries only the first one.
  "attributes": {                        // + Item details — keys vary BY CATEGORY: a book
    "catalog": "Vestes coupe-vent",      // gives author/isbn, a phone gives battery_health,
    "brand": "On Running",               // a sofa gives material.
    "size": "S",
    "status": "Très bon état",
    "color": "Beige",
    "upload_date": "Il y a 6 semaines"
  },
  "brandId": 267947,                     // + Item details — Vinted's own brand id
  "sizeId": 515,                         // + Item details
  "statusId": 2,                         // + Item details — the condition, as an id
  "pickupOnly": false,                   // + Item details — hand-off only, no shipping option

  // ── Item details add-on — what the same fetch learns about the seller ───
  "sellerFeedbackRating": 1,             // + Item details — 0-1 ratio, a byproduct of
  "sellerFeedbackCount": 5,              //   fetching the product record, not the full profile the
  "sellerItemCount": 5,                  //   separate `sellers` dataset below fetches on
  "sellerCity": "Courbevoie",            //   its own opt-in
  "sellerCountry": "France",             // + Item details
  "sellerLastSeenAt": "2026-09-12T13:24:46+02:00", // + Item details
  "sellerBadges": ["ACTIVE_LISTER", "SPEEDY_SHIPPING"], // + Item details

  // ── Provenance ──────────────────────────────────────────────────────────
  "country": "fr",
  "scrapedAt": "2026-09-12T13:33:37.732Z",
  "detailError": null                    // the product record arrived; a string
}                                        //   here names what stopped it instead
```

##### The seller row

With **Include seller details** on, each *unique* seller is fetched once and written to a separate **`sellers`** dataset — not mixed into the listings table, because a seller row has no `id`, `title` or `price` and would read as blank next to your items. Real row from a private seller, fetched on 13 September 2026 — 29 of its 36 columns populated, the seven pro-contact columns empty because this seller is not a pro:

```jsonc
{
  "sellerId": 295937518,
  "sellerLogin": "aliwali786",
  "sellerUrl": "https://www.vinted.fr/member/295937518-aliwali786",
  "sellerPhoto": "https://images1.vinted.net/t/06_00602_…/f800/1768570494.jpeg?s=9c99d5c1…",

  "feedbackReputation": 1,               // 0-1 ratio, NOT a 5-star score
  "feedbackCount": 24,
  "positiveFeedbackCount": 24,           // the breakdown behind the ratio: 4.8 from 6 reviews
  "neutralFeedbackCount": 0,             // is not 4.8 from 600, and only these three say so
  "negativeFeedbackCount": 0,
  "isEmailVerified": true,               // the profile's "verified info"
  "isGoogleVerified": true,
  "isFacebookVerified": false,

  "itemCount": 86,                       // listed right now
  "totalItemsCount": 113,                // listed ever
  "soldItemCount": 27,
  "boughtItemCount": 15,
  "sellThroughRate": 23.89,              // sold / listed ever, as a percentage
  "bundleDiscounts": [                   // 5 % off 2 items, 10 % off 3, 30 % off 5
    { "minItems": 2, "percent": 5 },
    { "minItems": 3, "percent": 10 },
    { "minItems": 5, "percent": 30 }
  ],

  "followersCount": 3,
  "followingCount": 9,
  "followingBrandsCount": 12,

  "city": "Lumezzane",
  "countryCode": "IT",
  "isBusinessSeller": false,
  "isOnHoliday": false,
  "isOnline": false,
  "lastSeenAt": "2026-09-12T21:55:06+02:00",  // ISO 8601, not "yesterday at 21:55"
  "about": "Beautiful collection for your home, kitchen accessories…",

  "businessName": null,                  // pro sellers only — see the example below
  "businessEmail": null,
  "businessPhone": null,
  "businessAddress": null,
  "businessCountryCode": null,
  "businessLegalCode": null,
  "businessRegistrar": null,
  "scrapedAt": "2026-09-12T20:23:59.689Z"
}
```

For a **pro seller**, those seven columns hold what their public Vinted profile displays. A company that shows everything reads like this (values replaced):

```json
{
  "businessName": "Exemple Vintage",
  "businessEmail": "contact@example.com",
  "businessPhone": "+33100000000",
  "businessAddress": "12 rue de la Gare, 75001 Paris, Ile-de-France",
  "businessCountryCode": "FR",
  "businessLegalCode": "12345678900012",
  "businessRegistrar": "RCS Paris"
}
```

A sole trader shows a city but no street address, so `businessAddress` stays empty — and so does `businessEmail` or `businessPhone` whenever Vinted masks it on the profile as a personal contact.

##### Ready-made views

The Output tab opens on **Overview** — product photo first, then title, brand, size, condition, price and seller. Four more tabs are set up for you, so you rarely need to export before you can read anything:

| Tab | What it is for |
|---|---|
| **Overview** | Photo-first browse of everything you collected |
| **Product details** | The `Include item details` columns, on their own |
| **Pricing & shipping** | Price, buyer fee, total and shipping-from, side by side |
| **Seller & demand** | Who is selling, and whether the listing is moving |
| **Failed items** | Anything that could not be extracted, with the reason |

The **Sellers** dataset has three of its own: **Sellers**, **Reputation** and **Activity & reach**.

***

### FAQ

#### Is it legal to scrape Vinted?

Our scrapers are ethical and only collect what Vinted itself displays on a public page. They never return a private seller's email address, phone number or street address. For **pro sellers**, *Include seller details* returns the business contact shown on their public Vinted profile — the trader details the EU Digital Services Act requires marketplaces to display — and nothing Vinted keeps private: a sole trader's personal email or phone stays empty. We therefore believe that our scrapers, used for ethical purposes by Apify users, are safe. However, be aware that your results could contain personal data — seller handles, cities, profile text and a sole trader's business contact are public but still personal. Personal data is protected by the GDPR in the European Union and by other regulations worldwide. You should not scrape personal data unless you have a legitimate reason. If you're unsure whether your reason is legitimate, consult your lawyers.

#### Which Vinted countries are supported?

All 12 live marketplaces: `vinted.com`, `.fr`, `.de`, `.es`, `.it`, `.be`, `.at`, `.cz`, `.pl`, `.pt`, `.ro` and `.co.uk`. One country per run.

#### Why is `viewCount` empty on some rows?

Vinted only serves view counts on the seller-wardrobe route, never on catalogue search. Rather than invent a number, the column is `null` — and `favouriteCount`, which *is* served everywhere, drives `favsPerDay` instead.

#### Can I get more than 813 results?

Yes — that's what **Deep scan** is for. 5,146 unique results measured on a single broad query. See [the section above](#why-vinted-scraper-beats-vinteds-813-result-wall).

#### How do I monitor prices over time?

Schedule the actor daily from the **Schedule** tab and let each run append to the same dataset, then diff on `id` + `price`. Webhooks can push each finished run straight into your own pipeline.

#### Something broke, or I need a field you don't have

Open the **Issues** tab on this actor — it's monitored, and feature requests genuinely shape the roadmap. We also build custom variants of this actor for specific pipelines; the Issues tab is the fastest way to start that conversation.

***

<sub>Made with ❤️ by [bebity.io](https://bebity.io) · Not affiliated with, endorsed by, or connected to Vinted.</sub>

# Changelog

This Actor's version history is a separate document: https://apify.com/bebity/vinted-premium-actor/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

Paste one or more vinted.<country> catalog URLs (copied straight from your browser after filtering on the site — brand, category, size, colour, price, condition, sort). Each URL's filters are extracted automatically, so you never have to know a Vinted ID: this is the easiest way to use category, size or condition filters. Leave empty to search by keyword instead.

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

Text to search for, exactly like typing into Vinted's search box (e.g. "nike jacket"). Combine with the filters below to narrow results. Not needed if you supplied search URLs above, or seller profile URLs under Advanced filters.

## `country` (type: `string`):

Which Vinted marketplace to search. This picks the domain (vinted.fr, vinted.de, ...) the actor queries.

## `brands` (type: `array`):

Only return items from these brands, one per line. Type the name the way Vinted spells it (e.g. Nike, Stone Island, Levi's) — case and apostrophes don't matter. The actor looks each one up when the run starts, and the log lists exactly which brands it will filter on before it collects anything. A number is read as a Vinted brand ID (e.g. 53 for Nike). A name that matches no Vinted brand exactly is left out rather than guessed: the log names it with the closest brands Vinted has, and the Failed items tab keeps a row for it.

## `colors` (type: `array`):

Only return items listed in one of these colours — the same colours as Vinted's own colour filter. Leave empty for any colour.

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

Only return items priced at or above this amount, in the marketplace's currency. Leave empty for no lower bound. When Deep scan is on, this also seeds where the actor starts slicing the price range.

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

Only return items priced at or below this amount, in the marketplace's currency. Leave empty for no upper bound. When Deep scan is on, this also seeds where the actor starts slicing the price range.

## `sortBy` (type: `string`):

Order results the same way Vinted's own sort dropdown would.

## `catalogId` (type: `number`):

A single Vinted category ID to filter by. Find it by opening a category on vinted.<country> and reading the number at the start of it in the address — 1206 in vinted.fr/catalog/1206-outerwear — or skip this and paste that URL into the URLs field above.

## `sizeIds` (type: `array`):

Vinted size IDs to filter by, e.g. \[207]. Sizes are catalog-specific on Vinted, so the same number means different things in different categories — find the right one by picking a size on vinted.<country> and reading the size_ids\[] value from the resulting URL.

## `condition` (type: `array`):

Vinted condition IDs to filter by (Vinted calls this status_ids — e.g. "New with tags", "Very good"). Find the right numbers by picking a condition on vinted.<country> and reading the status_ids\[] value from the resulting URL.

## `sellerUrls` (type: `array`):

Collect a seller's wardrobe directly, instead of (or as well as) a keyword search. Open the seller's profile on Vinted and copy the address from your browser bar — it looks like vinted.fr/member/12345678-username — then paste one per line. Leave Search keywords empty to collect only these wardrobes. The marketplace is read from each address, so the Country setting doesn't apply here, and neither do the keyword, brand, colour, price, sort or ID filters: you get the seller's listed items, up to Max items. Wardrobes are collected before any search, so they count toward Max items first.

## `includeItemDetails` (type: `boolean`):

Fetch each item's page to add its description, every colour, the cheapest shipping price, the readable category path and the brand's Wikidata id. Costs one extra request per item, so runs take longer and are billed an extra item-detailed event.

## `includeSellerDetails` (type: `boolean`):

When enabled, the actor also fetches each unique seller's profile (reputation, follower count, city, last-seen date, verified sign-ins, bundle discounts, ...) and writes it to a separate `sellers` dataset, one row per unique seller. For pro sellers it adds the business contact their public Vinted profile displays — name, email, phone, registration and, for companies, the address; a contact Vinted keeps private is never returned. Costs one extra request per unique seller, billed as a separate charge event.

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

Stop once this many unique items have been collected. Vinted itself caps a single search at roughly 813 unique results — turn on Deep scan below to collect more than that.

## `deepScan` (type: `boolean`):

Vinted's own search caps out at roughly 813 unique results per query, no matter how you page through it. When enabled, the actor automatically splits your price range into narrower slices and searches each one, so a broad query can return thousands of items instead of stopping at the wall. When disabled, the actor collects up to that cap and tells you in the log if more results existed.

## Actor input object example

```json
{
  "startUrls": [],
  "query": "nike jacket",
  "country": "fr",
  "brands": [],
  "colors": [],
  "sortBy": "relevance",
  "sizeIds": [],
  "condition": [],
  "sellerUrls": [],
  "includeItemDetails": false,
  "includeSellerDetails": false,
  "maxItems": 100,
  "deepScan": false
}
```

# Actor output Schema

## `items` (type: `string`):

One row per unique listing, 39 columns. Failed rows live here too, under the "Failed items" tab, so nothing is ever silently dropped.

## `sellers` (type: `string`):

One row per unique seller, 24 columns. Written only when the "Include seller details" add-on is on, and kept in its own dataset so a listing row and a seller row never share a table.

# 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": "nike jacket"
};

// Run the Actor and wait for it to finish
const run = await client.actor("bebity/vinted-premium-actor").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": "nike jacket" }

# Run the Actor and wait for it to finish
run = client.actor("bebity/vinted-premium-actor").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": "nike jacket"
}' |
apify call bebity/vinted-premium-actor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bebity/vinted-premium-actor"
        }
    }
}
```

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/9L9xQ5kiZeol7VgO6/builds/EcbbgSBwKdrdmcR8p/openapi.json
