DEV Community

Cover image for How to Scrape Vinted Listings with Python
ReventaData
ReventaData

Posted on Originally published at apify.com

How to Scrape Vinted Listings with Python

By the end of this tutorial, you will have a Python script that pulls second-hand fashion listings from Vinted Spain (vinted.es) into structured JSON: title, item asking price, buyer protection service fee, total price in EUR, brand, item condition, size, photo URL, favourite count, and seller type.

Vinted is a popular European marketplace where people buy and sell second-hand clothes, shoes, bags and accessories. Searching the catalog manually and copying product listings into a spreadsheet is slow and repetitive, and each search result page shows up to 96 items.

In this guide, we use Python and the Apify Actor Vinted Spain Scraper (reventadata/vinted-scraper). Our benchmark run (configured with searchQueries: ["nike"], conditions: ["Muy bueno", "Bueno"], minPrice: 10, maxPrice: 40, sortBy: "relevance", requireKeywordMatch: true, and maxItems: 200) finished in 19.2 seconds and returned 200 items.

⏱️ Time estimate: About 30 minutes.


Prerequisites

To follow this tutorial, you will need:

  1. Python 3.11+ installed locally on your system.
  2. The Apify API client for Python (pip install apify-client).
  3. An Apify account and its API token.

Copy your API token from API & Integrations in the Apify Console settings, and then install the official Apify client library in your terminal:

pip install apify-client
Enter fullscreen mode Exit fullscreen mode

What you'll achieve

You will run the Actor from Python and receive clean, structured JSON records for matching listings on Vinted Spain, up to the maxItems and maxPages caps. The scraper extracts item records directly from the server-rendered catalog pages, so individual listing pages do not need to be opened separately.

Note on pricing structures: Vinted displays both the seller's asking price and a buyer protection fee. The dataset separates these into price (the listing item price), serviceFee (the buyer protection fee), and totalPrice (item price plus service fee in EUR).

Example use case: Suppose you want to monitor second-hand Nike sportswear priced between 10 EUR and 40 EUR in very good or good condition. Setting searchQueries: ["nike"] with conditions: ["Muy bueno", "Bueno"], minPrice: 10, and maxPrice: 40 returns matching listings, up to your maxItems cap.


Step 1: Access Vinted Spain Scraper

Open the Vinted Spain Scraper page on Apify Store. The store listing details available input parameters, output schemas, and sample records. You can click Try for free to inspect the Actor in the Apify Console web interface. In this guide, we invoke the scraper directly using Python code.


Step 2: Configure search parameters

The primary configuration property is searchQueries, an array of search keywords. Each query searches the vinted.es catalog across fashion, footwear, electronics and home. You can also specify optional conditions, minPrice, maxPrice, and sortBy. Here is the Python script with the same input we used for our benchmark run:

from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run_input = {
    "searchQueries": ["nike"],
    "conditions": [
        "Muy bueno",
        "Bueno",
    ],
    "minPrice": 10,
    "maxPrice": 40,
    "sortBy": "relevance",
    "requireKeywordMatch": True,
    "maxItems": 200,
}

run = client.actor("reventadata/vinted-scraper").call(run_input=run_input)

for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item["title"], item["price"], item["totalPrice"], item["currency"], item["url"])
Enter fullscreen mode Exit fullscreen mode

This code uses the exact settings behind the metrics in this article. Setting maxItems: 200 stopped collection once 200 rows were saved, while requireKeywordMatch: True ensures every retained listing matches the search term.


Step 3: Configure optional settings and filters

The Actor provides multiple configuration options and filtering switches:

Parameter Type Default What it does
searchQueries array none List of search keywords on vinted.es. Required unless you provide catalogIds.
conditions array [] Condition filters: "Nuevo con etiquetas", "Nuevo sin etiquetas", "Muy bueno", "Bueno", "Satisfactorio".
minPrice integer none Minimum asking price in EUR, evaluated on the item price before service fee.
maxPrice integer none Maximum asking price in EUR, evaluated on the item price before service fee.
sortBy string relevance Sort order: relevance, priceAsc, priceDesc, or newest.
sellerType string any Filter sellers: any, private, or professional.
catalogIds array none Vinted category IDs (such as 2994 for Electronics or 1904 for Women) to narrow searches or browse categories.
brandIds array none Vinted brand IDs (such as 105 for Primark or 7 for H&M) scoped to the relevant category.
requireKeywordMatch boolean true Drops items whose title, brand, and model together do not contain every word of the search query.
maxItems integer 960 Hard cap on total rows saved across all search queries (minimum 1, prefill 10).
maxPages integer 10 Maximum catalog result pages per query (1 to 10; Vinted limits anonymous access to 10 pages).

Three operational details help you configure these filters effectively:

  • Private sellers carry no seller identifiers. The Actor evaluates seller type from Vinted's business flag. For private sellers, sellerId, sellerLogin, and sellerProfileUrl are omitted from the row to protect personal privacy, while sellerType is retained. For professional accounts, sellerId and sellerProfileUrl are included.
  • Vinted enforces a 10-page anonymous catalog ceiling. Vinted serves at most 10 pages of 96 items (960 items) per query to anonymous visitors. The input schema allows at most 10 pages, and the Actor clamps maxPages to this maximum because subsequent pages return empty item arrays on the site.
  • Price filters evaluate item asking prices. minPrice and maxPrice apply to the seller's asking price before Vinted's buyer protection fee is added.

