Vinted Scraper - Listings with Favourite Counts avatar

Vinted Scraper - Listings with Favourite Counts

Pricing

from $1.00 / 1,000 listings

Go to Apify Store
Vinted Scraper - Listings with Favourite Counts

Vinted Scraper - Listings with Favourite Counts

Collect verified Vinted listings from 26 marketplaces with favourite counts, search, category, brand, size, condition and price filters, and monitor new listings and favourite changes.

Pricing

from $1.00 / 1,000 listings

Rating

0.0

(0)

Developer

Amadeusz

Amadeusz

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Vinted Scraper

Collect listings from Vinted with the number of favourites (favouriteCount) of every listing. Pick a marketplace (26 countries), give a phrase, a category, brands, sizes, condition and a price range, or paste a search URL copied from Vinted. Every listing is checked against your filters, de-duplicated and returned as clean JSON, ready for CSV, Excel, the API or AI agents.

Run Vinted Scraper · Input schema · Output schema

What you get

  • Favourite counts: favouriteCount in every record, the same number the listing page shows.
  • 26 marketplaces: pl, fr, de, it, es, nl, be, lt, cz, sk, at, pt, hu, ro, hr, se, dk, fi, lu, gr, co.uk, com, ie, lv, ee, si.
  • Names instead of IDs: category takes a path (Mężczyźni > Obuwie > Obuwie sportowe), brands takes brand names, conditions takes names (new_with_tags, new_without_tags, very_good, good, satisfactory).
  • Filters you can discover: a free run with listFilters lists every filter of a category with its allowed values and the input field to put them in.
  • Price range, four sort orders, search URLs copied from Vinted (startUrls), several searches in one run with shared de-duplication.
  • Verified results: filters are checked against what Vinted reports as applied. A filter that Vinted would silently ignore stops the run with an explanation instead of returning wrong data.
  • No duplicates: the same listing is returned once per run, and you are charged once.
  • Optional details (enrichDetails): description, full photo list, category path, attributes, color, how long ago the listing was posted, seller profile and reputation.
  • Monitoring (mode: monitor): each run returns only listings not reported by earlier runs; with trackFavourites it also returns a change record when the favourite count of a listing moved.
  • Free estimate (countOnly): how many listings match your search, without scraping or charges.
  • More than 960 results per search: one Vinted search exposes at most 960 listings, so the Actor splits large searches by price automatically.
  • One date format (UTC, YYYY-MM-DDTHH:mm:ssZ) in every field.

Quick start

  1. Choose a Marketplace and type a Search phrase, or choose a Category.
  2. Add brands, condition, price range or other filters if you need them.
  3. Set Max items (the limit of listings returned and charged).
  4. Click Start. The default input (country: pl, maxItems: 100) is a working example.
  5. Open the Overview table, export JSON, CSV or Excel, or read the data through the API.

Not sure how many listings match? Start with Count only: it is free.

Pricing

Pay per event, no start fee:

EventPriceWhen
listing$1.00 / 1000One per listing returned, with favouriteCount
listing-details$4.00 / 1000One per listing when enrichDetails is on and the details were fetched
listing-change$0.50 / 1000One per change record (trackFavourites)

Duplicates, rejected cards, empty runs, countOnly and listFilters runs and runs that end with an input or filter error are not charged. maxItems and your maximum cost per run are hard limits: the run stops when either is reached.

Cost of a run = listings returned × $0.001 (plus $0.004 per enriched listing and $0.0005 per change record). Run countOnly first to see how many listings match.

Ready-to-use recipes

1. Search by phrase on one marketplace

{
"country": "pl",
"query": "nike air max",
"priceTo": 200,
"sortBy": "newest",
"maxItems": 100
}

2. Category, brand and condition

{
"country": "fr",
"category": "Hommes > Chaussures > Baskets",
"brands": ["Nike", "Adidas"],
"conditions": ["new_with_tags", "very_good"],
"maxItems": 300
}

Run listCategories to find the exact category name or ID, and listFilters with the same country and category to see every filter and value of the category.

3. Search URL copied from Vinted

{
"startUrls": ["https://www.vinted.de/catalog?search_text=levis&order=newest_first"],
"maxItems": 200
}

The marketplace comes from the URL. A parameter the Actor does not know is rejected instead of ignored.

