Resale Price Comps: Sold and Asking Prices, 5 Marketplaces avatar

Resale Price Comps: Sold and Asking Prices, 5 Marketplaces

Pricing

from $9.12 / 1,000 vinted comps

Go to Apify Store
Resale Price Comps: Sold and Asking Prices, 5 Marketplaces

Resale Price Comps: Sold and Asking Prices, 5 Marketplaces

Resale price comps across marketplaces: what is it worth on Vinted and Grailed? One query in, one row out with count, median, cheapest and dearest per marketplace, plus sold price vs asking price and a cross marketplace arbitrage check. Only marketplaces that return comps are billed.

Pricing

from $9.12 / 1,000 vinted comps

Rating

0.0

(0)

Developer

Adrian Voss

Adrian Voss

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

One search query in, one row out: how many listings each of five resale marketplaces has for it, what the median, cheapest and dearest price is on each, and — this is the part nobody else sells — what the thing has actually sold for, next to what people are currently asking for it.

Who it's for

  • Resellers and arbitrage bots. "A listing just appeared. Is it cheap?" needs a price to compare against, and the only honest comparison is the price things really sell at. askingVsSoldGapPct answers it in one number: negative means the cheapest asking price is below the going sold price.
  • Anyone deciding what to list something at. Five markets' medians side by side, in your own currency, shows where a piece sells dearest and where it is being given away.
  • Cross-border buyers. The same jacket is not the same price in Paris, New York and Tokyo. crossMarketGapPct is how far the cheapest listing sits below the market as a whole.

It is not a listings feed. If you want every listing, with new-listing and price-drop alerts, run the single-marketplace actors instead (see Related actors at the end). This one collapses a whole search into one statistical row per query, which is what makes it cheap enough to run across a watchlist of hundreds of queries.

What "sold" means here

This matters enough to be the second section on the page.

Only Yahoo! Auctions Japan returns genuine final prices. They come from Yahoo's own closed-auction search, where every row has at least one bid and carries the price the auction actually ended at. Those are real transactions.

The other four are asking prices. Vinted, Grailed, Poshmark and Vestiaire Collective search results are what sellers currently want, which is not what anyone paid:

  • Vinted, Grailed and Vestiaire results are live, unsold listings.
  • Poshmark does mark listings sold_out, but it never reveals the negotiated final amount. A "sold" Poshmark listing only carries its own last asking price at the moment it went out of stock, so it is counted here as an asking price, because that is what it is.

Everywhere in the output the distinction is visible rather than implied:

ColumnWhat it is
soldMedianPrice, soldSampleSize, yahoo*Real final prices, from Yahoo's closed auctions
bestAskingPrice, vinted*, grailed*, poshmark*, vestiaire*Asking prices
askingVsSoldGapPctThe cheapest asking price against the real sold median

soldSampleSize travels with soldMedianPrice on purpose: a median of 3 auctions and a median of 50 are not the same evidence, and you should be able to see which one you got.

The five marketplaces

MarketplacePricesCoversRoute
VintedaskingEU second-hand fashion, EURThe vinted.fr catalog search, relevance order
GrailedaskingUsed menswear and streetwear, USDGrailed's own first-party search index
PoshmarkaskingUS resale fashion, bags, shoes, USDA poshmark.com brand page narrowed by keywords
Vestiaire CollectiveaskingLuxury resale, USD (US locale)Vestiaire's own search API
Yahoo! Auctions JapanSOLDJapan's largest auction market, JPYYahoo's own closed-auction search

One thing to know about Poshmark. poshmark.com/robots.txt disallows keyword search, so this actor never requests it. Poshmark is read through brand pages instead, which robots.txt does allow. That is why a query should start with the brand: Carhartt Detroit jacket becomes the Carhartt brand page narrowed to "Detroit jacket". For a two-word brand, use the explicit form, Louis Vuitton: neverfull. A query whose first word is not a Poshmark brand gets poshmarkStatus: NO_RESULTS with a message naming the form that would have worked, and since Poshmark returned nothing, it costs you nothing.

What you get

Per marketplace, seven columns. For Vinted, for example:

ColumnMeaning
vintedCountHow many listings were matched and priced
vintedMedianPriceMedian price, in your output currency
vintedMinPrice / vintedMaxPriceCheapest and dearest, in your output currency
vintedCurrencyWhat Vinted itself quoted in, before conversion (MIXED if more than one)
vintedSampleUrlLink to the single cheapest listing, the one to open first
vintedStatusOK, NO_RESULTS, NOT_CHECKED, BLOCKED, REQUEST_FAILED, NO_COMPARABLE_PRICES or BAD_INPUT

Plus, once per row:

ColumnMeaning
bestAskingPrice / bestAskingSourceThe cheapest single asking price anywhere, and where it is
soldMedianPrice / soldSampleSizeThe real sold median, and how many auctions it is built from
askingVsSoldGapPctCheapest asking vs sold median. Negative = the arbitrage case
crossMarketGapPctCheapest asking vs the median of the marketplace medians
sourcesChecked / sourcesFoundHow many marketplaces were asked, and how many had comps
currency / fxRateDateThe currency every price is in, and the FX snapshot used