Step 4: Run the Actor

Replace <YOUR_APIFY_TOKEN> with your actual token from the Apify Console, save the script, and execute it. Calling .call() starts the Actor in the Apify cloud and waits for completion. The scraper fetches catalog pages sequentially without requiring external proxies, parses the embedded listing records, applies the keyword and seller-type filters (condition and price were already sent to Vinted in the search request), and stores matching items in the default dataset.

Allow the script to execute until completion. Our benchmark run finished in 19.2 seconds and returned 200 items. Each line printed by the script shows the item title, asking price in EUR, total price with service fee, currency, and listing URL.


Step 5: View and download results

The script loops through items in the dataset using .iterate_items(). In Apify Console, you can inspect dataset records and export the data in JSON, CSV, XML, Excel, HTML table, RSS, or JSONL formats.

Here is the first item record from our benchmark run (id: "10500531689"), verbatim:

{
  "id": "10500531689",
  "title": "T shirt Nike",
  "url": "https://www.vinted.es/items/10500531689-t-shirt-nike",
  "price": 10,
  "serviceFee": 1.2,
  "totalPrice": 11.2,
  "currency": "EUR",
  "brand": "Nike",
  "model": null,
  "condition": "Muy bueno",
  "size": "XS",
  "photoUrl": "https://images1.vinted.net/t/05_0215e_JV2wBP59Ao9gQftFrYkxAL2K/310x430/212da0d0.webp?s=859bad0c545f8fa148f97e7eb0afcff61240411b",
  "favouriteCount": 51,
  "isPromoted": false,
  "sellerType": "private",
  "matchedKeyword": "nike"
}
Enter fullscreen mode Exit fullscreen mode

Understanding your results

Key attributes returned in the dataset:

  • price: asking price in EUR before buyer fees.
  • serviceFee: Vinted's buyer protection fee.
  • totalPrice: item price plus service fee in EUR.
  • condition: Vinted's condition grade (Muy bueno or Bueno).
  • brand and size: parsed brand and size label.
  • sellerType: private or professional.

Our benchmark run extracted 200 items, yielding clear empirical metrics:

  • All 200 items had numeric prices from 10 EUR to 40 EUR (median 12.0 EUR), with service fees from 1.2 EUR to 2.7 EUR (median 1.3 EUR) and total prices from 11.2 EUR to 42.7 EUR (median 13.3 EUR).
  • 173 items were Muy bueno (86.5%) and 27 were Bueno (13.5%), matching the filter (173 + 27 = 200).
  • Brands were 198 Nike and 2 Nike Air items (198 + 2 = 200).
  • 196 listings were from private sellers (98.0%) and 4 from businesses (2.0%).
  • 139 listings were organic results and 61 were promoted placements (139 + 61 = 200).
  • Favourites ranged from 0 to 83 (median 15.0; 4 had 0 favourites).
  • 199 items had size values across 41 distinct sizes, and 1 had a null size.

Pro tips and advanced usage

  1. Respect catalog pagination ceilings. Vinted limits anonymous visitors to 10 pages of 96 items (960 items per query). To collect deeper catalogs, partition broad searches by price brackets using minPrice and maxPrice, or combine keywords with specific catalogIds.
  2. Handle privacy boundaries in downstream pipelines. The Actor omits personal seller identification fields (sellerId, sellerLogin, sellerProfileUrl) for private sellers to protect personal privacy, while retaining sellerType. For professional sellers, sellerId and sellerProfileUrl are populated.
  3. Automate alerts with webhooks. You can configure Apify webhooks to trigger downstream HTTP endpoints when a scrape finishes. The payload's resource object contains the run details (docs.apify.com/platform/integrations/webhooks/actions), including defaultDatasetId.
  4. Filter out accessories with keyword matching. Vinted's search also returns related items (an "iphone" search returns iPhone cases, per the input schema). Keeping requireKeywordMatch: true keeps only items where every search word appears in the title, brand, or model.
  5. For current pricing and details, see the Store page.

Troubleshooting common issues

  • The run fails with "No rows pushed: all X parsed listings were rejected...". The Actor raises a runtime error when items were found on Vinted but rejected by your filters. Check whether your price range (minPrice / maxPrice), condition selections, or sellerType settings are too restrictive.
  • The run fails with "No rows pushed: the site returned no listings at all...". The Actor raises this error when Vinted returned zero listings for your search term or category.
  • The run fails with "searchQueries is required unless you supply catalogIds...". The Actor raises this error if searchQueries is empty and no category IDs are provided.
  • Input refused before the run starts. The platform validates schema enums before starting. Supplying unrecognized values for sortBy, sellerType, or conditions is refused before the run starts.

For technical support or feature requests, visit the Actor's Store page.


Next steps

Save your search configuration as a task in Apify Console and configure an Apify schedule to run daily or hourly. You can track second-hand fashion price trends, monitor newly posted bargains, or stream catalog rows directly into a database or spreadsheet. Check the Apify Python client documentation and the Store page to get started.

What items or brands are you planning to track on Vinted? Drop a comment below!

Top comments (0)