4. Monitor new listings and favourite changes

{
"country": "pl",
"query": "iphone 13",
"mode": "monitor",
"trackFavourites": true,
"seenStoreName": "vinted-iphone",
"maxItems": 200
}

Schedule it in Apify. The first run returns what is there; later runs return only new listings and change records.

Use it from the API

$curl -X POST "https://api.apify.com/v2/acts/ziomixshot~vinted-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" -H "Content-Type: application/json" -d '{"country":"pl","query":"nike air max","maxItems":50}'

The same Actor is available to AI agents through the Apify MCP server: add ziomixshot/vinted-scraper to the tools of the server.

Input

The full description of every field is in the input form. A field the Actor does not know (for example a typo) is rejected when the run starts.

FieldDescription
countryMarketplace code, default pl. Ignored for startUrls (the URL decides).
querySearch phrase.
categoryCategory name or path in the language of the marketplace (Kobiety > Ubrania > Sukienki), a category code or a category page URL. A name used by several categories is refused with the list to choose from.
brandsBrand names, matched to the Vinted brand with the same name (or the best match); the run log shows what was chosen.
conditionsnew_with_tags, new_without_tags, very_good, good, satisfactory.
priceFrom, priceToPrice range in the currency of the marketplace, inclusive.
sortByrelevance, newest, priceAsc or priceDesc. A price order starts from the cheapest (or most expensive) listing of the whole result, so combine priceAsc with priceFrom to skip very cheap ones.
maxItemsHard limit of returned listings and charges, shared by all startUrls (default 100).
includePromotedVinted mixes promoted cards into results; false skips them (default true).
enrichDetailsFetch the listing page of each listing; each one also triggers the listing-details event.
includeRawDataAdd raw, the unchanged Vinted card of the listing.
mode, seenStoreName, seenIdsKey, stopMonitorOnAllSeenPages, trackFavouritesMonitoring, see below.
countOnlyReturn only the number of matching listings (free).
listFiltersReturn the filters of the category instead of listings (free).
listCategoriesReturn the category tree of the marketplace (ID, path, code, URL) instead of listings (free); category narrows it to paths containing that text.
startUrlsSearch URLs copied from Vinted, as strings or {url} objects. They replace all search fields above.
categoryId, brandIds, sizeIds, colorIds, materialIdsVinted numeric IDs, for when you already know them. listFilters shows them.
otherFiltersFilters of the category without a field of their own, as filter code to a list of IDs, for example {"video_game_platform":[7]}. listFilters lists them; a filter the category does not have fails the run before any listing is charged.

category and categoryId cannot be combined, and neither can brands and brandIds; the run stops with an explanation instead of guessing.

Output

Every listing is one dataset item. The dataset has an Overview view, and the Overview table also shows status, estimate, filter, category and change records.

Fields of every listing item: recordType, id, url, title, country, price, currency, priceWithDiscount, serviceFee (buyer protection), totalPrice, favouriteCount, brand (as shown on the card), size and condition (text in the language of the marketplace), isPromoted, thumbnailUrl, photos (card photos), seller (id, isBusiness), scrapedAt. A value Vinted does not provide is null.

Added by enrichDetails: detailsFetched, description, originalPrice, categoryId, categoryPath, brandId, sizeId, color, attributes, uploadedAgo, isReserved, isHidden, canBuy, all photos, and in seller: login, feedbackCount, feedbackReputation (0 to 1), lastLoggedIn (relative text, for example 3 godz.), badges. The favouriteCount of a detailed record is read from the listing page, so it is the freshest value. A listing Vinted no longer serves is skipped and not charged; the count is detailsUnavailable in the run status.

Other record types, always free except change:

  • status: the run ended because of your input and returned no listings. Fields: status, message (what is wrong and how to fix it), details, scrapedAt.
  • estimate: result of countOnly: estimatedTotal, isLowerBound, sources, note.
  • filter: result of listFilters: code, title, selectionType, inputField, values, note.
  • category: result of listCategories: id, path, title, code, url, hasSubcategories, country. Put id into categoryId, or path into category.
  • change: see monitoring.

Run status