crossMarketGapPct is deliberately the median of the marketplaces, not of all the listings pooled together. Pooling would let a marketplace that returned 20 listings outvote one that returned 2, which is a sampling artefact rather than a market signal.

Currency, and the fixed FX table

Pick one output currency (default EUR) and every price column is expressed in it. Two rules make the numbers trustworthy:

  1. Prices are converted before any median is taken. A median is never computed across mixed currencies. A listing in a currency the table does not cover is dropped from the statistics rather than counted at face value, and if that leaves a marketplace with nothing comparable you get NO_COMPARABLE_PRICES instead of a wrong number.
  2. The rates are a frozen snapshot, not a live lookup. Every row is stamped with fxRateDate, the date of the ECB reference rates used. That means two runs a week apart are comparable: a price change is a price change, not a currency wobble. It also costs you nothing, because no extra request is made to fetch rates.

Covered currencies: EUR, USD, GBP, JPY, PLN, CZK, SEK, DKK, HUF, RON, CHF, NOK, CAD, AUD, KRW. Ask for anything else and the run warns you and uses EUR rather than failing.

What a run costs, and how to control it

  • "Which marketplaces to check (and pay for)" is the real control. Only the marketplaces you select are requested at all, and you are billed only for the ones that actually return comps. Drop Yahoo if you don't need sold prices and that whole leg disappears from the bill.
  • "Pages to fetch per marketplace" defaults to 1, and one page per marketplace is what the published price is based on. Each extra page is another real request. Raise it only for a query so rare that one page doesn't fill your "listings to price" target.
  • "Listings to price per marketplace" (default 20) does not change the cost. The cost is the page requests; reading 20 rows or 96 rows off the same page costs the same.
  • "Sold prices only" makes a run cheaper as a side effect: only Yahoo can honour it, so the other four marketplaces are skipped entirely instead of having their asking prices relabelled.

A query that finds nothing anywhere is free. So is every individual marketplace that fails, is unreachable, or comes back empty, and one failing marketplace never affects the row or the other four.

How to use

  1. In the Apify Console. Open the actor page and click Start — the queries field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
  2. Via the API. Call it directly with a POST request — no Console needed once you have an API token:
    curl "https://api.apify.com/v2/acts/accountable_eel~resale-comps-unified-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"queries":["Carhartt Detroit jacket","Nike Air Max 90","Levi's 501"]}'
  3. On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.

Input

{
"queries": [
"Carhartt Detroit jacket",
"Nike Air Max 90",
"Levi's 501"
]
}

One product, brand or model per line. Each line is searched on every marketplace you select and comes back as ONE row: count, median, cheapest, dearest and a link per marketplace, plus the asking-vs-sold and cross-marketplace gaps. Put the BRAND FIRST — Poshmark's robots.txt disallows keyword search, so that source reads brand pages ("Carhartt Detroit jacket", or the explicit "Carhartt: Detroit jacket"). Accepted formats: Carhartt Detroit jacket, Nike Air Max 90, Louis Vuitton: neverfull.

Output

One row per query. Every column, for one query:

queryfoundstatusvintedCountvintedMedianPricevintedMinPricevintedMaxPricevintedCurrencyvintedSampleUrlvintedStatusgrailedCountgrailedMedianPricegrailedMinPricegrailedMaxPricegrailedCurrencygrailedSampleUrlgrailedStatusposhmarkCountposhmarkMedianPriceposhmarkMinPriceposhmarkMaxPriceposhmarkCurrencyposhmarkSampleUrlposhmarkStatusvestiaireCountvestiaireMedianPricevestiaireMinPricevestiaireMaxPricevestiaireCurrencyvestiaireSampleUrlvestiaireStatusyahooCountyahooMedianPriceyahooMinPriceyahooMaxPriceyahooCurrencyyahooSampleUrlyahooStatusbestAskingPricebestAskingSourcesoldMedianPricesoldSampleSizeaskingVsSoldGapPctcrossMarketGapPctsourcesCheckedsourcesFoundcurrencyfxRateDatescrapedAt
Carhartt Detroit jackettrueOK<vinted: listings found><vinted: median price><vinted: cheapest><vinted: dearest><vinted: native currency><vinted: cheapest listing><vinted: status><grailed: listings found><grailed: median price><grailed: cheapest><grailed: dearest><grailed: native currency><grailed: cheapest listing><grailed: status><poshmark: listings found><poshmark: median price><poshmark: cheapest><poshmark: dearest><poshmark: native currency><poshmark: cheapest listing><poshmark: status><vestiaire: listings found><vestiaire: median price><vestiaire: cheapest><vestiaire: dearest><vestiaire: native currency><vestiaire: cheapest listing><vestiaire: status><yahoo auctions jp (sold): listings found><yahoo auctions jp (sold): median price><yahoo auctions jp (sold): cheapest><yahoo auctions jp (sold): dearest><yahoo auctions jp (sold): native currency><yahoo auctions jp (sold): cheapest listing><yahoo auctions jp (sold): status><asking vs sold gap %><cross-marketplace gap %>1970-01-01T00:00:00.000Z

