Vinted
Vinted API: Export Vinted Listings to CSV, Excel or JSON
No public Vinted API? Use the Vinted Scraper API on Apify to export listings to CSV, Excel or JSON, with cURL, Python and JavaScript examples.
Vinted
No public Vinted API? Use the Vinted Scraper API on Apify to export listings to CSV, Excel or JSON, with cURL, Python and JavaScript examples.
Vinted doesn’t publish an API for searching listings, so if you want Vinted data in a spreadsheet, a database or your own app, you need a scraper with an API in front of it. The Vinted Scraper runs on Apify, which gives every run a REST endpoint and official Python and JavaScript clients. You send search input as JSON and get listings back as JSON, CSV or Excel.
This post covers the developer side: one-off exports from the console, cURL, Python and JS clients, choosing columns, and pulling data from scheduled runs. For what the fields mean and how to build good searches, see the Vinted scraper guide.
Or connect Google Sheets or Google Drive in the Integrations tab and every run lands there automatically.
Which format:
| Format | Best for | Nested objects (price, user, photo) |
|---|---|---|
| JSON | Apps, databases, full fidelity | Kept as objects |
| CSV | Scripts, database imports, pandas | Flattened into columns |
| Excel | Pivot tables, sharing with non-developers | Flattened into columns |
One thing to keep in mind with any format: price.amount is a string in the listing’s own currency (price.currency_code). Keep both columns, and convert before summing or averaging across countries.
Every API call sends the same JSON input you’d type in the console. Property names come from the actor’s input schema:
{
"keywords": ["nike", "adidas"],
"country": "it",
"minPrice": 10,
"maxPrice": 50,
"maxProducts": 20
}
| Property | What it does |
|---|---|
keywords |
Search terms; each is a separate search |
startUrls |
Vinted search or catalog URLs as [{"url": "..."}], filters kept |
country |
Main Vinted site for keywords (it, fr, de, gb, us, and 21 more) |
compareCountries |
Extra countries to run every keyword in |
minPrice / maxPrice |
Price range for keywords, in the main country’s currency |
maxProducts |
Max listings per URL, keyword and country (1 to 960, default 20) |
trackPriceChanges / saveOnly |
Remember listings between runs; save all, new, priceDrops or newOrPriceDrops |
aiFilteringEnabled / aiFilterPrompt / aiMatchThreshold |
Keep only listings that match a plain-language rule |
maxProducts multiplies: two keywords in one country at 20 returns up to 40 listings.
The run-sync-get-dataset-items endpoint starts a run, waits for it, and returns the dataset. Change format to get CSV or Excel directly:
curl --fail-with-body --request POST \
"https://api.apify.com/v2/acts/epicscrapers~vinted-search-scraper/run-sync-get-dataset-items?format=csv" \
--header "Authorization: Bearer ${APIFY_TOKEN}" \
--header "Content-Type: application/json" \
--data '{"keywords":["nike"],"country":"it","maxProducts":20}' \
--output vinted.csv
Use format=json for JSON or format=xlsx for an Excel file (save it as vinted.xlsx). The sync endpoint suits small runs; it waits up to 300 seconds. For bigger jobs, start the run asynchronously and fetch the dataset when it finishes:
# start the run
curl -s --request POST \
"https://api.apify.com/v2/acts/epicscrapers~vinted-search-scraper/runs" \
--header "Authorization: Bearer ${APIFY_TOKEN}" \
--header "Content-Type: application/json" \
--data '{"keywords":["levis 501"],"country":"fr","maxProducts":500}'
# later: download the dataset of the actor's last successful run
curl -s "https://api.apify.com/v2/acts/epicscrapers~vinted-search-scraper/runs/last/dataset/items?status=SUCCEEDED&format=xlsx" \
--header "Authorization: Bearer ${APIFY_TOKEN}" --output vinted.xlsx
Dataset endpoints accept fields to pick top-level fields and flatten to expand nested ones. This keeps a CSV down to the columns a spreadsheet user actually needs:
curl -s "https://api.apify.com/v2/datasets/${DATASET_ID}/items?format=csv&fields=id,title,price,brand_title,size_title,status,favourite_count,view_count,vinted_country,url&flatten=price" \
--header "Authorization: Bearer ${APIFY_TOKEN}" --output vinted-clean.csv
You’ll find the dataset ID as defaultDatasetId on any run.
import os
import pandas as pd
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("epicscrapers/vinted-search-scraper").call(run_input={
"startUrls": [{"url": "https://www.vinted.fr/catalog?search_text=vintage%20jacket&price_to=40"}],
"keywords": ["carhartt jacket"],
"country": "de",
"maxProducts": 100,
})
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
rows = [{
"id": i["id"],
"title": i.get("title"),
"price": float(i["price"]["amount"]) if i.get("price") else None,
"currency": (i.get("price") or {}).get("currency_code"),
"brand": i.get("brand_title"),
"size": i.get("size_title"),
"condition": i.get("status"),
"favourites": i.get("favourite_count"),
"views": i.get("view_count"),
"seller": (i.get("user") or {}).get("login"),
"country": i.get("vinted_country"),
"url": i.get("url"),
} for i in items]
df = pd.DataFrame(rows).drop_duplicates("id")
df.to_csv("vinted.csv", index=False)
df.to_excel("vinted.xlsx", index=False) # needs openpyxl
drop_duplicates("id") matters when you mix URLs and keywords: overlapping searches in one run can return the same listing twice. iterate_items() pages through the dataset for you, so it works for thousands of rows.
import { ApifyClient } from 'apify-client';
import { writeFile } from 'node:fs/promises';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('epicscrapers/vinted-search-scraper').call({
keywords: ['nike air max 90'],
country: 'it',
compareCountries: ['fr', 'pl'],
maxProducts: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const byId = new Map(items.map((i) => [i.id, i]));
await writeFile('vinted.json', JSON.stringify([...byId.values()], null, 2));
// Country price summary saved by compareCountries runs
const summary = await client
.keyValueStore(run.defaultKeyValueStoreId)
.getRecord('COUNTRY_PRICE_SUMMARY');
console.log(summary?.value);
listItems() returns up to the default page size; pass { offset, limit } in a loop for very large datasets.
For recurring exports, save your input as a task in the console and schedule it. Then you don’t need to start runs from code at all. Read the latest results whenever you need them:
GET https://api.apify.com/v2/actor-tasks/{TASK_ID}/runs/last/dataset/items?status=SUCCEEDED&format=csv
Point Power BI, Excel’s Get Data > From Web, or any ETL tool at that URL, passing your token in an Authorization: Bearer header, and it always returns the freshest run. Avoid pasting the token into the URL of a shared spreadsheet, since anyone who can open the file can read it. For pipelines that react to each run, add a webhook on Run succeeded in the task’s Integrations tab; the payload contains the run’s defaultDatasetId.
If what you’re building is notifications, the Vinted alerts tutorial has a full bot. If it’s price history, the Vinted price tracking guide has a snapshot schema and SQL.
Not a public one for listing search. Vinted’s internal endpoints are undocumented and change without notice. A maintained scraper behind the Apify API gives you a stable input and output format instead.
Yes. All three have Apify integrations that can run the actor or a saved task and read the dataset.
960 is Vinted’s limit per search. Split one search into several (by price range, size or category) and pass them all in one run as startUrls or keywords.
No. The actor handles Vinted access itself; you only need an Apify token.
Run the cURL example above with your own keyword, or open the Vinted Scraper on Apify and click Export after your first run. Pricing is pay-per-listing; check the Pricing tab for current rates.