The OUTPUT record of the key-value store describes the run: status (OK, PARTIAL, INVALID_INPUT, URL_NOT_FULLY_RESOLVED, FILTER_VERIFICATION_FAILED, SEEN_STATE_INVALID, UPSTREAM_ERROR), counters and jobs[] per search (criteria as sent to Vinted, expectedTotal, coverage, partitions, truncatedPartitions, failedPages). Input and filter errors end the run without listings and without charges. PARTIAL means some pages or details failed after all retries; the returned records are still valid.

Monitoring new listings and favourite changes

mode: monitor returns only listings whose ID was not reported by earlier runs with the same seenStoreName and seenIdsKey (a named key-value store in your account). Without seenStoreName the Actor uses a store named after the search (vinted-monitor-..., shown in the run log), so repeating the same search keeps its history; set a name to share one history between different runs. The first run returns everything up to maxItems; later runs return only new IDs.

  • It always reads newest first and ignores sortBy, does not split the search and skips promoted cards.
  • It reads pages until stopMonitorOnAllSeenPages consecutive pages hold nothing new.
  • When maxItems stops it before that, the listings it did not return stay unseen and the next run returns them (the run log says so). Raise maxItems to catch up in one run.
  • State is saved only for listings that were actually returned. A corrupted state record ends the run with SEEN_STATE_INVALID instead of starting over.

Tracking favourites (trackFavourites)

With trackFavourites: true the run also returns a change record for every listing whose favouriteCount changed since the previous run: recordType: "change", metric: "favourites", id, url, title, country, previous, current, delta and changedAt. New listings are still returned as listing items.

  • It compares the cards the run reads anyway (the newest listings of the search, up to the first page without new IDs), with no extra requests. A listing that falls off those pages is not checked.
  • The first time a listing is seen only a baseline counter is stored; a change needs a stored value to compare with.
  • Counters are stored next to the seen IDs, in the record named like seenIdsKey plus _FAVOURITES (up to 200000 newest listings).
  • maxItems limits listings and change records together. A change beyond the limit is kept for the next run.

Estimate (countOnly)

Returns one item with recordType: "estimate" and estimatedTotal. One Vinted search reports at most 960 matches, so a result of 960 is a lower bound (isLowerBound: true, the run message says "at least 960"): narrow the filters to see the real number. Counting beyond 960 would mean reading the search page by page, which is what a run does. With several startUrls the result is the sum of the searches. It is not charged.

Limits and notes

  • One search exposes at most 960 listings (10 pages of 96). For maxItems above that the Actor splits by price. Sorting then applies only inside each part. truncatedPartitions above 0 means more than 960 listings with the same price that cannot be separated.
  • Vinted shows no absolute posting date on the listing page: enrichDetails returns the relative text as uploadedAgo (for example 2 dni). Vinted shows no public view counter, so there is none in the output; the favourite count is the only public counter.
  • price is in the currency of the marketplace; Vinted converts listings from other countries. originalPrice (with enrichDetails) is the price as the seller listed it.
  • Names of categories and conditions are in the language of the marketplace. A category name that is not found is answered with close names; listCategories shows the whole tree.
  • A filter code in otherFilters that the category does not offer stops the run before anything is charged, with the codes the category has.
  • maxItems is one budget for the whole run: with several startUrls the first URLs use it up first.
  • Vinted protects its site with anti-bot systems. Runs use Apify residential proxies in the country of the marketplace (included in the platform usage cost). A page that cannot be read after all retries is counted in failedPages and the run ends PARTIAL.
  • The Actor uses the web interface of Vinted, which is unofficial and can change without notice.
  • The Actor reads public pages anonymously. It never logs in, never favourites, messages or buys, and never changes anything on an account.

This Actor collects data that Vinted shows publicly. Vinted's terms of service restrict automated access to the site and the use of its content; you are responsible for using the data lawfully and in line with the terms of the marketplace you read. Listings contain personal data of sellers (login, ID, reputation), so GDPR rules apply to how you store and use them. The Actor is not affiliated with Vinted.

Development

npm test, npm run typecheck, npm run lint. The mapping of the Vinted network requests lives in docs/openapi/ (openapi.yaml, ENDPOINTS.md, captures/); npm run openapi regenerates it from the Playwright captures in tmp/har/ (npm run openapi:capture). Backlog: docs/backlog.md, architecture: docs/diagram.md, competitors and pricing: docs/pricing.md.