A query nothing was found for comes back as a row with "found": false, a message saying why each marketplace was empty, and no charge.

Example runs

Three inputs that need no credentials of any kind and return rows as they stand. Paste one into the Input tab and press Start.

1. What is a Carhartt Detroit jacket worth, everywhere?

{
"queries": ["Carhartt Detroit jacket", "Carhartt: Detroit jacket blanket lined"],
"currency": "EUR"
}

2. Sold price vs asking price, before you list something

{
"queries": ["Nike Air Max 90", "Nike: Air Max 95", "New Balance 990"],
"currency": "USD",
"maxPerSource": 30
}

3. A cross-marketplace arbitrage check on luxury bags

{
"queries": ["Louis Vuitton: neverfull", "Gucci: marmont", "Prada: re-edition"],
"currency": "EUR",
"sources": ["vinted", "vestiaire", "poshmark", "yahoo"]
}

Pricing

Pay-per-event. A flat per-run fee covers session/proxy warmup; each independent source is billed under its own event, only when that source actually returns data — see .actor/pay_per_event.json for exact prices. A miss is never charged.

Concretely: a query that hits three of five marketplaces is billed three events, not five and not one flat fee. A query that hits none is billed nothing at all.

Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

curl "https://api.apify.com/v2/acts/accountable_eel~resale-comps-unified-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
-X POST \
-H "Content-Type: application/json" \
-d '{"queries":["Carhartt Detroit jacket","Nike Air Max 90","Levi's 501"]}'

n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~resale-comps-unified-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"queries":["Carhartt Detroit jacket","Nike Air Max 90","Levi's 501"]} (swap in an expression from an earlier node for a real value).

Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~resale-comps-unified-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"queries":["{{search query}}"]}, mapping the row's search query into the queries array.

MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Resale price comps: Vinted, Grailed, Vestiaire, Poshmark" — the agent will find and run this actor.

vs. the alternatives

  • Single-marketplace comps actors answer "what is it worth on Vinted?" — one market, asking prices only. This one answers "what is it worth, and where is it cheapest", across five, with a real sold price on the same row.
  • Cross-country arbitrage checks compare one marketplace against itself in two countries. That finds shipping arbitrage; it does not tell you the same piece sells for a third more on a different platform.
  • eBay sold comps are the usual answer to "sold, not asking", and eBay's sold-listings pages are behind a bot wall that does not open to an HTTP client. Yahoo! Auctions Japan's closed-auction search is genuinely open and genuinely final-price, which is why the sold column on this row exists at all.

Limits, stated plainly

  • One country per marketplace. Vinted is read on vinted.fr (EUR), Poshmark on poshmark.com (US), Vestiaire on its US locale; Grailed is USD-only and Yahoo is JPY-only. For a specific other country, run that marketplace's own actor, which exposes all of them.
  • Poshmark needs the brand first (see above). That is a robots.txt constraint, not a shortcut.
  • A median is only as good as its sample. Every *Count and soldSampleSize is on the row so you can see when a median rests on two listings.
  • Sold comps are Japanese auctions. They are real final prices, and they are the Japanese market's prices. For a Western-market sold price, treat them as a floor and a sanity check, not a local comp.
  • Asking prices carry no shipping or fees. Every price is the item price as the marketplace states it.

Data & privacy

Only public search results are read, and only the fields needed to price them: an id, a title, a price, a currency and a link. No seller names, no seller ids, no seller profiles, no photos and no descriptions are requested or returned by this actor — a comps median does not need them, so they are never collected. No account, cookie or credential of yours is used; this actor signs into nothing.

FAQ

Is soldMedianPrice a real sold price? Yes, and it is the only one on the row. It comes from Yahoo! Auctions Japan's own closed-auction search, which lists auctions that ended with at least one bid, at the price they ended at. Every other price column is an asking price and is labelled as one.

Why is askingVsSoldGapPct negative? Because the cheapest asking price is below what things actually sell for. That is usually the interesting case.

Why did one marketplace come back empty? Read its *Status column. NO_RESULTS means it genuinely had nothing, NOT_CHECKED means you didn't select it (or "Sold prices only" skipped it), BLOCKED means it refused the request this time. In all of those, that marketplace cost you nothing.

Can I get the individual listings? Not from this actor — it returns one statistical row per query by design, which is what keeps it cheap. *SampleUrl gives you the cheapest listing on each marketplace; for the full list, run the per-marketplace actors below.

Why is the FX rate fixed instead of live? So that two runs a week apart are comparable, and so a run costs no extra request. The date is stamped on every row as fxRateDate.

How many queries can one run take? As many as you like, each line is independent. Start with "Try it first" on to check the shape on five of them before running the whole list.

For the full listing feed, with new-listing and price-drop alerts, on one marketplace: vinted-listing-lookup, grailed-listing-lookup, poshmark-listing-lookup, vestiaire-listing-lookup, yahoo-auctions-jp-lookup.