# Vinted Scraper: New Listings, Prices & Deal Alerts (`moggedhq/vinted-scraper-alerts`) Actor

Get Vinted listings for searches such as Nike trainers or vintage denim, with price, size, condition, seller ratings and photos. Track new listings and price drops across countries with sampled deal scores. $0.0015 per listing; 100 cost $0.15. Details optional. No login.

- **URL**: https://apify.com/moggedhq/vinted-scraper-alerts.md
- **Developed by:** [mogged](https://apify.com/moggedhq) (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.20 / 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: New Listings, Prices & Deal Alerts

For resellers and vintage dealers monitoring Vinted asking prices, new listings and price drops. **A listing costs $0.0015: 100 listings cost $0.15**, plus the small platform start charge. Optional full details add $0.0075 per successfully enriched listing. No Vinted login.

Search Nike trainers, vintage denim or the brands you buy regularly. Compare the same search across country sites, filter price, brand, size and condition, and export structured rows. Save a watch once and reuse its `watchId` to receive newly observed listings and lower prices in later runs. The first priced cloud test returned 20 listings in 11.8 seconds. Validation included 31 successful varied cloud inputs across eight country sites, ten readable live listing checks, and a public seller-statistics check. Extraction reads structured data inside public pages and does not require a browser.

### What you get

Each `LISTING` row starts with a short verdict: its price, its position relative to the sampled search median, and its condition. Watch rows identify new observations or lower prices. A separate free `SUMMARY` reports delivered listings, new items, price drops, country medians and source failures.

| Field | Meaning |
| --- | --- |
| `verdict` | Plain-language price, deal context and watch changes |
| `itemId`, `title` | Stable listing ID and source title |
| `brand`, `size`, `condition` | Public attributes in the site's language |
| `price`, `currency` | Original asking price and currency before shipping |
| `totalPriceWithFees` | Displayed total with Vinted fees when supplied; excludes shipping |
| `priceConverted`, `convertedCurrency` | Optional converted price for comparison |
| `previousPrice`, `priceChange` | Prior observed price and signed difference in original currency |
| `isNewSinceLastRun` | New to this watch; null outside watch mode |
| `dealScore` | Whole-number percent below the sampled median; negative means above |
| `medianPrice`, `medianSampleSize` | Comparison median and sample size |
| `category`, `colour` | Attributes from successful item enrichment |
| `favourites`, `views` | Engagement counts when supplied publicly |
| `listedAt` | Exact source timestamp when available; otherwise null |
| `listingDateText` | Displayed relative listing date with details enabled |
| `country` | Country site searched, separate from seller country |
| `observedCountries` | Country sites where this deduplicated listing was observed |
| `sellerUsername` | Public shop username with full details enabled |
| `sellerRating` | Public reputation expressed on a five-point scale |
| `sellerReviewCount`, `sellerItemCount` | Public reviews and inventory when available |
| `sellerCountry` | Public seller country code when available |
| `description`, `photos` | Optional description and public image URLs |
| `detailsIncluded`, `detailStatus` | Enrichment success and seller availability |
| `url`, `scrapedAt` | Listing link and observation time in UTC |

Missing values stay null. A page saying an item was added a few minutes ago does not supply an exact timestamp. The scraper keeps that text separately rather than inventing a precise date. Seller enrichment excludes private profile fields, personal contact fields, addresses and biographies.

### Start in three steps

1. Enter one search term and country. Keep `maxItems` at 20 for the first run.
2. Open the listing overview. Check that the brands, conditions and sizes suit your buying rules.
3. Export JSON, CSV or Excel, or save the input as an Apify task. Add a schedule after checking the result.

```json
{
  "searchTerms": ["nike trainers"],
  "countries": ["fr"],
  "maxItems": 20,
  "sort": "newest_first"
}
```

`maxItems` is the combined delivery limit across all searches and countries. Sources share that limit in rotation. An item found in overlapping searches is delivered and charged once within the run.

### Inputs and filters

| Input | Default | Use |
| --- | --- | --- |
| `searchTerms` | Prefilled example | Ordinary search phrases such as vintage denim |
| `countries` | `fr` | `fr`, `de`, `gb`, `it`, `es`, `nl`, `be`, `pl`; `uk` is accepted as `gb` |
| `startUrls` | Empty | Optional catalog, category or item links on supported sites |
| `brands` | Empty | Exact displayed brand labels or native numeric IDs |
| `sizes` | Empty | Exact displayed size labels or native numeric IDs |
| `conditions` | Empty | Exact source-language labels or native numeric IDs |
| `priceMin`, `priceMax` | Unset | Asking-price bounds in each site's original currency |
| `currency` | Unset | Optional comparison currency such as EUR, GBP or USD |
| `sort` | `newest_first` | Also lowest price, highest price or relevance |
| `maxItems` | 20 | Maximum unique delivered listings, from 1 to 1,000 |
| `includeDetails` | False | Slower item and public seller enrichment |
| `onlyNewSinceLastRun` | False | Persistent new-listing and price-drop monitoring |
| `watchId` | `default` | Stable identifier for independent history |
| `proxyConfiguration` | Automatic | Optional custom Apify proxy settings |

Text labels match exactly, ignoring letter case. A French condition label and an English condition label are different filters. For complex native filters, configure your search on Vinted and paste its catalog URL. Numeric filters already in that URL are retained. Sorting, pagination and explicit price bounds follow the Actor inputs.

```json
{
  "searchTerms": ["nike"],
  "countries": ["fr"],
  "brands": ["Nike"],
  "priceMin": 10,
  "priceMax": 30,
  "maxItems": 50
}
```

Vinted may place promoted listings ahead of ordinary newest results. Filtering can produce fewer results than requested. An empty search is legitimate and has no listing charge. Invalid inputs produce a free note explaining what to correct.

### Monitor prices every day

Save this input as an Apify task, then give that task a schedule:

```json
{
  "searchTerms": ["vintage denim"],
  "countries": ["gb"],
  "priceMax": 40,
  "onlyNewSinceLastRun": true,
  "watchId": "denim-gb",
  "maxItems": 100
}
```

The first run establishes a baseline and returns up to the output limit. Later runs return newly observed listings and price drops. Unchanged listings have no listing charge. A price increase updates history, so a later decrease is compared with the most recent observed price.

History remembers the matching observation window, including items omitted by the output limit. Those older items do not become false new alerts next time. When a spending limit stops delivery, undelivered observations are not silently consumed as a new baseline. History is private to your Apify account, this Actor and your `watchId`.

Use one sequential schedule per watch. An atomic lock prevents overlapping runs from writing the same history. A competing run ends with a free watch-busy note. Rebooting the original run resumes its saved source snapshot and delivery ledger. After interruption, resume that run when you need the same observation window.

An alert is an output row for your automation. The Actor does not send messages or buy items. Connect successful output to your webhook, spreadsheet, Make or n8n workflow. Start with a daily schedule; choose faster checks after measuring how much new inventory your search receives. Keep your maximum run charge set before increasing frequency.

### Compare countries and understand deals

```json
{
  "searchTerms": ["nike"],
  "countries": ["fr", "de", "gb", "it", "es"],
  "currency": "EUR",
  "maxItems": 100
}
```

Original prices remain unchanged. Comparison conversion uses daily European Central Bank reference rates and includes the rate date where available. It is not a checkout quote. If a rate is unavailable, the converted value stays null. Price bounds apply to original site currencies, so choose them carefully across different markets.

The deal score is `(sample median - asking price) / sample median * 100`, rounded to a whole percent. A score of 25 means an asking price 25% below that sample median. At least five comparable sampled listings are required; exact item lookups and tiny samples can have a null score.

The comparison uses matching sampled listings from the same search, country and currency, including listings outside the small export limit. Country summaries deduplicate overlapping items. Asking-price differences do not account for authenticity, shipping, condition differences or eventual sold prices. Check the actual listing before purchasing.

### Optional detail enrichment

Enable `includeDetails` for description, colour, category, more photos and public seller statistics. Successful item enrichment adds $0.0075 before tier discounts. A missing seller page is shown in `detailStatus` and the summary. Public seller usernames are shop identifiers; private profile attributes are excluded.

If an item page is unavailable, a useful catalog row can still be delivered at the base price. Unavailable enrichment is not charged. Email addresses and international telephone patterns are removed from descriptions. No account credentials or private seller records are requested.

### Prices and spending limits

| Delivered output | List price |
| --- | --- |
| 20 plain listings | $0.03 |
| 100 plain listings | $0.15 |
| 1,000 plain listings | $1.50 |
| 20 listings with successful details | $0.18 |
| 100 listings with successful details | $0.90 |

The platform start fee is $0.00005 at default memory. Bronze receives 5% off listing and detail prices, Silver 10%, Gold 20%. Apify's Pricing tab shows your exact tier. Summaries, notes, duplicates and failed enrichments have no result charge. There is no extra tracked-search or watch-check event.

Set the maximum total charge before larger jobs. The scraper checks that a complete useful row is affordable, stops cleanly at the limit, and explains the stop in the summary. A successful final charge can consume the remaining capacity; the row is still delivered.

### API examples

Load your own Apify token from the environment. Never put credentials in datasets or support messages.

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("moggedhq/vinted-scraper-alerts").call(
    run_input={"searchTerms": ["vintage denim"], "countries": ["gb"], "maxItems": 20}
)
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row.get("recordType") == "LISTING":
        print(row["title"], row["price"], row["url"])
```

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('moggedhq/vinted-scraper-alerts').call({
  searchTerms: ['nike trainers'], countries: ['fr'], maxItems: 20
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const listings = items.filter(row => row.recordType === 'LISTING');
```

The output panel links to the overview, a free filtered DEALS record and the summary. The dataset deals view provides comparison columns for all listings. Filter `recordType` when processing the raw dataset: a summary or note is not a listing.

### Use with AI agents (MCP)

Connect an Apify-compatible agent to `https://mcp.apify.com`. Ask it to use `moggedhq/vinted-scraper-alerts`, run a small input, and retrieve the dataset and summary. A useful request is: Find 20 Nike listings in France below EUR 30, return prices and conditions, and show below-median deals. Enable details only when you need descriptions or seller statistics.

### Limits and FAQ

**Does this show sold prices?** No. It observes public asking prices. A disappeared listing is not labelled sold.

**Are all countries supported?** Eight country sites are supported. Other domains produce a note. Sellers can be from other connected countries, so site country and seller country are separate.

**Is search exhaustive?** No. Each source is bounded to ten public pages, with its page allowance derived from `maxItems`. Watches observe that bounded matching window. Use narrower native filters or a larger output limit for wider coverage.

**Why are fields null?** Public responses do not always expose views, exact listing dates or seller statistics. Missing information remains unknown. Relative dates are preserved without estimating an exact timestamp.

**Can the same item appear twice?** Once per run after deduplication. It can appear in another ordinary run. Watch mode suppresses unchanged observations and records observed price differences.

**Can a run be partial?** Yes. Removed pages and persistent source refusals are reported. Useful available rows remain, while unavailable details are not charged. Requests are paced and retried with fresh connections, with residential proxy used after cheaper routes fail.

**Can I supply Vinted cookies?** No. This is a signed-out public-data Actor. It does not solve challenges, log in or perform account actions.

**What persists?** Named watch history and coordination records. Ordinary runs have separate datasets. A new watch name creates new history. You can remove the named storage from your own Apify account when that history is no longer needed.

# Actor input Schema

## `searchTerms` (type: `array`):

Searches such as nike trainers or vintage denim. Each term is searched in each country.

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

Site country codes: fr, de, gb, it, es, nl, be or pl. The site country is separate from the seller country.

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

Optional HTTPS catalog, category or item links from a supported Vinted site. Existing numeric filters are preserved.

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

Exact public brand labels, such as Nike, or numeric Vinted brand IDs.

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

Exact displayed size labels, such as M, or numeric Vinted size IDs.

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

Exact displayed condition labels in the source language, or native numeric Vinted status IDs.

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

Asking price filter in the original site currency, before fees and shipping.

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

Asking price filter in the original site currency, before fees and shipping.

## `currency` (type: `string`):

Optional uppercase currency code such as EUR, GBP or USD. Original prices remain unchanged; converted values use daily ECB reference rates.

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

Newest first is the default. Promoted listings may be placed ahead of ordinary listings by the site.

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

Maximum unique delivered listing rows across all searches and countries. Free summaries and notes do not count.

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

Slower. Add full description, colour, category, photos and public seller username, rating, review count and inventory when shown. Successful enrichment adds $0.0075 per listing; unavailable enrichment has no detail charge.

## `onlyNewSinceLastRun` (type: `boolean`):

Remember delivered IDs and prices in a named watch store. The first run delivers a baseline. Later runs deliver newly observed listings and lower prices. Run the same watch sequentially.

## `watchId` (type: `string`):

Stable name for an independent history, such as denim-fr. Changing it creates a new baseline. A lock prevents overlapping runs for one watch.

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

Optional custom Apify proxy configuration. By default try datacenter, direct cloud HTTP, then residential in the source country.

## Actor input object example

```json
{
  "searchTerms": [
    "nike trainers"
  ],
  "countries": [
    "fr"
  ],
  "sort": "newest_first",
  "maxItems": 20,
  "includeDetails": false,
  "onlyNewSinceLastRun": false,
  "watchId": "default"
}
```

# Actor output Schema

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

No description

## `deals` (type: `string`):

No description

## `summary` (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 = {
    "searchTerms": [
        "nike trainers"
    ],
    "countries": [
        "fr"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("moggedhq/vinted-scraper-alerts").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 = {
    "searchTerms": ["nike trainers"],
    "countries": ["fr"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("moggedhq/vinted-scraper-alerts").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 '{
  "searchTerms": [
    "nike trainers"
  ],
  "countries": [
    "fr"
  ],
  "maxItems": 20
}' |
apify call moggedhq/vinted-scraper-alerts --silent --output-dataset

```

## MCP server setup

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

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/rbLGgndrLFPMQJMne/builds/UCfmJuiS3PVyVH5xf/openapi.json
