eBay Sold Listings Scraper
Get eBay sold and completed listings with sale price, shipping, sold date and condition. 9 marketplaces, no eBay API key. $0.70 per 1,000 listings.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
query,site,categoryId(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.0007 per sold listing = $0.7 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Sold listing returned | Charged once per unique real sold eBay listing row returned. Sample and diagnostic rows are never charged. | $0.0007 |
| Actor Start | Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). | $0.001 |
Pay-per-event pricing: you are billed per result, not per subscription — a run that returns nothing costs nothing beyond the start fee. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-08-10, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
query | Keywords to search sold and completed listings for, for example vintage camera. Leave empty to get one labeled, uncharged sample row. | string |
site | Which eBay site to search. Prices and sold dates come back in that marketplace's currency and date format. | string |
categoryId | Optional eBay category ID to restrict the search, for example 625 for cameras and photo. | string |
condition | Optional condition filter, applied by eBay itself through LH_ItemCondition. | string |
minPrice | Applied by eBay through _udlo and re-checked on the parsed price. | number |
maxPrice | Applied by eBay through _udhi and re-checked on the parsed price. | number |
soldFrom | Keep only listings whose sold date is on or after this date. Applied after parsing. | string |
soldTo | Keep only listings whose sold date is on or before this date. Applied after parsing. | string |
currency | Keep only listings priced in this currency, for example USD or GBP. Useful on marketplaces that mix currencies. | string |
maxItems | Maximum unique sold listings to return and charge for. | integer |
maxPages | Result pages to walk. Each page carries about 200 sold listings. | integer |
maxSessions | eBay burns sessions. Each attempt warms a brand new session on a new proxy address before requesting the page. | integer |
requestTimeoutSecs | Maximum duration of each request. | integer |
What you get
A structured dataset — each result includes fields like:
itemIdtitlesalePricecurrencyshippingCostconditionsoldDatebuyingFormatitemLocationlistingUrlExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
Related tools in E-commerce & Price Tools
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
1688 Wholesale Scraper
Scrape 1688.com wholesale listings: product ID, title, unit price, quantity price tiers, minimum order quantity, supplier company, sales counts.
Alibaba 1688 Supplier Ratings Scraper
Scrape 1688.com supplier ratings: composite score, five sub-scores, repeat-buyer rate, years on platform, factory vs trader, audits, location.
Alibaba.com Scraper
Extract Alibaba.com products without an account: price ranges, quantity price tiers, MOQ, supplier name, country, years, verified status, ratings and images.
AliExpress Products Scraper
Extract public AliExpress product pages and direct search cards with product IDs, prices, ratings, reviews, orders, stores and images.
Taobao Category Products Scraper
Scrape Taobao products by category. 20 categories, prices in CNY, seller and shop IDs, product URLs. No account, no cookies. $1.95 per 1,000 products.
Amazon Product & Reviews Scraper
Scrape Amazon product details, prices, ratings and reviews by ASIN or keyword search across any marketplace. No login or API key needed.
Where this tool sits
- Categories
- E-commerce & Price Tools
- Platforms
- eBay
eBay Sold Listings Scraper — sold comps API, no eBay key
Search eBay's sold and completed listings and get them back as rows: item id, title, sale price, currency, shipping cost, sold date, condition, buying format, seller location and image.
This is what you use to price something. What did this actually sell for, how many times, at what spread, in the last N days.
No eBay developer account, no OAuth, no browser.
Output
| Field | Notes |
|---|---|
itemId, title, listingUrl | the listing |
salePrice, currency | the price it sold for, parsed to a number, plus the marketplace currency |
shippingCost, shippingText | shipping parsed to a number; Free delivery becomes 0. shippingText keeps eBay's raw string |
soldDate, soldDateText | ISO timestamp and eBay's own label ("Aug 9, 2026" / "10 Aug 2026") |
condition | "Pre-Owned", "Brand New", "Open Box", "Parts Only", "Very Good - Refurbished" … |
buyingFormat | "Buy It Now", "or Best Offer", "Best offer accepted", "4 bids" |
bids | number of bids, when the listing was an auction |
itemLocation | where the seller shipped from |
imageUrl | the gallery thumbnail URL (the image is not downloaded) |
page, source, scrapedAt | provenance |
A real row, as it lands in the dataset:
{
"ok": true,
"_sample": false,
"itemId": "396512340987",
"title": "Nintendo Switch OLED Console White Joy-Con — Very Good Condition",
"listingUrl": "https://www.ebay.com/itm/396512340987",
"salePrice": 249.99,
"currency": "USD",
"shippingCost": 0,
"shippingText": "Free delivery",
"soldDate": "2026-08-09T00:00:00.000Z",
"soldDateText": "Aug 9, 2026",
"condition": "Pre-Owned",
"buyingFormat": "Buy It Now",
"bids": null,
"itemLocation": "United States",
"imageUrl": "https://i.ebayimg.com/images/g/AbCdEfGh/s-l500.jpg",
"page": 1,
"source": "ebay.com",
"scrapedAt": "2026-08-10T12:41:07.882Z"
}
Auction rows look the same but carry "buyingFormat": "12 bids" and "bids": 12.
Measured field coverage
Measured on a real 300-row platform run on 2026-08-10: query nintendo switch, 2 pages, ebay.com. 300/300 rows real, 0 diagnostics, 54 s.
| Field | Filled |
|---|---|
itemId, title, listingUrl, salePrice, currency, soldDate, soldDateText, condition, buyingFormat, itemLocation, imageUrl | 100% |
shippingCost, shippingText | 99.7% |
bids | 19.0% |
bids is only present on auction listings — 19% of that sample. No column was empty on every row. Median sale price in the sample: $126.75.
Input
query— keywords. Leave it empty and you get one labelled, uncharged sample row.site—ebay.com,.ca,.co.uk,.de,.com.au,.fr,.it,.es,.ie.categoryId— eBay category ID (e.g.625for cameras). Verified to change results.condition—new,open box,refurbished,used,parts. eBay applies it server-side.minPrice/maxPrice— applied by eBay and re-checked on the parsed price.soldFrom/soldTo— date window, applied after parsing.currency— keep only listings in one currency.maxItems(default 120),maxPages(default 3, ~200 listings per page),
maxSessions (default 8), requestTimeoutSecs.
proxyConfiguration— optional; leave it empty for the tuned default.
Every filter above was run live before being documented. Rows a filter drops are neither returned nor charged.
Input field names follow the conventions used across similar Actors, so switching is usually a drop-in change — query, maxItems and proxyConfiguration mean what you already expect them to mean.
A full example: everything sold in the last month, used or better, between $150 and $400, on the UK site.
{
"query": "nintendo switch oled",
"site": "ebay.co.uk",
"condition": "used",
"minPrice": 150,
"maxPrice": 400,
"soldFrom": "2026-07-15",
"maxItems": 300,
"maxPages": 3
}
The minimum viable input is just { "query": "nintendo switch oled" } — everything else has a working default.
Reliability
eBay refuses a large share of automated traffic outright, and it does not announce it: an interstitial arrives as HTTP 200 with a small body and zero listings. So this Actor judges the body content, never the status code — a 200 that contains no result cards is treated as a refusal, not as an empty search.
Sessions are warmed before they are used. A request fired straight at a search URL succeeds far less often than one made by a session that first visited the marketplace homepage and kept the cookies it was handed, then asked for the search page with a same-origin referer. Warmed sessions also paginate several pages deep without being challenged, where cold ones are stopped almost immediately. Those two numbers were measured, not assumed, on real platform runs.
A session that starts being refused is discarded and a fresh one is warmed on a new address — a burned eBay session stays burned, so retrying on the same one only wastes time. Each page gets up to maxSessions attempts. Egress is rotating datacenter addresses; no residential bandwidth is used, so there is no per-gigabyte surprise on the bill.
eBay also changes its result-card markup periodically, which silently turns a working parser into one that returns zero rows. The parser here accepts both the current and the previous card structure, and a page that genuinely yields nothing produces an uncharged diagnostic row rather than a silent empty dataset.
Billing
$0.70 per 1,000 sold listings ($0.0007 each), plus $0.001 each time a run starts. This is the cheapest eBay sold-listings scraper on the Apify Store.
Pay per event, event name listing. One event per unique real listing. Duplicates across pages are charged once. Never charged: the empty-input sample, filtered-out rows, EBAY_BLOCKED, NO_LISTINGS and NO_MATCHES diagnostics.
What a run actually costs:
| Run | Real listings returned | Total |
|---|---|---|
| Quick price check | 50 | $0.036 |
| Default settings | 120 | $0.085 |
| Full comp pull, 2 pages | 300 | $0.211 |
| Maximum, 10 pages | 2,000 | $1.401 |
Because charging happens per row after the row is pushed, a run that is blocked or matches nothing costs you the $0.001 start fee and nothing else. Filters are the cheap way to work: minPrice, condition and soldFrom drop rows before they are charged, so a narrow query is genuinely cheaper than a broad one you post-process yourself.
What this does not do
- No seller username or feedback score. eBay removed those from the search-result card; this actor
will not fabricate them. Use a seller-profile scraper if you need them.
- No per-item detail pages, so no item specifics, description HTML, or full photo set.
- No live/active listings — this is the sold and completed view only.
- No eBay API, no OAuth, no application key.
- No residential proxy.
- eBay caps a search at roughly 200 listings per page; very deep pagination eventually stops
returning new items and the actor writes an uncharged NO_LISTINGS row rather than looping.
- Non-US marketplaces publish fewer attributes on the result card, so
conditionanditemLocation
are sparser there than the 100% measured on ebay.com.
- Sold-listing coverage on eBay itself is roughly the last 90 days.
soldFromcannot reach further
back than eBay retains.
FAQ
How do I find what something sold for on eBay? Put the product name in query, set soldFrom to the start of the window you care about, and read salePrice and soldDate from each row.
How many sold listings per run? About 200 per page. maxPages up to 20, maxItems up to 2,000. A 300-row run took 54 seconds.
Do I need an eBay API key? No. Nothing to register, nothing to authorise.
Can I search a non-US eBay site? Yes — set site. Prices come back in that marketplace's currency and soldDateText in its date format; soldDate is normalised to ISO either way. Note that non-US sites publish fewer attributes, so condition is much sparser there than the 100% measured on ebay.com.
Does it include shipping in the price? No. salePrice is the item price and shippingCost is separate, so you can add them yourself or compare item-only prices.
How do I get a median or a price range out of this? Run the query, export the dataset as CSV or JSON, and aggregate salePrice yourself — the rows are one listing each, already parsed to numbers, so a median is a one-liner in a spreadsheet or pandas. Use currency to avoid mixing marketplaces in the same average.
What happens if eBay blocks it? Each page gets up to maxSessions freshly warmed sessions on new addresses. If all of them are refused you get one uncharged EBAY_BLOCKED row saying so, and zero listing charges.
Is the sample row charged? No. Empty input returns one _sample: true row and zero billable events.
Can I schedule it? Yes — a daily or weekly schedule on the same query gives you a rolling comp history. Each run is independent, so deduplicate on itemId if you merge datasets across runs.