# Vinted Scraper — Listings, Prices & Seller Data (`vonsensey/vinted-scraper-api`) Actor

Scrape Vinted listings, prices, sellers and reviews across 27 country markets. Goes past Vinted's hard 960-item search cap and reports exactly how complete each run was. Export to CSV, Excel, JSON or API.

- **URL**: https://apify.com/vonsensey/vinted-scraper-api.md
- **Developed by:** [Blackcube](https://apify.com/vonsensey) (community)
- **Categories:** E-commerce, Developer tools, Integrations
- **Features:** Limited permissions
- **Stats:** 15 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 listings

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 — Listings, Prices & Seller Data

**More from this account:** [YouTube Transcript Suite](https://apify.com/vonsensey/youtube-transcript-scraper) · [Website Contact & Email Suite](https://apify.com/vonsensey/website-contact-email-extractor) · [Career Site & ATS Jobs Suite](https://apify.com/vonsensey/career-page-job-postings-scraper-api) · [Google News Suite](https://apify.com/vonsensey/google-news-scraper-api) · [Keyword Research Suite](https://apify.com/vonsensey/google-keyword-ideas-scraper) · [Shopify Store Intelligence Suite](https://apify.com/vonsensey/shopify-store-leads-scraper) · [eBay Data Suite](https://apify.com/vonsensey/ebay-scraper-api) · [Amazon Reviews Suite](https://apify.com/vonsensey/amazon-reviews-scraper-api) · [Reddit](https://apify.com/vonsensey/reddit-scraper-posts-comments-api) · [Meta Ad Library](https://apify.com/vonsensey/facebook-ads-library-scraper-meta-ad-api) · [Trustpilot Review Intelligence Suite](https://apify.com/vonsensey/trustpilot-reviews-scraper) · [App Store & Google Play Reviews Suite](https://apify.com/vonsensey/app-store-google-play-reviews-scraper) · [Etsy Research Suite](https://apify.com/vonsensey/etsy-scraper) · [YouTube Comments Intelligence Suite](https://apify.com/vonsensey/youtube-comments-scraper) · [Telegram Channel Intelligence Suite](https://apify.com/vonsensey/telegram-channel-scraper-api) · [Business Reviews Suite](https://apify.com/vonsensey/business-reviews-aggregator-scraper-api) · [Google Trends Suite](https://apify.com/vonsensey/google-trends-scraper) · [Amazon Product Data Suite](https://apify.com/vonsensey/amazon-product-scraper-api) · [Polymarket Order Book](https://apify.com/vonsensey/polymarket-orderbook-clob-prices-scraper-api) · [Nordic Marketplaces Suite](https://apify.com/vonsensey/blocket-finn-nordic-marketplace-scraper-api) · [Google Sheets Suite](https://apify.com/vonsensey/google-sheets-scraper-api) · [TikTok Suite](https://apify.com/vonsensey/tiktok-scraper-api) · [Snapchat Suite](https://apify.com/vonsensey/snapchat-scraper-api) · [LinkedIn Public Data Suite](https://apify.com/vonsensey/linkedin-scraper-api) · [Instagram Suite](https://apify.com/vonsensey/instagram-posts-scraper-api) · [Contact Validation Suite](https://apify.com/vonsensey/email-verifier-validator-api) · [Google Maps Suite](https://apify.com/vonsensey/google-maps-reviews-scraper-api) · [X / Twitter](https://apify.com/vonsensey/tweet-scraper)

Scrape **Vinted** listings, prices, sellers and reviews across **27 country markets**, and get past the hard **960-item cap** that silently truncates every other Vinted tool.

Paste a Vinted URL or type a keyword. Get clean JSON, CSV or Excel — with a per-query report telling you exactly how complete the result was.

- **Past the 960-item cap** — 6.4× more items than any single Vinted query can return, measured.
- **Coverage you can audit** — every run says what it reached and what is genuinely unreachable.
- **`condition` in English on every market** — Vinted returns `Très bon état` / `Sehr gut` / `Bardzo dobry`; a multi-market dataset is unfilterable without this, and no other Vinted tool does it.
- **Listings, sellers, closets and reviews** in one actor, with the two real sale signals the API leaks.

> **Failed inputs are free.** A row that could not be scraped is written to the dataset with a reason and is never charged. If a run returns nothing, it costs nothing.

*Unofficial and not affiliated with, endorsed by, or connected to Vinted. This tool reads only publicly visible marketplace data.*

### How this compares

| | This actor | Typical Vinted actor |
|---|:---:|:---:|
| More than 960 items from a single query | ✅ | ❌ |
| Reports how complete each query actually was | ✅ | ❌ |
| Separates "we stopped at your limit" from "Vinted cannot reach it" | ✅ | ❌ |
| Any number of markets in one run | ✅ | ❌ |
| Item condition in English on every market | ✅ | ❌ |
| Seller's completed-sales count next to their live listings | ✅ | ❌ |
| Marks Vinted's automatic review entries, so cancellations aren't read as sales | ✅ | ❌ |
| No actor-start fee — a run that returns nothing costs nothing | ✅ | ❌ |

<sub>Compared against the 12 largest Vinted actors on Apify Store on 2026-08-13, read from their public input
and dataset schemas rather than their marketing. "Typical" means the clear majority, not every one: a couple of
recent entrants do attempt to break the item cap, and one supports up to five countries per run. Every ✅ above is
something this actor is measured doing — the numbers behind each are in the sections below.</sub>

***

### The 960-item cap, and why your current export is incomplete

Vinted's catalog API returns **96 items per page and stops at page 10**. Page 11 answers `HTTP 400`. So **any single Vinted search returns at most 960 items**, however much stock actually matches.

Worse, the API reports `total_entries: 960` for *every* saturated query — so a tool that trusts that number tells you it found "960 of 960" and looks complete when it is not.

We measured it. Every one of these broad queries reports exactly 960:

| Query | `total_entries` reported |
|---|---|
| `nike` | 960 |
| `zara` | 960 |
| `dress` | 960 |
| `a` | 960 |

You will see it claimed that this field is simply a display constant with no meaning. It is not, and that matters: narrow queries report a **true** count, which is exactly what makes the cap detectable and the fix possible.

| Query | `total_entries` reported |
|---|---|
| `supreme box logo hoodie red` | 298 |
| `chanel haute couture vintage 1987` | 4 |
| `zxcvbnmqwerty` | 1 |

**Deep mode** uses that: it splits a saturated query into price bands, checks each one, and keeps splitting until every band fits under the cap.

Measured on `nike` / vinted.fr on 2026-08-13:

| | Result |
|---|---|
| Distinct items collected | **6,125** |
| What one Vinted query can ever return | 960 |
| Multiplier | **6.4×** |
| Requests used | 129 (0.021 per item) |
| Duplicates in output | 0 |

That run stopped because it hit its 6,000-item target — **not** because the data ran out. It had covered only €1.00–€2.20 of the price range with 11 bands still queued, so 6.4× is a floor, not a ceiling.

#### It tells you when it did not get everything

Every run writes a `RUN_SUMMARY` record with per-query coverage, and the log says so plainly:

```
"nike" (fr): returned 2501 items but the result set was not exhausted
  - 17 price band(s) were left unwalked because maxItems was reached - raise it for more.
```

Three different things are reported separately, because conflating them is how tools mislead you:

- **`unexploredBands`** — reachable; the run stopped at a budget. `stopReason` says which: `targetItems` means raise `maxItems`, `probeBudget` means narrow the query or set a price range.
- **`truncatedBands`** — genuinely unreachable; more than 960 items share one exact price, so no price split can separate them. An honest limit, stated rather than hidden.
- **`failedBands`** — a price range whose size could not be read because the request failed. Those items are unaccounted for, and the run says so instead of counting the band as empty.

***

### How to scrape Vinted search results

Type keywords, pick markets, run.

```json
{
  "searchQueries": ["nike air max", "adidas samba"],
  "markets": ["fr"],
  "maxItems": 500
}
```

For a complete pull of a large query, turn on deep mode and raise the ceiling:

```json
{
  "searchQueries": ["nike"],
  "markets": ["fr"],
  "deep": true,
  "maxItems": 20000
}
```

### How to scrape a Vinted URL

Paste any Vinted URL — filtered catalog, item, or member page. Filters in the URL are carried over, and the country comes from the domain.

```json
{
  "startUrls": [
    "https://www.vinted.fr/catalog?search_text=levis&price_to=25&brand_ids=7",
    "https://www.vinted.pl/items/9651715467-nike-air-max-720",
    "https://www.vinted.de/member/3175818454-someseller"
  ]
}
```

### How to scrape a Vinted seller's closet and reviews

```json
{
  "startUrls": ["https://www.vinted.fr/member/3175818454-someseller"],
  "includeSellerProfile": true,
  "includeSellerReviews": true,
  "maxReviewsPerSeller": 50
}
```

Returns the seller's profile, their listings, and the reviews buyers left — three row types most Vinted tools do not return at all. Reviews are fetched before the listings and every billable row counts toward `maxItems`, so a large closet cannot crowd the reviews out.

**The two real sale signals.** Vinted has no sold-listings search, but two fields leak actual transactions:

- `soldItemCount` on a seller row is their lifetime completed sales, next to `itemCount` (still listed). Together they are a genuine sell-through ratio.
- Each review carries `itemId` and `createdAt` — a review only exists after a transaction on that item. **Check `isAutomatic` first:** Vinted posts system feedback for cancellations too (`"Évaluation automatique : l'acheteur a annulé la transaction"`), so only `isAutomatic: false` rows evidence a completed sale.

### How to scrape Vinted item descriptions

Descriptions are not in the search response. Turn on `includeItemDetail` and each item gets one extra fetch of its page, which adds `description`, `color`, `category`, `isAvailable` and `conditionCode`:

```json
{ "searchQueries": ["carhartt jacket"], "includeItemDetail": true, "maxItems": 50 }
```

A pasted item URL returns the same fields plus `title`, `price` and `currency`, all read off that page. A page with no product data (a sold item's had none on 2026-10-01) returns a free error row instead.

***

### Output

One row per listing. Every field is either a real value or `null` — never a guess.

```json
{
  "type": "listing",
  "id": "9650298818",
  "url": "https://www.vinted.fr/items/9650298818-nike-air-max-blanche",
  "title": "Nike air max blanche",
  "brand": "Nike Air",
  "size": "44",
  "condition": "New with tags",
  "price": 64,
  "currency": "EUR",
  "buyerProtectionFee": 3.9,
  "totalPrice": 67.9,
  "favourites": 5,
  "views": null,
  "photoCount": null,
  "photos": ["https://images1.vinted.net/t/05_0209f_.../f800/1786616038.jpeg"],
  "listedAt": null,
  "sellerId": "3168303451",
  "sellerLogin": null,
  "sellerUrl": "https://www.vinted.fr/member/3168303451",
  "sellerIsBusiness": false,
  "sellerFeedbackReputation": null,
  "sellerFeedbackCount": null,
  "isPromoted": false,
  "market": "fr",
  "description": null,
  "color": null,
  "category": null,
  "isAvailable": null,
  "conditionCode": null,
  "scrapedAt": "2026-08-13T13:28:29.908Z"
}
```

Details worth knowing:

- **`condition` is in English on every market.** Vinted localizes it (`Très bon état`, `Sehr gut`, `Bardzo dobry`), which makes a multi-market dataset impossible to filter. The session requests English, so you get `Very good` everywhere.
- **`totalPrice` is what the buyer actually pays** — `price` plus Vinted's Buyer Protection fee. Comparing raw `price` across listings understates the real cost.
- **`listedAt`, `views` and `sellerLogin` are null on search rows.** Vinted's search stopped exposing `listedAt` and `views` in September 2026, and the seller's login name in October 2026; `sellerId` and `sellerUrl` still identify the seller, and seller and closet rows carry the login. Closet rows still carry `listedAt` (the upload time of the item's first photo, accurate to the day); `views` is null everywhere because Vinted now reports 0 for every item, and a fabricated zero would mislead.
- **`photoCount` is null on search and item-URL rows.** Both name only the main photo (it is in `photos`), so a count would read 1 on a listing with seven. Closet rows list every photo and carry the real count.
- **Item-page fields come in the site's language.** `category` and `color` read as the market's site shows them (`Femmes Chaussures de course`, `Crème`). `conditionCode` is schema.org's class (`NewCondition`, `UsedCondition`): the item page does not state Vinted's own English label, which `condition` carries on search and closet rows.
- **Seller rating on listing rows.** `includeSellerRating` adds `sellerFeedbackReputation` (0-1) and `sellerFeedbackCount`, the values the seller row carries, at one small request per distinct seller. Vinted allows about 30 of those a minute, so 100 rated rows take about 2.5 minutes.

***

### Which markets exist, and the one thing nobody tells you about them

27 markets, verified live on 2026-08-13 — the domain resolved, returned HTTP 200, and yielded listings:

`fr` `de` `uk` `us` `pl` `lt` `es` `it` `nl` `be` `cz` `sk` `at` `lu` `pt` `se` `dk` `fi` `ro` `hu` `gr` `ie` `hr` `si` `lv` `ee` `au`

Currencies observed: EUR, GBP, USD, PLN, CZK, SEK, DKK, RON, HUF, AUD.

Not included, and why: `vinted.no`, `vinted.ch` and `vinted.com.tr` do not resolve; `vinted.ca` returns HTTP 403; **`vinted.bg` serves the Swedish catalog in SEK** (98% of its listings are identical to `vinted.se`, versus 0% overlap with `vinted.fr`), so it is not a Bulgarian market and is excluded.

#### Vinted is one catalog, not 27 marketplaces

This matters for your bill, so here is the measurement rather than the marketing.

| Comparison | Common item IDs | Same price *and* currency |
|---|---|---|
| `nl` vs `be` | 91 | **91** |
| `fr` vs `de` | 68 | **68** |

Identical listings, identical prices. And where the currency differs, the price is a straight conversion:

| Item | Sweden | Denmark |
|---|---|---|
| `9651853828` | 285.42 SEK | 193.28 DKK |
| `9651868165` | 181.63 SEK | 123.00 DKK |

Median implied rate 0.6772 across 93 shared items — the actual SEK→DKK rate, with a 2.4% spread that is rounding.

**Two consequences:**

1. **A listing is billed once across the euro markets.** Pick `fr`, `de`, `nl` and `be` together and a listing all four return is delivered and charged once, tagged with the first market that returned it (its `market` and URL domain); `RUN_SUMMARY.crossMarketDuplicates` counts the repeats dropped. Markets with their own currency (`se`, `dk`, `pl` and the rest) are another price view, so they keep their own rows. Extra euro markets still add requests, and few new listings.
2. **A "cross-country price gap" computed on the same item ID is an FX artifact, not arbitrage.** Any tool comparing raw numbers across markets without normalizing currency reports noise as opportunity.

   To be precise about what this does and does not say: cross-border reselling is a real business. What is not real is a *same-listing* price gap. Genuine dispersion is **within** a market (two sellers pricing the same model differently) and **across platforms** (Vinted versus eBay sold). Both need the full price distribution for a query — which is what deep mode exists to give you, and what a 960-item sample cannot.

***

### What this actor does not do, and why

These are commonly advertised. We could not make them work against the public API, so we do not ship them rather than shipping something that returns nothing.

- **A searchable sold-listings feed.** Vinted deletes sold listings from search and exposes no sold flag, so there is no sold-price history to scrape from the public API. We checked the endpoints this actor uses and found no sold filter that returns data. What this actor *does* give you is the two genuine sale signals the API leaks, both documented below rather than dressed up as a sold feed: a seller's lifetime `soldItemCount`, and per-review `itemId` + timestamp.
- **Cross-country arbitrage signals.** See the measurement above: within the shared EU pool the same item is the same listing at a converted price. We return `price`, `currency` and `totalPrice` so you can normalize deliberately, rather than shipping a gap number that is mostly FX.
- **Item measurements and full attribute sets.** Not exposed by the endpoints this actor uses.

***

### Using it from Python

There are good open-source Vinted wrappers. They break when Vinted changes its session handling or tightens Datadome, and you maintain that yourself. If you would rather not:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("vonsensey/vinted-scraper-api").call(run_input={
    "searchQueries": ["nike air max"],
    "markets": ["fr"],
    "deep": True,
    "maxItems": 5000,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["price"], item["currency"])
```

Node.js, direct HTTP, CSV/Excel download, webhooks and scheduling all work the same way — the dataset is a standard Apify dataset.

***

### Notes on reliability

**The proxy is handled for you: direct first, residential when Vinted refuses.** Vinted is fronted by Datadome. Its search and item pages answer Apify's own servers, so each market starts there, with no proxy cost; the first time Vinted refuses a request (a 403, a 429, a bot interstitial or a dropped connection), that market moves to Apify Proxy `RESIDENTIAL` for the rest of the run. Search pages, item pages and the seller endpoints each allow about 30 requests a minute: on their `HTTP 429` the run pauses that kind of request for 30 s and stays direct (the other kinds keep going meanwhile), and moves only if three pauses in a row bring no answer. A deep run spends those pauses planning its price bands: 200 rows across two markets took about 3 minutes.

| Route (run on Apify) | Result |
|---|---|
| Search page, direct (2026-10-10) | 5 rows, 2 requests, no proxy |
| Item pages, direct (2026-10-10) | 3 item-detail rows, no proxy |
| Seller API, direct (2026-10-10) | 100 of 100 ratings, ~30 a minute with pauses, no proxy |
| Deep search, direct (2026-10-11) | 200 of 200 rows across 2 markets, ~30 pages a minute with pauses, no proxy |
| Old search API, datacenter IP (2026-08-13) | HTTP 403, 0 rows |
| **Apify Proxy `RESIDENTIAL`** | **rows on the first request** |

You do not need to configure anything. If you name a proxy group or your own proxy URLs, they are used as given, with no direct try first.

- **A blocked run costs you nothing.** Blocked requests produce free error rows, never charges. The 403 runs above billed $0.00.
- **Blocks are detected by content, not status code.** An `HTTP 200` carrying a Datadome interstitial is treated as a block and the session is rebuilt, rather than being recorded as zero results.
- **Migration-safe.** Apify restarts containers routinely. Delivered rows are checkpointed, so a resumed run does not re-deliver or re-charge them.
- **Stops inside its time limit.** Near the end of its timeout (a quarter of the run, 20 to 120 s, before it) a run stops starting requests, so it ends SUCCEEDED with the rows it delivered, a free row for each input it did not reach, and its `RUN_SUMMARY`. Listings it had found but had no time left to open come without their item-page fields, billed as plain `listing` rows.

### What a run costs

Pricing is per event. Rows that arrive in bulk from one request are cheap; rows that need their own request cost more.

| Event | What it is | FREE tier | Volume tiers down to |
|---|---|---|---|
| `listing` | A listing row, arriving 96 per request | $0.0030 | $0.0012 |
| `seller-review` | A review row, also arriving in bulk | $0.0030 | $0.0012 |
| `seller` | A seller profile — its own request | $0.0060 | $0.0024 |
| `item-detail` | A listing **upgraded** with its description | $0.0200 | $0.0140 |

**Why `item-detail` is the expensive one.** Vinted publishes descriptions only on the item page, never in the search API, and that page is about 500 KB on the wire (measured 2026-10-01). It goes direct, at about 30 pages a minute per market; through the residential proxy, where a run moves only if Vinted refuses outright, we measured it at **$5.50 per 1,000 rows** to serve, against **$0.071 per 1,000** for plain listings. The price reflects that honestly rather than burying it. Leave `includeItemDetail` off unless you need descriptions.

**There is no actor-start fee**, so a run that returns nothing costs nothing — that promise only works without one.

`item-detail` **replaces** the `listing` charge for that row, it is not added on top. You are never billed twice for one row, and a listing that several euro markets return in one run is billed once.

Deep mode costs nothing extra. It is the product, not an upsell.

### Input reference

| Field | Type | Default | What it does |
|---|---|---|---|
| `searchQueries` | array | `["nike"]` | Keywords, run against every selected market |
| `startUrls` | array | — | Any Vinted catalog, item or member URL |
| `markets` | array | `["fr"]` | Country markets for keyword searches |
| `maxItems` | integer | `100` | Hard ceiling on billable rows. `0` = unlimited |
| `deep` | boolean | `false` | Split past the 960-item cap |
| `priceMin` / `priceMax` | integer | — | Price filter, in the market's currency |
| `sortBy` | enum | `newest_first` | `newest_first`, `relevance`, `price_low_to_high`, `price_high_to_low`. On broad searches Vinted answers `relevance` with paid-promoted listings only |
| `includeItemDetail` | boolean | `false` | Fetch description, colour, category, availability and condition class from each item page |
| `includeSellerRating` | boolean | `false` | Add the seller's feedback reputation and count to listing rows (one request per distinct seller) |
| `includeSellerProfile` | boolean | `false` | Emit seller rows for member URLs |
| `includeSellerReviews` | boolean | `false` | Emit review rows for member URLs |
| `maxReviewsPerSeller` | integer | `25` | Cap on reviews per seller |
| `maxConcurrency` | integer | `5` | Targets in flight at once |
| `requestDelayMs` | integer | `250` | Pause between requests per market |

### Legal

Reads only publicly visible Vinted pages — no login, no private data, no personal data behind authentication. You are responsible for how you use the output, including GDPR obligations where seller information counts as personal data. Not affiliated with Vinted.

### Use it from n8n, MCP, the API or a schedule

Built to be called by a workflow, not only from the Store form. The Actor is `vonsensey/vinted-scraper-api`; every snippet below sends `{}`, which runs the defaults shown on the form — replace it with your own input.

#### n8n

Install the **Apify** community node (`@apify/n8n-nodes-apify` under *Settings → Community Nodes*, or search "Apify" on n8n Cloud). Add **Apify → Run Actor** with Actor `vonsensey/vinted-scraper-api` and your input JSON, then **Apify → Get Dataset Items** on the run's `defaultDatasetId` and pipe the rows anywhere. For scheduled runs, the **On new Apify Event** trigger fires when a run of this Actor finishes.

#### MCP (Claude, Cursor, VS Code, any MCP client)

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=vonsensey/vinted-scraper-api",
      "headers": {
        "Authorization": "Bearer <YOUR_APIFY_TOKEN>"
      }
    }
  }
}
```

Your agent then calls `vonsensey/vinted-scraper-api` as a tool with the same input the form takes and reads the dataset back.

#### REST API (one call, rows in the response)

```bash
curl -X POST "https://api.apify.com/v2/acts/vonsensey~vinted-scraper-api/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" -d '{}'
```

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("vonsensey/vinted-scraper-api").call(run_input={})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row)
```

#### JavaScript

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('vonsensey/vinted-scraper-api').call({});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

#### Make, Zapier, LangChain, CrewAI

The Apify app in **Make** and **Zapier** has a *Run an Actor* module: pick `vonsensey/vinted-scraper-api`. In **LangChain** and **CrewAI** the Apify tool wrappers take the same Actor id. A daily **schedule** needs nothing but the Console: *Schedules → Create → this Actor → cron*, and the dataset fills on its own.

> **Run it without configuring anything** — [Scrape Vinted listings for a search](https://apify.com/vonsensey/vinted-scraper-api/examples/vinted-listings-for-a-search), a ready-made example you can start as-is or copy.

### Use cases

- **Source inventory.** Find underpriced listings across markets faster than the app's own search allows.
- **Price a resale.** See what comparable items are actually listed at, by brand, size and condition.
- **Watch a seller.** Pull a seller's listings and their review history in one run.
- **Track a market on a schedule.** Prices move; a scheduled run turns them into a series.

### Run it on a schedule

A one-off pull answers a question; a schedule answers it every day without you. Open **Schedules** in the Apify Console, point a cron at this Actor, and the dataset keeps filling on its own — no server, no cron box, no babysitting. Everything here is built to be re-run: you are billed per listing delivered, and the FAQ below says exactly what a scheduled run that finds nothing new costs.

### FAQ

#### Which Vinted country markets are supported?

27, selected per run.

#### Can I get past Vinted's 960-item search limit?

Yes — that hard cap is worked around, and every run reports exactly how complete it was rather than quietly truncating.

#### Is seller information included?

Yes: seller profile, rating and reviews alongside the listing.

#### Do I need a Vinted account?

No login and no API key.

***

Something wrong, or a field you need that is missing? Open an issue on the **Issues** tab — it is read and it gets fixed. If this saved you time, a rating on the Store page helps the next person find it.

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords to search for. Each keyword is run against every market you select. Leave empty if you are pasting URLs instead.

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

Paste any Vinted URL and it is handled automatically: a filtered catalog or search URL (its filters are carried over), an item URL (/items/123...), or a member URL (/member/123...). The country is taken from the domain, so a vinted.pl URL is scraped on the Polish market.

## `markets` (type: `array`):

Which country markets to search. Applies to keywords only; pasted URLs keep their own domain. Most European markets share one inventory pool, so extra euro markets add requests but few new listings, and a listing that several euro markets return is delivered and billed once. Markets with their own currency keep their own rows. See the README for the measured overlap.

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

Hard ceiling on billable rows for the whole run. Set 0 for no limit. This is the single most important cost control, especially with Deep mode on.

## `deep` (type: `boolean`):

A single Vinted search returns at most 960 items (96 per page, 10 pages, then HTTP 400) no matter how much stock matches. Deep mode splits the query into price bands so it can reach far more, and reports exactly how complete the result was. Costs extra requests, so raise Max items to make use of it.

## `priceMin` (type: `integer`):

Only return items at or above this price.

## `priceMax` (type: `integer`):

Only return items at or below this price.

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

Result ordering. Newest first returns ordinary listings and is the right choice for monitoring. On broad searches Vinted answers Relevance with paid-promoted listings only (every row isPromoted: true, measured 2026-10-01), so use it for narrow searches. Note: with Deep mode on, price bands are walked from cheapest upward, so a run that stops at Max items returns the cheapest matches regardless of this setting. Turn Deep mode off if ordering matters more than coverage.

## `includeItemDetail` (type: `boolean`):

Fetch each item's page for its full description, colour, category, availability (isAvailable) and schema.org condition class (conditionCode). Vinted only exposes these on the item page, about 500 KB per item on the wire (measured 2026-10-01), direct, at about 30 pages a minute per market (the run pauses when Vinted asks it to slow down), and through a residential proxy only if Vinted refuses outright. It is billed as the item-detail event (about 7x a listing) and that charge REPLACES the listing charge for the row rather than adding to it. Leave it off unless you actually need descriptions.

## `includeSellerRating` (type: `boolean`):

Add each seller's feedback reputation (0-1) and feedback count to their listing rows (sellerFeedbackReputation, sellerFeedbackCount). It costs one small request per distinct seller per market (included in the listing price, which does not change). Vinted allows about 30 of those a minute, so the run pauses when it says so: 100 rated rows take about 2.5 minutes.

## `includeSellerProfile` (type: `boolean`):

For member URLs, also emit a seller row with feedback counts, reputation, location and item count.

## `includeSellerReviews` (type: `boolean`):

For member URLs, also emit the reviews buyers left on that seller. They are fetched before the seller's listings, and both count toward Max items.

## `maxReviewsPerSeller` (type: `integer`):

Caps how many reviews are pulled per seller.

## `maxConcurrency` (type: `integer`):

How many targets to work on at once. Lower this if you see blocking.

## `requestDelayMs` (type: `integer`):

Pause between requests on the same market. Raising it trades speed for a lower chance of being throttled.

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

Optional — proxy is handled for you and its cost is included in the price. When this names no proxy group and no proxy URLs (left empty, switched off, or automatic mode), each market goes direct first and moves to Apify Proxy RESIDENTIAL the first time Vinted's Datadome refuses it. Pick a group or enter your own proxy URLs only if you have a specific reason: they are used as given, with no direct try, and a datacenter group may return only free error rows.

## Actor input object example

```json
{
  "searchQueries": [
    "nike"
  ],
  "markets": [
    "fr"
  ],
  "maxItems": 100,
  "deep": false,
  "sortBy": "newest_first",
  "includeItemDetail": false,
  "includeSellerRating": false,
  "includeSellerProfile": false,
  "includeSellerReviews": false,
  "maxReviewsPerSeller": 25,
  "maxConcurrency": 5,
  "requestDelayMs": 250
}
```

# Actor output Schema

## `listings` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

# 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 = {
    "searchQueries": [
        "nike"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("vonsensey/vinted-scraper-api").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 = { "searchQueries": ["nike"] }

# Run the Actor and wait for it to finish
run = client.actor("vonsensey/vinted-scraper-api").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 '{
  "searchQueries": [
    "nike"
  ]
}' |
apify call vonsensey/vinted-scraper-api --silent --output-dataset

```

## MCP server setup

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

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/vYMeJCbHvr7ZZhHcg/builds/AqrhhBl8uGPOxn0qv/openapi.json
