# Vinted Scraper & Tracker: New Listings, Price Drops, Sold (`apizilla/vinted-tracker`) Actor

Scrape Vinted listings from 26 country sites in one run (keywords, brands, sizes, price, condition or search URLs) and track them: new listings, price drops, reserved and sold alerts, plus deals below the search median.

- **URL**: https://apify.com/apizilla/vinted-tracker.md
- **Developed by:** [APIzilla](https://apify.com/apizilla) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 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.

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

### What does Vinted Scraper & Tracker do?

Vinted Scraper & Tracker scrapes **listings from [Vinted](https://www.vinted.com)**, the second-hand fashion marketplace, on **26 country sites** in one run: France, Germany, UK, Spain, Italy, Netherlands, Belgium, Poland, Portugal, Austria, Lithuania, Czechia, the US and more.

Search with **keywords and filters** (brand, category, size, condition, price) or paste **Vinted search URLs**. You get price, price with buyer protection, brand, size, condition, photos, favourites and seller for every listing.

It also **tracks your searches between runs** and tells you what changed:

- **New listings** (catch good items minutes after upload)
- **Price drops** and **price increases**
- **Reserved** items
- **Sold** and **removed** items
- **Relisted** items

And it flags **deals**: listings well below the median price of the same search.

### Why use Vinted Scraper & Tracker?

- **Alerts, not only data.** Schedule it every 15-60 minutes with **Only changes** on, and get only new listings, price drops and sold items. Quiet runs cost only the start fee.
- **Sold detection.** When a tracked item leaves the search, the Actor opens its page and tells you if it was **sold, reserved, deleted** or only re-priced.
- **Many countries, one run.** Search `levis 501` on vinted.fr, vinted.de and vinted.co.uk at once. Items listed on several sites come once, with `alsoOnSites`.
- **Deals.** Every listing gets `medianPriceInSearch`, `percentBelowMedian` and `isDeal`. Free.
- **Fast and cheap.** No browser: plain HTTP, 512 MB memory. Direct connection first, residential proxy only for a country site that Vinted blocks.
- **Pay per listing.** Not per page, not per minute.

Typical users: resellers and flippers, vintage shops, brand and price analysts, collectors, deal-alert bots and apps.

You also get everything the Apify platform offers: schedules, API, webhooks and integrations (Google Sheets, Make, Zapier, Slack, Telegram via Make or n8n).

### What data does it extract?

| Field | What it is |
| --- | --- |
| `id`, `title`, `url` | Vinted item ID, title and link |
| `price`, `currency` | Seller price in the site currency (EUR, GBP, PLN, CZK, SEK, USD...) |
| `totalPrice`, `buyerProtectionFee` | Price with the Vinted buyer protection fee |
| `brand`, `size`, `condition`, `conditionCode` | Brand, size, condition (`new_with_tags`, `very_good`...) |
| `photo`, `photos` | Photos |
| `favouriteCount` | Favourites (hearts) |
| `sellerId`, `sellerUrl`, `sellerIsBusiness` | Seller |
| `sellerLogin`, `sellerRating`, `sellerFeedbackCount` | Seller name, rating 0-5 and reviews (Item details or Seller profiles) |
| `sellerCountry`, `sellerCity`, `sellerItemCount`, `sellerFollowers`, `sellerLastLoginAt` | With **Seller profiles** |
| `description`, `color`, `material`, `category`, `uploadedAgo`, `uploadedAt`, `isReserved` | With **Item details** |
| `medianPriceInSearch`, `percentBelowMedian`, `isDeal` | Deal check |
| `changeType`, `previousPrice`, `priceChange`, `priceChangePercent`, `priceHistory`, `lowestPriceSeen`, `firstSeenAt`, `goneAt` | Change tracking |
| `site`, `domain`, `alsoOnSites`, `searchKeyword`, `searchUrl` | Where it was found |

`changeType` is one of `baseline` (first run), `unchanged`, `new_listing`, `price_drop`, `price_increase`, `reserved`, `sold`, `removed`, `relisted`.

Vinted does not show view counts to visitors, so there is no views field. The exact upload time is not public either: `uploadedAt` is computed from the "2 hours ago" text, and `firstSeenAt` tells you when the tracker first saw the item.

### How to scrape Vinted

1. Go to the **Input** tab.
2. Type **Keywords**, for example `levis 501`, `nike dunk`, `barbour jacket`. Or paste **Vinted search URLs** from the website.
3. Pick the **Countries**.
4. Optional: **Brands**, **Category IDs**, **Sizes**, **Condition**, **Min / Max price**.
5. Set **Max listings**.
6. Optional: turn on **Item details** or **Seller profiles**.
7. Click **Start**, then download JSON, CSV or Excel.

```json
{
    "keywords": ["levis 501"],
    "countries": ["fr", "de", "uk"],
    "conditions": ["very_good", "new_without_tags"],
    "maxPrice": 40,
    "maxItems": 100,
    "trackChanges": true,
    "trackerName": "levis-501"
}
```

### How to get alerts for new Vinted listings, price drops and sold items

1. Set up your search and a **Tracker name**, for example `dunk-low-42`.
2. Run it once. This saves the **baseline** (every listing has `changeType: "baseline"`).
3. Turn on **Only changes**.
4. Add a **schedule** (Actor > Schedules), for example every 30 minutes.
5. Connect an integration (Slack, email, Google Sheets, a webhook) to get each change.

Runs with the same tracker name compare with each other. Use a different name for each search you want to track. The memory is stored in a named key-value store `vinted-tracker-<tracker name>` in your account.

**How sold detection works:** Vinted does not list sold items in search results. When a tracked item is missing from a search that should show it, the Actor opens the item page (**Check gone items**, max 30 per run by default): `sold` when Vinted shows it as sold, `removed` when the page is gone, `reserved` when a buyer reserved it, or a price change if the seller only changed the price.

Tip: sort by **Newest first** (the default) for tracking. Vinted shows at most 960 results per search, so narrow wide searches with filters.

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

Pay per event:

| Event | Price |
| --- | --- |
| Listing saved | $1.00 per 1,000 |
| Change alert (new listing, price drop, sold...) | $0.50 per 1,000 |
| Item details | $1.00 per 1,000 |
| Seller profile | $0.50 per 1,000 sellers |
| Actor start | $0.003 per run |
| Residential proxy page (only if Vinted blocks the direct connection for a site) | $0.004 per page |

Examples:

- 1,000 listings from three countries: about **$1.00**.
- A tracker running every 30 minutes with **Only changes** and 20 new listings per run: 48 runs x ($0.003 + 20 x $0.0015) = about **$1.60 per day**. Quiet runs cost $0.003.
- Sold items and price changes found by the gone check cost only the change alert.

Set **Maximum cost per run** in the run options: the Actor stops cleanly at that limit and never charges for an item it did not save.

### Input options

- **Keywords**: each keyword is one search in each country. Vinted search also finds similar items; turn on **Keywords must be in the title** for exact matches.
- **Countries**: `fr`, `de`, `uk`, `es`, `it`, `nl`, `be`, `pl`, `pt`, `at`, `lt`, `cz`, `sk`, `lu`, `ie`, `se`, `dk`, `fi`, `gr`, `hu`, `ro`, `hr`, `si`, `ee`, `lv`, `us`.
- **Vinted search URLs**: any `https://www.vinted.../catalog?...` URL. Its filters are used as they are.
- **Brands**: looked up on Vinted and used as a brand filter.
- **Category IDs**: the number in `/catalog/<ID>-...` (you can paste the category URL).
- **Sizes**: as Vinted writes them (`M`, `42`, `W32`), exact match.
- **Condition**, **Min / Max price** (in each site's currency), **Exclude words**, **Sort**.
- **Max listings**, **Max listings per search**, **Max pages per search** (96 listings per page).
- **Item details**, **Seller profiles**, **Find deals**, **Deal threshold**, **Only deals**.
- **Track changes**, **Tracker name**, **Only changes**, **Check gone items**, **Max gone checks per run**.
- **Proxy**: leave the default (Apify Proxy, no group). Each country site connects directly first and switches to the residential proxy of that country only if Vinted blocks it. In our tests all 13 tested country sites worked directly. A page that needs the residential proxy costs the extra residential page fee (search pages are about 0.5 MB, so this covers our proxy cost).

### Output example

```json
{
    "id": "10498509794",
    "changeType": "price_drop",
    "title": "Levi's 501 W32 L32",
    "price": 18,
    "currency": "EUR",
    "totalPrice": 19.6,
    "buyerProtectionFee": 1.6,
    "previousPrice": 25,
    "priceChange": -7,
    "priceChangePercent": -28,
    "brand": "Levi's",
    "size": "W32 | FR 42",
    "condition": "Très bon état",
    "conditionCode": "very_good",
    "url": "https://www.vinted.fr/items/10498509794-levis-501",
    "site": "fr",
    "alsoOnSites": ["de"],
    "photo": "https://images1.vinted.net/t/.../f800/....webp",
    "favouriteCount": 4,
    "sellerId": "166514974",
    "sellerLogin": "leandro2780",
    "sellerRating": 4.9,
    "sellerFeedbackCount": 27,
    "sellerCountry": "PT",
    "medianPriceInSearch": 26.95,
    "percentBelowMedian": 27.3,
    "isDeal": true,
    "firstSeenAt": "2026-10-23T08:00:00.000Z",
    "priceHistory": [{ "date": "2026-10-23", "price": 25 }, { "date": "2026-10-24", "price": 18 }]
}
```

The run summary (status per search and country, changes, gone checks, charged events) is in the key-value store record `OUTPUT`.

### FAQ

**Is it legal to scrape Vinted?** The Actor reads public pages only, without logging in. You are responsible for how you use the data. Personal data (seller usernames, cities) is protected by GDPR in the EU: only collect what you need and have a legal reason. Read [Apify's blog on web scraping legality](https://blog.apify.com/is-web-scraping-legal/).

**Do I need a Vinted account?** No.

**Why did a search return items that do not match my keyword exactly?** Vinted search is fuzzy. Turn on **Keywords must be in the title**, or add brands and exclude words.

**A country was blocked.** The Actor switches that site to the residential proxy on its own (and charges the residential page fee for those pages). If it still fails, pick the RESIDENTIAL proxy group in the input.

**Can I get the buyer's shipping price?** No, shipping depends on the buyer's address and the carrier.

Found a problem or need a field? Open an issue on the **Issues** tab.

# Actor input Schema

## `keywords` (type: `array`):

What to search for, as you would type it on Vinted, for example "levis 501", "nike dunk", "barbour jacket". Each keyword is one search in each country. Empty: use brands, category or search URLs only.

## `countries` (type: `array`):

Vinted country sites to search. Several countries run in one go. Prices are in the currency of each site.

## `searchUrls` (type: `array`):

Or paste searches from the Vinted website: open a search, set the filters, copy the URL (https://www.vinted.fr/catalog?search_text=...). Any country site. The filters in the URL are used as they are.

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

Only these brands, for example "Levi's", "Nike", "Zara", "Ralph Lauren". Looked up on Vinted and used as a brand filter.

## `categoryIds` (type: `array`):

Vinted category IDs, for example 1231 (men's shoes) or 2050 (men's clothing). Open the category on Vinted: the ID is the number in /catalog/<ID>-... . You can also paste the category URL.

## `sizes` (type: `array`):

Only these sizes, as Vinted shows them: "M", "L", "42", "W32", "UK 9". Exact match (case-insensitive).

## `conditions` (type: `array`):

Only these conditions. Empty: all.

## `minPrice` (type: `integer`):

Lowest price, in the currency of each country site (EUR, GBP, PLN...).

## `maxPrice` (type: `integer`):

Highest price, in the currency of each country site.

## `excludeKeywords` (type: `array`):

Drop listings whose title or brand has one of these words, for example "kids", "replica".

## `strictKeywords` (type: `boolean`):

Vinted search also finds similar items. Turn on to keep only listings whose title or brand has every word of the keyword.

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

Order of the Vinted results. "Newest first" is best for tracking new listings.

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

Most listings to save in one run (all searches together). Changes are saved first.

## `maxItemsPerSearch` (type: `integer`):

Most listings per search (keyword x country, or URL). Empty: Max listings divided by the number of searches.

## `maxPagesPerSearch` (type: `integer`):

Each page has up to 96 listings. Vinted shows at most 10 pages (960 listings) per search.

## `includeDetails` (type: `boolean`):

Open each saved listing for the description, colour, material, category, upload time, reserved status, all photos and the seller name, rating and review count. Charged per item (see pricing).

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

Add the seller profile: username, rating (0-5), number of reviews, country, city, business account, items for sale, followers, last login. Charged once per seller.

## `computeDeals` (type: `boolean`):

Compare every listing with the median price of its search (same currency, at least 8 listings) and flag the ones well below it. Free.

## `dealThresholdPercent` (type: `integer`):

A deal is a listing at least this many percent below the search median (price with buyer protection).

## `onlyDeals` (type: `boolean`):

Save only listings flagged as deals.

## `trackChanges` (type: `boolean`):

Remember the listings between runs and report new listings, price drops and increases, reserved, sold and removed items. The first run saves the baseline. Schedule the Actor (for example every 30 minutes) to get alerts.

## `trackerName` (type: `string`):

Name of this tracker, for example "levis-501-fr". Runs with the same name compare with each other. Empty: a name made from your searches. Letters, numbers and dashes.

## `onlyChanges` (type: `boolean`):

Save only listings that changed since the last run (new listing, price drop, reserved, sold...). Good for scheduled alerts: quiet runs cost only the start fee.

## `checkGoneItems` (type: `boolean`):

When a tracked listing is no longer in the search results, open its page to tell if it was sold, reserved, deleted or only re-priced. Without it, gone items are reported as "removed" only when the whole search was read.

## `maxGoneChecks` (type: `integer`):

Most item pages opened per run to check gone listings. The rest are checked in the next runs.

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

Leave the default (Apify Proxy, no group). Each country site connects directly first (no proxy cost) and switches to RESIDENTIAL proxy (same country) only if Vinted blocks it. Pages loaded through RESIDENTIAL cost an extra "residential page" fee. You can also pick a group or use your own proxies.

## Actor input object example

```json
{
  "keywords": [
    "levis 501"
  ],
  "countries": [
    "fr",
    "de"
  ],
  "strictKeywords": false,
  "sort": "newest_first",
  "maxItems": 50,
  "maxPagesPerSearch": 3,
  "includeDetails": false,
  "includeSellerDetails": false,
  "computeDeals": true,
  "dealThresholdPercent": 25,
  "onlyDeals": false,
  "trackChanges": true,
  "onlyChanges": false,
  "checkGoneItems": true,
  "maxGoneChecks": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with one item per listing or change

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

Status per search and country, counts, changes and charged events

# 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 = {
    "keywords": [
        "levis 501"
    ],
    "countries": [
        "fr",
        "de"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("apizilla/vinted-tracker").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 = {
    "keywords": ["levis 501"],
    "countries": [
        "fr",
        "de",
    ],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("apizilla/vinted-tracker").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 '{
  "keywords": [
    "levis 501"
  ],
  "countries": [
    "fr",
    "de"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call apizilla/vinted-tracker --silent --output-dataset

```

## MCP server setup

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

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/p7WSEg6GzCVYEHnfM/builds/XcA1xcQalmBTqQZln/openapi.json
