Vinted Scraper & API - New Listings to Discord, Telegram
Pricing
$3.00 / 1,000 items
Vinted Scraper & API - New Listings to Discord, Telegram
Vinted scraper and Vinted API: Vinted search, prices and deals in any country. Get Vinted new listings on Discord or Telegram, or use a Vinted watchlist as a Vinted bot backend (a monitor: no login, no buying, no seller data). $0.003 per item.
Pricing
$3.00 / 1,000 items
Rating
5.0
(2)
Developer
Luke Hunter
Maintained by CommunityActor stats
1
Bookmarked
15
Total users
3
Monthly active users
5 days ago
Last modified
Categories
Share
A Vinted scraper and Vinted API for a vinted price tracker, reselling research, Vinted deals and bulk vinted listings data across any Vinted country. Use it for Vinted search from your own code or as the backend of your own Vinted bot: it is a monitor and API, not a buying bot. Give it search terms (or your own Vinted catalog URLs) and it returns every item listing on the results page(s) - title, brand, size, condition, price (including buyer protection), favourites and image - read straight from Vinted's own public search pages. No login, no session, no seller data. Turn on new-listing alerts mode (onlyNewSinceLastRun) and run it on a schedule so resellers get new listings matching a saved search - brand, size, price range - the moment they appear, and optionally have each run send them to your own Discord, Telegram, Slack, Teams, Google Chat, phone (ntfy/Pushover) or any app via webhook.
Pay-per-result: $0.003 per item — 1,000 items = $3. (Raised from $0.001 on 2026-10-09; Apify applies price increases to existing users only after its notice period.)
Vinted Pro: watchlists for reseller bots
Building (or running) a Vinted monitor bot? Put all your saved searches in one watchlist. Every entry is a named, independent watch: it has its own "already seen" memory, its own filters, and optionally its own Discord channel or Telegram chat. One scheduled run polls them all and only charges for listings that are new and match.
{"country": "uk","sortBy": "newest","onlyNewSinceLastRun": true,"maxPagesPerSearch": 2,"maxItems": 200,"discordWebhookUrl": "https://discord.com/api/webhooks/<id>/<token for #all-finds>","watchlist": [{"name": "Nike jackets","searchTerm": "nike jacket","priceTo": 30,"brand": "Nike","size": ["M", "L"],"condition": ["Very good", "New with tags"],"notifyDiscordWebhookUrl": "https://discord.com/api/webhooks/<id>/<token for #nike>"},{"name": "Carhartt under 40","searchTerm": "carhartt","priceTo": 40,"brand": "Carhartt","notifyDiscordWebhookUrl": "https://discord.com/api/webhooks/<id>/<token for #carhartt>"},{"name": "Pasted search","url": "https://www.vinted.co.uk/catalog?search_text=levis%20501&price_to=25"}]}
What you get:
- Independent memory per watch. Each
nameis its own seen-state key (insidestateStoreName), so a new watch gets its own baseline run without touching the others. A watch is identified by itsnameplus what it searches (term/URL, country, price range, sort): renaming it or changing the search starts a fresh baseline; changing onlybrand,sizeorconditiondoes not. watchNameon every row, so your bot can route or label results. In a run that also usessearchTerms/startUrls, those rows getwatchName: null.- Filters before charging.
brand,sizeandcondition(each a string or a list) are matched, case-insensitively, against the delivered listing fields. Rows that do not match are never delivered and never charged. Size matches the whole text or any/-separated part ("M"matches"M / UK 12-14"). Write values as Vinted shows them in that country (e.g."Very good"on vinted.co.uk; the French site says"Très bon état"). A listing with no brand/size/condition set never matches a watch that filters on it. Vinted's own brand/size/condition URL filters use numeric ids this Actor does not map, which is why these three are matched on the listing text; in a pastedurlwatch you can still bake Vinted's own filters into the URL.priceFrom/priceTogo straight into the Vinted search for asearchTermwatch, and are checked on the delivered price for aurlwatch. - Per-watch routing.
notifyDiscordWebhookUrlandnotifyTelegramChatIdsend that watch's new listings to their own channel instead of the global Discord / Telegram destination (watches without their own route use the global one; other global channels such as Slack, ntfy or the JSON webhook still receive every watch's listings). A Telegram chat override uses your globaltelegramBotTokenand needs the globaltelegramChatIdas the default chat. Webhook URLs follow the same rules as the global ones and are never logged; the wholewatchlistinput is stored as a secret. firstSeenAton every row of a watchlist run: the run timestamp at which this Actor first saw the listing (nullunlessonlyNewSinceLastRunis on).- Early stop for fast polling. With
onlyNewSinceLastRunandsortBy: "newest"(or a pasted URL that already hasorder=newest_first), pagination stops at the first page that contains only listings you have already seen, so a quiet poll costs one page fetch instead ofmaxPagesPerSearch. - No fake freshness filter. Vinted's search cards expose no "listed N minutes ago" timestamp, so there is no
maxListingAgeMinutesoption. Newest-first plusonlyNewSinceLastRunis the reliable way to get "just listed" items;firstSeenAttells you when you first saw one.
Rules: up to 50 watches; each needs a unique name and exactly one of searchTerm or url; a typo in a field name is rejected rather than silently ignored.
Schedule it: every 5-10 minutes
In the Apify Console create a Schedule (cron) for a saved Task with the input above:
*/5 * * * * # every 5 minutes (use */10 for every 10)
The first run is the baseline for every watch (it delivers and remembers what is listed now); from then on each run returns only new, matching listings. A run where nothing new matches still succeeds with an empty dataset. The Actor is set up to start on 256 MB, and a quiet poll of a few watches is one catalog page each.
Call it from your bot
curl -s -X POST \"https://api.apify.com/v2/acts/lukehunter~vinted-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"sortBy": "newest", "onlyNewSinceLastRun": true, "maxItems": 100,"watchlist": [{"name": "Nike jackets", "searchTerm": "nike jacket", "priceTo": 30, "brand": "Nike", "size": "M"},{"name": "Carhartt", "searchTerm": "carhartt", "priceTo": 40, "brand": "Carhartt"}]}'
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("lukehunter/vinted-scraper").call(run_input={"sortBy": "newest","onlyNewSinceLastRun": True,"maxItems": 100,"watchlist": [{"name": "Nike jackets", "searchTerm": "nike jacket", "priceTo": 30, "brand": "Nike", "size": "M"},{"name": "Carhartt", "searchTerm": "carhartt", "priceTo": 40, "brand": "Carhartt"},],})for item in client.dataset(run["defaultDatasetId"]).iterate_items():send_to_my_bot(item["watchName"], item["title"], item["price"], item["url"], item["firstSeenAt"])
Every row is the normal listing row plus watchName and firstSeenAt; the existing field names are unchanged. Without watchlist the output is exactly as before.
Vinted search quick start (1 minute)
- Open the Input tab and enter one or more search terms, e.g.
jacket. - Pick the Vinted country to search (defaults to the UK).
- Click Start. Export the resulting dataset to CSV/Excel/JSON, or pull it through the API shown below.
{"searchTerms": ["jacket"],"country": "uk","maxItems": 20}
That prefilled example finishes in well under a minute and costs $0.04.
How it works
Vinted's own catalog search page (/catalog?search_text=...) is server-rendered HTML - no login or session needed to view it, and no public JSON API exists for search (Vinted's /api/v2/catalog/items endpoint requires a signed-in browser session, so this Actor never uses it). This Actor:
- Checks the target domain's
robots.txtfor the exact path it is about to read (/catalog), and skips that search (reporting why, in the run's status message) if it is disallowed. - Pages through the search results, stopping on the first page with zero items - the real end of the results.
- Parses each listing card into one flat dataset row: title, brand, size, condition, price, price including buyer protection, favourites count and image.
- Reads Vinted politely: about one request every 3 seconds, and honestly reporting - never disguising or evading - a block, a challenge page (e.g. a bot-check interstitial), or a search with genuinely no results.
Vinted prices and deals: use cases
- Vinted price tracker: run a search on a schedule and compare
price/totalPriceWithFeesover time for a brand, item type or your own listings' competitors. - Reselling research: see what similar items are actually listed and sold for - brand, size, condition and price together - before pricing your own listing.
- Vinted listings data: export a whole search's results (title, brand, size, condition, price, favourites) for spreadsheet analysis.
New-listing alerts: get only new items
Turn on onlyNewSinceLastRun and put this Actor on a schedule to get a genuine Vinted new-listing alert: every run after the first delivers (and charges for) only items it hasn't delivered before for that exact search. It's the same wedge as Wellfound Jobs Scraper's job-alerts mode, applied to reselling.
- Set your search as usual — a search term with
priceFrom/priceTo(a brand or size can go insearchTermstoo, e.g."nike jacket medium"), or a pastedstartUrlscatalog link with brand/size/price filters already baked in — plus:
{"searchTerms": ["nike jacket"],"country": "uk","priceFrom": 10,"priceTo": 40,"onlyNewSinceLastRun": true,"maxItems": 100}
- Click Schedule on the run page (or create one under Schedules in the Apify Console) — every 30-60 minutes works well for a fast-moving search.
- The first scheduled run is a baseline: it delivers every item currently listed (it's all new to you) and remembers it — you're charged normally for that run. Every run after that only delivers items it hasn't seen before for this exact search.
- Add a Webhook under the schedule's Integrations for
ACTOR.RUN.SUCCEEDED, pointing at Apify's own Slack/email integration (or a Zapier/Make webhook step) so you see new matching listings the moment a run finds them.
The run's status message tells you what happened: "First run for 1 search: 40 item(s) delivered and remembered; next runs return only new ones." on the baseline, then "3 new item(s) since last run across 1 search (37 already seen)." on later runs. A run that finds nothing new still succeeds with an empty dataset — that's the point of the mode, not a failure.
Each searchTerms entry and each startUrls entry is tracked as its own, independent watch (not one watch for the whole run), keyed on that search's own terms/country/price/sort (or its exact pasted URL) — so you can run several saved searches (different brands, sizes, price bands) in one Actor task without their seen-history mixing. stateStoreName only needs changing if you want to isolate or reset a watch's memory, or run several Actor tasks against the same account without them sharing state.
Get alerts in Discord, Telegram, Slack, Teams, Google Chat, your phone (ntfy/Pushover) or any app (webhook)
Want a Vinted Discord alert, a Vinted Telegram bot, or listings pushed to Slack, Teams, Google Chat or your phone instead of checking a dataset? Add one or more destinations in the Actor's Notifications (optional) section and each run sends the listings it delivered. It is a monitor that notifies you: it never buys anything, messages sellers or logs in to Vinted, and the messages go only to the places you set up.
| Channel | Fill in | What you get |
|---|---|---|
| Discord | discordWebhookUrl | One card per listing, 10 per message |
| Telegram | telegramBotToken + telegramChatId | Up to 10 listings per message, one line each |
| Slack | slackWebhookUrl | Block Kit message, up to 10 listings per message |
| Mattermost, Rocket.Chat | slackCompatibleWebhookUrl | Slack-style incoming webhook: a Markdown list (these apps do not render Slack Block Kit) |
| Microsoft Teams | teamsWebhookUrl | Adaptive Card from a Teams Workflows webhook, up to 10 listings per card |
| Google Chat | googleChatWebhookUrl | Card in a space, up to 10 listings per message |
| ntfy (phone push, no account) | ntfyTopic (optional ntfyServer, ntfyToken) | A push per listing, up to 10, then one "...and N more" |
| Pushover (phone push) | pushoverUserKey + pushoverAppToken | A push per listing, up to 10, then one "...and N more" |
| Any app: Zapier, Make, n8n, Pipedream, IFTTT, Home Assistant | webhookUrl | One JSON POST per run with every delivered row |
Fill in as many as you like; each channel works on its own and a failing one never stops the others.
Setup, channel by channel
- Discord (1 minute): Server Settings → Integrations → Webhooks → New Webhook → pick the channel → Copy Webhook URL.
- Telegram (2 minutes): chat with @BotFather, send
/newbot, paste the token intotelegramBotToken. Add the bot to the chat or channel (administrator for a channel; for a chat with yourself press Start on the bot).telegramChatIdis a numeric id (123456789, or-1001234567890for a group or channel) or a public@channelusername. - Slack: at api.slack.com/apps create an app (From scratch) → Incoming Webhooks → switch it on → Add New Webhook to Workspace → pick the channel → copy the
https://hooks.slack.com/services/...URL. - Mattermost or Rocket.Chat: create an incoming webhook in the app and paste its public
https://URL intoslackCompatibleWebhookUrl. It must be reachable from the internet: localhost, private IP addresses and.local/.internalnames are rejected. - Microsoft Teams: in the channel open ... → Workflows → Post to a channel when a webhook request is received → finish the wizard and copy the URL (a host ending in
.logic.azure.comor.powerplatform.com). The old "Office 365 connector" webhooks are retired and not supported. - Google Chat: in the space open Apps & integrations → Webhooks → Add webhook, name it and copy the
https://chat.googleapis.com/v1/spaces/...URL (needs a Google Workspace account that allows webhooks). - ntfy (free, no account): install the ntfy app (or open ntfy.sh), subscribe to a topic with a long random name, and put the same name in
ntfyTopic. Anyone who knows the topic can read it, so make it unguessable. Own server or a protected topic: setntfyServer(publichttps://address) andntfyToken. - Pushover: copy your user key from pushover.net into
pushoverUserKey, create an application at pushover.net/apps/build and put its API token inpushoverAppToken. Pushover itself is a separate paid app after its trial: check their pricing. - Any app (webhook): paste the catch-hook URL from Zapier, Make, n8n, Pipedream, IFTTT or Home Assistant into
webhookUrl. It must be a publichttps://address.
The recipe: a Vinted monitor in five steps
- Set your search (search terms with
priceFrom/priceTo, or astartUrlslink with brand and size filters already set). - Turn on
onlyNewSinceLastRunand setsortBytonewest. - Add your destination(s) from the table above.
- Run it once. The first run is the baseline and sends what is currently listed (up to
maxNotifications). - Create a Schedule (for example every 10-15 minutes). From then on you only hear about listings it has not delivered before.
{"searchTerms": ["nike jacket"],"country": "uk","priceTo": 40,"sortBy": "newest","onlyNewSinceLastRun": true,"maxItems": 100,"discordWebhookUrl": "https://discord.com/api/webhooks/<id>/<token>","ntfyTopic": "your-long-random-topic-name","maxNotifications": 25}
The generic webhook (webhookUrl)
Each run sends one POST per 100 delivered rows (so usually one) with this body, followed by whatever your tool does with it:
{"source": "apify","actor": "vinted-scraper","runId": "HG7ML7M8z78YcAPEB","count": 2,"total": 2,"part": 1,"parts": 1,"items": [ { "...": "the full dataset rows" } ]}
count is the number of rows in this POST, total the number delivered in the run, and part / parts number the POSTs when a run delivers more than 100 rows. maxNotifications does not cap the webhook: your tool gets every delivered row. Your endpoint should answer with a 2xx status; redirects are not followed and a failure is reported in the run status, never retried in a loop.
What each message contains
Title, link, price and currency, brand, size, condition, thumbnail (where the channel shows one) and the country and search term it matched. Discord gets a card per listing, Telegram one line per listing, Slack Block Kit sections, Teams an Adaptive Card, Google Chat a card, and ntfy/Pushover a push with the listing link. Link previews are off, and titles are escaped so a listing title can never inject formatting or mentions.
What to expect
- Only delivered listings are sent. A run that finds nothing new sends nothing, so there is no "no new items" spam. Rows the run could not deliver (for example because your spending limit was reached) are not sent.
maxNotifications(default 25, max 100) caps how many listings go to chat and phone channels per run (the webhook is not capped). The rest are still in the dataset and the status message says so. ntfy and Pushover send at most 10 individual pushes, then one "...and N more" summary.- Cost: notifications are free. You pay only $0.003 per delivered listing, exactly as without alerts. There is no extra charge for any channel.
- Failures never fail the run. A deleted webhook or an unreachable service leaves the run successful and the dataset complete, and the status message says what happened, for example
Notified: Discord 12, Slack 12, ntfy 10 (+summary). Teams failed (HTTP 404) - check the webhook URL.The logs show the channel name and HTTP status only, never a URL or token. - Your URLs, tokens and ntfy topic are stored as secret inputs. Anyone holding a webhook URL can post to that channel, so treat it like a password.
- It is a monitor that notifies you. It never buys anything, messages sellers or logs in to Vinted, and the messages go only to the destinations you set up.
Input
{"searchTerms": ["jacket"],"startUrls": [],"country": "uk","priceFrom": null,"priceTo": null,"sortBy": "relevance","maxPagesPerSearch": 1,"maxItems": 60,"onlyNewSinceLastRun": false,"stateStoreName": "vinted-scraper-seen-items","discordWebhookUrl": "","telegramBotToken": "","telegramChatId": "","slackWebhookUrl": "","slackCompatibleWebhookUrl": "","teamsWebhookUrl": "","googleChatWebhookUrl": "","ntfyTopic": "","ntfyServer": "https://ntfy.sh","ntfyToken": "","pushoverUserKey": "","pushoverAppToken": "","webhookUrl": "","maxNotifications": 25}
| Field | Type | Default | Description |
|---|---|---|---|
searchTerms | string[] | (none) | Words to search for, e.g. "jacket". Searched on the domain set by country. Up to 50 terms per run. |
startUrls | string[] | (none) | Full Vinted catalog URLs to scrape instead of (or alongside) search terms, e.g. https://www.vinted.co.uk/catalog?search_text=jacket&price_to=20. Any filters already in the URL are kept; only pagination is added. Must be a vinted.* URL. Up to 50 per run. At least one of searchTerms, startUrls or watchlist is required. |
country | string | "uk" | Which Vinted domain to search on for searchTerms (ignored for startUrls, which use their own domain). One of: uk, fr, de, es, it, nl, be, pl, us, au, at, cz, dk, ee, fi, gr, hr, hu, ie, lt, lu, lv, pt, ro, se, si, sk. |
priceFrom | integer | (none) | Only include listings priced at or above this amount, in the country's own currency. |
priceTo | integer | (none) | Only include listings priced at or below this amount. |
sortBy | "relevance" | "newest" | "price_low" | "price_high" | "relevance" | How Vinted orders the results. |
maxPagesPerSearch | integer | 1 | 1–20. How many result pages to fetch per search term/start URL. Vinted shows about 96 items per page. |
maxItems | integer | 60 | 1–5,000. Hard cap on rows delivered across the whole run — your cost cap. |
watchlist | object[] (secret) | (none) | Vinted Pro: up to 50 named, independent saved searches - see "Vinted Pro: watchlists for reseller bots". Each: name (required, unique), exactly one of searchTerm / url, and optional country, priceFrom, priceTo, brand, size, condition (string or list; matched on the listing text before charging), notifyDiscordWebhookUrl, notifyTelegramChatId. When set, searchTerms/startUrls become optional. |
onlyNewSinceLastRun | boolean | false | New-listing alerts mode — see above. Delivers and charges only items not delivered by a previous run of the same search. |
stateStoreName | string | vinted-scraper-seen-items | Name of the store that remembers what every alert-mode search has already delivered. Change it only to isolate several Actor tasks or reset a watch. |
discordWebhookUrl | string (secret) | (none) | Discord webhook URL. Must look like https://discord.com/api/webhooks/<id>/<token>. Empty means no Discord messages. See "Get alerts in Discord, Telegram, Slack, Teams, Google Chat, your phone (ntfy/Pushover) or any app (webhook)". |
telegramBotToken | string (secret) | (none) | Telegram bot token from @BotFather. Needs telegramChatId. |
telegramChatId | string | (none) | Telegram chat to post to: a numeric chat id or @channelusername. The bot must be added to that chat or channel. Needs telegramBotToken. |
slackWebhookUrl | string (secret) | (none) | Slack incoming webhook, https://hooks.slack.com/services/.... |
slackCompatibleWebhookUrl | string (secret) | (none) | Mattermost / Rocket.Chat incoming webhook (public https:// URL; Markdown list, no Block Kit). |
teamsWebhookUrl | string (secret) | (none) | Microsoft Teams Workflows webhook (host ending .logic.azure.com or .powerplatform.com). |
googleChatWebhookUrl | string (secret) | (none) | Google Chat space webhook, https://chat.googleapis.com/v1/spaces/.... |
ntfyTopic | string (secret) | (none) | ntfy topic name; setting it turns ntfy phone pushes on. Pick a long, unguessable name. |
ntfyServer | string | https://ntfy.sh | ntfy server. Only change it for your own public https:// ntfy server. |
ntfyToken | string (secret) | (none) | Optional ntfy access token for a self-hosted server or protected topic. Needs ntfyTopic. |
pushoverUserKey | string (secret) | (none) | Pushover user key. Needs pushoverAppToken. |
pushoverAppToken | string (secret) | (none) | Pushover application API token. Needs pushoverUserKey. |
webhookUrl | string (secret) | (none) | Generic JSON webhook (Zapier, Make, n8n, Pipedream, IFTTT, Home Assistant): every delivered row, 100 per POST. Public https:// only. |
maxNotifications | integer | 25 | 1–100. Most listings sent to chat and phone channels per run (the webhook is not capped). Extra listings are still in the dataset. Only used when a destination is set. |
Input details
The Store form and the MCP tool schema show a short description for each field (an AI agent sees only the first 500 characters of each); the longer rules are here.
watchlist: up to 50 named saved searches for reseller bots, each tracked as its own independent watch (its own "seen" memory when New-listing alerts is on). Each entry:{"name": "Nike jackets", "searchTerm": "nike jacket"(or"url": "https://www.vinted.co.uk/catalog?..."), "country": "uk", "priceFrom": 5, "priceTo": 40, "brand": "Nike", "size": "M", "condition": "Very good", "notifyDiscordWebhookUrl": "https://discord.com/api/webhooks/...", "notifyTelegramChatId": "-100123..."}. Onlynameand one ofsearchTerm/urlare required.brand,sizeandconditionare matched on the listing text (case-insensitive; each may be a list) BEFORE anything is charged, so filtered-out listings cost nothing; they must be written as Vinted shows them in that country (for example "Very good" on vinted.co.uk). Each delivered row gets awatchName.notifyDiscordWebhookUrl/notifyTelegramChatIdsend that watch's listings to its own channel instead of the global Discord/Telegram destination (Telegram needs the global bot token). The field is marked secret because it can hold webhook URLs. Names must be unique; renaming a watch or changing what it searches starts a fresh baseline.onlyNewSinceLastRun: items already delivered on a previous run for the same search (search term/URL, country, price range, sort) are skipped and never charged again. The first run for a given search delivers everything (it is all new) and remembers it; later runs deliver what is new since then. Each search term or start URL is tracked as its own watch.stateStoreName: only used when New-listing alerts is on; remembers which items each search has already delivered so it persists across scheduled runs. Leave the default unless several tasks' alert histories must not share this store. Letters, numbers and hyphens only.
Output fields
| Category | Fields |
|---|---|
| Identity | itemId, url |
| Listing | title, brand, size, condition |
| Price | price, currency, totalPriceWithFees |
| Engagement | favouritesCount |
| Media | imageUrl |
| Search context | country, searchTerm, page, position, scrapedAt |
| Watchlist runs only | watchName, firstSeenAt |
Missing values are returned as null. Nothing is invented.
Notifications use these same fields and add nothing to the dataset: the output rows are identical whether or not you set a destination. The run's status message gains a short note such as Notified: Discord 12, ntfy 10 (+summary).
Output example
{"itemId": "10156138130","url": "https://www.vinted.co.uk/items/10156138130-fat-face-teddy-fleece-age-45","title": "Fat face teddy fleece age 4/5","brand": "FatFace","size": "5 years / 110 cm","condition": "Very good","price": 4,"currency": "GBP","totalPriceWithFees": 4.62,"favouritesCount": 0,"imageUrl": "https://images1.vinted.net/t/02_024e5_kxdcgDrGSSp2hJYWN1hXEwpV/310x430/28e5250f.webp?s=6b5663cff047d9d187bc4a4d2468793ff128e470","country": "uk","searchTerm": "jacket","page": 1,"position": 1,"scrapedAt": "2026-09-27T00:00:00.000Z"}
Use it as an API
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("lukehunter/vinted-scraper").call(run_input={"searchTerms": ["jacket", "coat"],"country": "uk","maxItems": 200,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["title"], item["price"], item["currency"])
Poll for new listings from your own code
One HTTP call starts a run, waits for it and returns only listings your previous calls have not seen. Call it from a cron job or your bot every few minutes:
curl -s -X POST \"https://api.apify.com/v2/acts/lukehunter~vinted-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"searchTerms": ["carhartt jacket"], "country": "uk", "sortBy": "newest", "onlyNewSinceLastRun": true, "maxItems": 50}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('lukehunter/vinted-scraper').call({searchTerms: ['carhartt jacket'], country: 'uk', sortBy: 'newest',onlyNewSinceLastRun: true, maxItems: 50,});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const item of items) console.log(item.itemId, item.title, item.price, item.url);
- The response is a JSON array of new listings; an empty array means nothing new. You pay $0.003 only per listing returned.
- "Seen" memory is kept per search in a named key-value store in your account (
stateStoreName). Use a differentstateStoreNameper bot or environment if you run several. - Prefer push over polling? Set
webhookUrland each run POSTs its new listings to your endpoint (see the alerts section above). - Output field names are stable: an automated test fails the build if any documented field is renamed or removed.
Use with AI agents (MCP)
This Actor works as a tool for Claude, ChatGPT, Cursor and other MCP clients through Apify's MCP server. The only input a call needs is searchTerms (add country to pick the marketplace).
Claude Desktop (claude_desktop_config.json), with your own token from Apify Console > Settings > API & Integrations:
{"mcpServers": {"apify-vinted": {"command": "npx","args": ["-y", "mcp-remote","https://mcp.apify.com?tools=lukehunter/vinted-scraper","--header", "Authorization: Bearer ${APIFY_TOKEN}"],"env": { "APIFY_TOKEN": "<YOUR_APIFY_TOKEN>" }}}}
Clients that support OAuth (Claude.ai, VS Code) can connect with just the URL https://mcp.apify.com?tools=lukehunter/vinted-scraper and sign in to Apify. Never paste a real token into a shared file or chat.
Example. You ask: "Find the cheapest Levi's 501 jeans on Vinted UK under 30 pounds." The agent calls the tool lukehunter--vinted-scraper with:
{"searchTerms": ["levi's 501"],"country": "uk","priceTo": 30,"sortBy": "price_low","maxItems": 20}
It is charged $0.003 per delivered listing, capped by maxItems.
Pricing and cost control
Pay per delivered listing.
$0.003 per item — 1,000 items = $3.
| Rows delivered | Cost |
|---|---|
| 20 | $0.06 |
| 1,000 | $3.00 |
| 10,000 | $30.00 |
Notifications to Discord, Telegram, Slack, Teams, Google Chat, ntfy, Pushover and webhooks are free: you pay only for delivered listings, never for messages sent.
There is no charge for starting a run, and no charge for a search that is skipped, blocked, or produces no results. maxItems gives you a hard upper bound on cost.
Limitations
- No seller/member data, by design. This Actor only ever collects listing (item) fields - title, brand, size, condition, price, favourites count, image. It never collects seller usernames, profile links, avatars or any other member data, and never fetches a
/member/page (Vinted's ownrobots.txtdisallows it, and this Actor would not fetch it even if it didn't). - Search results pages only. This Actor reads Vinted's catalog search pages, not individual item detail pages - so it does not collect a listing's full description, all photos, or the seller's shipping/return terms.
- No login, no session, no Vinted API. Vinted's own JSON search API needs a signed-in browser session; this Actor never uses it and never logs in on your behalf.
- A minority of requests may be met with a bot-check/challenge page. When that happens, this Actor reports it honestly (per search, in the run's status message) and stops that search rather than attempting to evade it - you are not charged for a blocked search.
- Prices reflect the listing at scrape time; a seller can change or remove a listing at any moment.
- This is an independent tool, not affiliated with, endorsed by, or connected to Vinted. You are responsible for using the collected data in accordance with Vinted's terms and applicable law.
Use it from your code, Make, Zapier or n8n
Built for automated pipelines: small runs, stable field names, one row per item, and you pay only for rows actually delivered.
One API call that runs the Actor and returns the data (replace $APIFY_TOKEN with your token from Apify Console → Settings → Integrations):
curl -s -X POST "https://api.apify.com/v2/acts/lukehunter~vinted-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"searchTerms": ["jacket"], "country": "uk", "sortBy": "relevance", "maxPagesPerSearch": 1, "maxItems": 20}'
JavaScript (npm i apify-client):
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('lukehunter~vinted-scraper').call({"searchTerms": ["jacket"],"country": "uk","sortBy": "relevance","maxPagesPerSearch": 1,"maxItems": 20});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Python (pip install apify-client):
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ['APIFY_TOKEN'])run = client.actor('lukehunter~vinted-scraper').call(run_input={"searchTerms": ["jacket"], "country": "uk", "sortBy": "relevance", "maxPagesPerSearch": 1, "maxItems": 20})items = client.dataset(run['defaultDatasetId']).list_items().items
Schedules, webhooks and no-code tools: save your input as a Task, add a Schedule (e.g. hourly or daily), and attach a webhook or one of the Integrations tab's connectors (Make, Zapier, n8n, Google Sheets, Slack) to push each run's results into your own system.
Only new items each run: set "onlyNewSinceLastRun": true on a scheduled Task and every run after the first delivers, and charges for, only items it hasn't delivered before for that same input. That makes it a ready-made change feed.
Reliability: an automated test runs this Actor's parser against the live site every day, and failures are fixed fast.
Feedback: an honest rating on the Store page, good or bad, helps others decide if this Actor fits their needs. Missing a field or found a problem? Open an issue on the Actor page.
FAQ
Does this collect seller information?
No, never. Only listing (item) fields - see "Limitations" above.
Can I filter by price?
Yes - set priceFrom and/or priceTo in the country's own currency.
Can I use my own Vinted search URL, with filters I've already set (brand, size, etc.)?
Yes - paste it into startUrls. Every filter already in the URL is kept; this Actor only adds pagination.
Why is currency sometimes different from what I expected?
currency is set from the country you searched (or, for a startUrls entry, the domain in that URL) - e.g. uk → GBP, fr → EUR. It is not read from the page itself.
How do I get alerted to new listings instead of the same items every time?
Set onlyNewSinceLastRun: true and put the Actor on a schedule — see "New-listing alerts" above. The first scheduled run delivers everything (and remembers it); later runs only deliver what's new. Each search term or start URL keeps its own history, so several saved searches (different brands, sizes, price bands) never mix up each other's alerts.
Can I get Vinted alerts in Discord?
Yes. Create a webhook in your Discord server (Server Settings → Integrations → Webhooks → New Webhook → Copy Webhook URL), paste it into discordWebhookUrl, turn on onlyNewSinceLastRun, set sortBy to newest and put the Actor on a schedule. Each run posts the new listings it delivered as cards with the price, brand, size, condition and a thumbnail. It only notifies you: it does not buy items or message sellers. See "Get alerts in Discord, Telegram, Slack, Teams, Google Chat, your phone (ntfy/Pushover) or any app (webhook)" above.
Can I get Vinted alerts in Telegram?
Yes. Create a bot with @BotFather, add it to the chat or channel you want, then set telegramBotToken and telegramChatId (a numeric id or @channelusername). With onlyNewSinceLastRun on and a schedule, each run sends the new listings, up to 10 per message. It is a monitor that notifies you, not a buying bot, and it never logs in to Vinted. Notifications cost nothing extra: you pay $0.003 per delivered listing.
Can I get Vinted alerts in Slack, Teams, Google Chat or on my phone?
Yes. Set slackWebhookUrl, teamsWebhookUrl or googleChatWebhookUrl, or use ntfyTopic (free, no account) or pushoverUserKey + pushoverAppToken for phone pushes. Mattermost and Rocket.Chat work through slackCompatibleWebhookUrl. Setup steps for each are in the alerts section above.
Can I get Vinted alerts by email?
Not natively. There are two routes. (1) Set webhookUrl to a Zapier, Make or n8n catch hook and add an email or Gmail step: the webhook delivers every row as JSON, so the email can list the items. (2) Apify's own run integrations and run notifications can email you when a run finishes, but they only send a link to the run or dataset, not the listings themselves. For instant alerts without building anything, Telegram, ntfy or Pushover reach your phone directly.
Can I get Vinted alerts in WhatsApp?
Not natively, and we do not use unofficial WhatsApp APIs, which risk getting your number banned. The official route is the WhatsApp Business Platform (Cloud API) with its own business account, message templates and pricing: point webhookUrl at a Zapier, Make or n8n flow that calls it. For free phone alerts use Telegram or ntfy instead.
Related Actors
Other data tools from the same developer, built to the same standard: official or public sources, hard cost caps, and honest documentation of limits.
- Vinted Cross-Country Price Comparison: compare the same search across Vinted country markets with EUR-normalized summaries and median price gaps.
- Vinted Item Scraper by URL: price-drop and sold alerts for specific Vinted item URLs: price, brand, size, condition and availability, with a changes-only mode.
- Shopify Product Scraper by URL: price, compare-at price and stock for specific Shopify product URLs, with a change-only feed.
- Shopify Store Products Scraper: full product catalogues from any Shopify store, with prices, sale prices, variants and stock.
- AliExpress Search Scraper: AliExpress search results with prices, discounts, ratings and sold counts, by keyword.
- Temu Scraper: Temu search results with prices, product links and images for any keyword, with a new-products-only mode for scheduled runs.
- YouTube Channel Scraper: new-video alerts and channel monitoring for any list of YouTube channels: subscribers, latest videos and a new-uploads-only mode for scheduled runs.
- Google Play App Scraper: ratings, installs, developer contact info and pricing for any Google Play app.