eBay Product Listing Scraper With Sold Price Data
Pricing
from $2.99 / 1,000 results
eBay Product Listing Scraper With Sold Price Data
eBay Product Listing Scraper extracts product listings with sold price data, including titles, prices, sold prices, item details, seller information, shipping, images, and URLs. Ideal for price research, market analysis, competitor tracking, and e-commerce intelligence.
Pricing
from $2.99 / 1,000 results
Rating
0.0
(0)
Developer
SimpleAPI
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
0
Monthly active users
2 days ago
Last modified
Categories
Share
eBay Sold Listings Scraper — Prices, Titles and Sold Status Data
Extract eBay product listing data — titles, prices, condition, images, shipping and item details — from any eBay search or category URL, in bulk and without an eBay account. Switch on sold/completed-listings mode and every row gets a soldStatus, plus an optional per-URL price-summary row (avgSoldPrice, medianSoldPrice, minSoldPrice, maxSoldPrice) computed only from the sold rows the run actually collected. Built for resellers, dropshippers, arbitrage sourcers and pricing analysts who need current or historical eBay pricing as structured JSON, not a screen full of listing cards.
What is eBay Sold Listings Scraper?
eBay Sold Listings Scraper takes one or more eBay search-results or category page URLs and returns every listing card on that page as a structured JSON row — title, price, condition, image, shipping, and a normalized product URL and item ID. No eBay account, login, or API key is required to run it. Switching on Sold / completed listings only re-fetches each URL as eBay's sold/completed-items view instead, tagging rows soldStatus: "sold" with the realized sale price and, where eBay shows one, a sold date.
Key features:
- 🔗 URL-based discovery — paste any eBay search-results or category URL (a keyword search, a category page, or a saved search); no crawling logic to configure
- 📦 Bulk input — add as many URLs as you need in one run; each is fetched and parsed independently
- 🏷️ Core listing fields — title, price, condition, image (upgraded to the
s-l1600full-resolution image where available), item ID, and a canonicalproduct_url - ✅ Sold-status tagging and price analytics —
soldStatus,soldDate,soldCount, plus an optional price-summary row per input URL with sample size, average, median, min and max sold price - 📍 Structured card details — shipping cost, item location, buying format (Buy It Now / Auction / Best Offer) and returns-accepted, parsed out of eBay's raw attribute text
- 🌐 Automatic proxy fallback — runs with no proxy by default; if a request fails it escalates through Apify's datacenter and residential proxy tiers on its own
Results are saved to an Apify dataset and are exportable in JSON, CSV, Excel and the other formats the Apify platform supports for any dataset.
What data can I extract with eBay Sold Listings Scraper?
Each run returns two row shapes in the same dataset: a "listing" row per scraped item, and — only when sold mode and the price-summary option are both on — one "priceSummary" row per input URL. Every field either row can carry:
| Field | Example value | Use case |
|---|---|---|
type | "listing" or "priceSummary" | Distinguish an individual item row from the aggregated price-analytics row |
product_title | "Nike Air Max 270 Men's Running Shoes Size 10" | Item identification and search matching |
condition | "Pre-Owned" | Filtering by new / used / refurbished |
price | "$54.99" | Display price as shown on the eBay card |
image_url | "https://i.ebayimg.com/images/g/abc/s-l1600.jpg" | Product image for catalogs or listings |
original_price | "$79.99" | Pre-discount / struck-through price, when eBay shows one |
card_attribute | ["Free shipping", "Located in United States"] | Raw attribute text captured from the listing card |
shippingCost | "Free shipping" | Delivery-cost comparison across listings |
itemLocation | "Located in United States" | Sourcing or shipping-distance filtering |
buyingFormat | "Buy It Now" | Segmenting fixed-price vs. auction inventory |
returnsAccepted | "30 days returns accepted" | Buyer-risk assessment |
itemId | "1234567890" | Stable eBay item identifier, also used for de-duplication |
product_url | "https://www.ebay.com/itm/1234567890" | Canonical link back to the listing |
input_url | "https://www.ebay.com/sch/260010/i.html?_nkw=shoe&Brand=Nike" | Which input search/category URL produced the row |
scrapedAt | "2026-08-15T09:41:02.123456+00:00" | Freshness / audit timestamp |
soldStatus | "active" or "sold" | Whether the row came from the normal listing view or the sold/completed view |
soldDate | "Aug 5, 2026" or null | Realized sale date, when eBay's card carries one |
soldCount | 109 or null | Popularity badge ("109 sold") parsed from the card |
sampleSize | 12 | Number of sold rows the price summary was computed from (priceSummary row only) |
avgSoldPrice | 61.4 or null | Average realized price across sampled sold rows (priceSummary row only) |
medianSoldPrice | 58.99 or null | Median realized price (priceSummary row only) |
minSoldPrice | 24.0 or null | Lowest realized price in the sample (priceSummary row only) |
maxSoldPrice | 119.99 or null | Highest realized price in the sample (priceSummary row only) |
Sold status and price analytics
soldStatus, soldDate and soldCount sit on every listing row and tell you whether that item is from the live marketplace or a completed sale. When Sold / completed listings only and Include price summary row are both on, one extra priceSummary row is appended per input URL — sampleSize, avgSoldPrice, medianSoldPrice, minSoldPrice and maxSoldPrice — computed purely from the sold rows that specific run collected. A reseller pricing a pair of sneakers can point one URL at the sold/completed search for that model and read the median realized price straight off the summary row instead of averaging listing prices by hand. Fields are null when the run collected zero sold rows for that URL — the summary is never estimated or filled from another query.
Listing details and identifiers
condition, shippingCost, itemLocation, buyingFormat, returnsAccepted and card_attribute are the fields you filter and segment on downstream. They let you split a raw pull into, for example, "Buy It Now, free shipping, US-located, new condition" without re-scraping — since none of these are input filters on eBay's side, they're the columns you'd apply your own WHERE clause to once the data lands in your warehouse or spreadsheet.
How does eBay Sold Listings Scraper differ from the official eBay API?
eBay's free Buy Browse API returns active listings with OAuth authentication, but it does not return sold or completed-sale data at all — that lives in eBay's separate Marketplace Insights API, which eBay's own developer documentation describes as a Limited Release product restricted to approved partners (as observed on developer.ebay.com, checked 2026-08-15). eBay's older Finding API, which used to expose completed-item search to any registered developer, was deprecated in January 2024 and fully decommissioned in February 2025 — its findCompletedItems operation had already been restricted since 2020.
| Feature | eBay's official APIs | eBay Sold Listings Scraper |
|---|---|---|
| Access to sold/completed listing data | Only via Marketplace Insights API — Limited Release, requires eBay business approval | Built in via the sold/completed-view toggle, no approval process |
| Setup | Developer account, app registration, OAuth token; sold data requires a separate approval application | Paste eBay URLs, run |
| Access to active listings | Free (Browse API), requires an OAuth token per request | No eBay account, API key or OAuth token required |
| Output shape | Per-API response schema, separate integration for active vs. sold data | One consistent JSON row shape for both listing and sold-price-summary rows |
| Price analytics | Not provided — computed by the caller from raw API responses | avgSoldPrice / medianSoldPrice / minSoldPrice / maxSoldPrice computed automatically per run |
Why is eBay's own sold-data API not an option for most developers?
The API that actually answers "what did this sell for" — Marketplace Insights — is not self-serve. eBay's developer documentation states it is a Limited Release API, and its access page has described it as restricted and not open to new applicants (checked 2026-08-15). A small team or individual developer typically cannot get a keyset for it at all, which is why most public "eBay sold price" tools, including this one, work from eBay's public search pages rather than a sold-data API endpoint. This Actor covers that gap by re-requesting the same public search/category URL with eBay's own sold/completed-items filter parameters and parsing the result — no API keyset, approval, or OAuth flow involved.
⚠️ Note the trade-off: because this route uses eBay's public search pages rather than an approved API, it inherits eBay's page-level access rules for that view (see the FAQ on zero sold rows below) — something a fully approved Marketplace Insights integration would not.
Use eBay's official APIs directly if you already hold approved Marketplace Insights access and need a formally supported API integration. Use this Actor when you need sold-price or listing data now, without an approval process, a developer account, or OAuth setup.
How to use data extracted from eBay?
Resellers and arbitrage sourcers
Point priceCheckUrls at a search for the exact product and variant you're pricing, turn on Sold / completed listings only, and read avgSoldPrice / medianSoldPrice straight off the priceSummary row to decide a listing or offer price before you buy inventory. Cross-check against minSoldPrice and maxSoldPrice to see the realistic spread rather than a single number, and use soldCount on individual rows to gauge how liquid that specific listing has been.
Agencies and marketplace consultants
Run the same set of category or brand-search URLs on a recurring schedule for multiple clients, and compare avgSoldPrice trends and buyingFormat mix over time to benchmark a client's pricing against the category norm. Because every row carries input_url and scrapedAt, historical runs stay attributable to the exact search and the exact date they were captured.
Market research and category intelligence
Feed a batch of category or keyword URLs across a product line and build a distribution of price, condition and buyingFormat to map how a category is actually selling on eBay — new vs. pre-owned mix, auction vs. Buy It Now share, and shipping-cost norms via shippingCost. Combine with the priceSummary rows to track a category's realized-price band over successive runs.
AI agents and automated pipelines
Because the Actor is a standard Apify Actor callable over HTTP with a fixed JSON row shape, it drops into an agent tool call or scheduled pipeline directly: a pricing agent can call it with a product URL, read avgSoldPrice from the returned priceSummary row, and act on it — list, re-price, or flag — without any custom parsing logic per source.
🔼 Input sample
| Parameter | Required | Type | Constraints | Description |
|---|---|---|---|---|
priceCheckUrls | No | array (stringList) | — | Paste one or more eBay search or category URLs. Example: search results for "Nike shoes", a category page, or saved searches. |
urls | No | array (stringList) | — | Same meaning as priceCheckUrls. Kept so input JSON written for the plain eBay Product Listing Scraper keeps running unchanged. Used only when priceCheckUrls is empty. |
soldListingsOnly | No | boolean | default false | ON re-fetches each URL as eBay's sold & completed-items view and tags every returned row soldStatus: "sold", with the realized sale price in price and soldDate when eBay shows one. OFF (default) scrapes the normal active-listing view, tagging rows soldStatus: "active". |
includePriceSummary | No | boolean | default true | When soldListingsOnly is ON, adds one extra row per input URL (type: "priceSummary") with sampleSize, avgSoldPrice, medianSoldPrice, minSoldPrice and maxSoldPrice, computed only from the sold rows this run actually collected. No effect when soldListingsOnly is OFF. |
proxyConfiguration | No | object (proxy) | default {"useApifyProxy": false} | Optional. Leave default (no proxy) for most runs. If you enable a proxy here, your choice is used first; the Actor still automatically falls back to a broader proxy tier if the request fails. |
No parameter is required — but the run produces no rows and exits with an error if both priceCheckUrls and urls are empty.
{"priceCheckUrls": ["https://www.ebay.com/sch/260010/i.html?_nkw=shoe&Brand=Nike"],"soldListingsOnly": true,"includePriceSummary": true,"proxyConfiguration": {"useApifyProxy": false}}
Common pitfall: turning on soldListingsOnly does not guarantee sold rows come back. eBay's sold/completed-items search view can return a genuine sign-in/verification page instead of results for anonymous or proxied traffic — the run still succeeds, the page fetch still worked, but that URL legitimately produces 0 sold rows. This is logged per page and never faked as data; see the FAQ below for how to tell the difference from a query that has no sold history.
🔽 Output sample
Every row is typed, normalized JSON with a consistent schema across a run — type tells you whether you're looking at a "listing" row or a "priceSummary" row. Results are stored in the run's Apify dataset and are downloadable as JSON, CSV, Excel, or the platform's other standard dataset export formats.
{"type": "listing","product_title": "Nike Air Max 270 Men's Running Shoes Size 10","condition": "Pre-Owned","price": "$54.99","image_url": "https://i.ebayimg.com/images/g/abc123AAOSw/s-l1600.jpg","original_price": "$79.99","card_attribute": ["Free shipping", "Located in United States"],"shippingCost": "Free shipping","itemLocation": "Located in United States","buyingFormat": "Buy It Now","returnsAccepted": "30 days returns accepted","product_url": "https://www.ebay.com/itm/1234567890","input_url": "https://www.ebay.com/sch/260010/i.html?_nkw=shoe&Brand=Nike","itemId": "1234567890","scrapedAt": "2026-08-15T09:41:02.123456+00:00","soldStatus": "sold","soldDate": "Aug 5, 2026","soldCount": 109}
{"type": "priceSummary","input_url": "https://www.ebay.com/sch/260010/i.html?_nkw=shoe&Brand=Nike","sampleSize": 12,"avgSoldPrice": 61.4,"medianSoldPrice": 58.99,"minSoldPrice": 24.0,"maxSoldPrice": 119.99,"scrapedAt": "2026-08-15T09:41:03.804112+00:00"}
Each pushed row — listing or price-summary — is charged under the single row_result pay-per-event name; there is no separate uncharged accounting row to filter out.
How do you filter and target specific listings?
This Actor's targeting is done through the URL you feed it and two toggles, not a set of built-in search parameters — precision comes from how you build the eBay search/category URL itself:
- Search vs. category URL — a keyword search URL (
_nkw=...) is more precise for a specific model or variant; a category URL returns everything in that eBay category, which is broader but useful for category-level price mapping. Use the query that matches how specific your target is. - Active vs. sold scope —
soldListingsOnly: false(default) gets you current asking prices and live inventory;soldListingsOnly: truere-fetches the same URL against eBay's sold/completed-items filter (LH_Complete=1&LH_Sold=1) so you see what actually sold, not what's listed. - Narrowing inside the URL — any filter eBay's own search UI supports (brand, condition, price range, item location, "Buy It Now" only) is expressed as query parameters on the URL you paste in, so building a tighter eBay search before pasting it produces a tighter result set — the Actor doesn't re-filter after the fact.
- Volume via more URLs, not a result-count parameter — there is no
maxItems/limitinput; each URL returns the listings on that one search-results page. To cover more ground, add more URLs (different keywords, categories, or price-banded searches) rather than expecting one URL to paginate further.
Three real examples:
{ "priceCheckUrls": ["https://www.ebay.com/sch/i.html?_nkw=nike+air+max+270&_sacat=0&LH_ItemCondition=3000"] }
Narrow to a specific model, in "Used" condition only, via eBay's own condition filter on the URL.
{"priceCheckUrls": ["https://www.ebay.com/sch/i.html?_nkw=nike+air+max+270"],"soldListingsOnly": true,"includePriceSummary": true}
Get realized sold prices and a computed price summary for the same search, instead of live asking prices.
{"priceCheckUrls": ["https://www.ebay.com/sch/i.html?_nkw=nike+air+max+270&_udlo=40&_udhi=80","https://www.ebay.com/sch/i.html?_nkw=nike+air+max+270&_udlo=80&_udhi=150"]}
Split one product into price bands across multiple URLs to widen coverage instead of relying on a single page's result count.
▶️ Want to try other eBay scrapers?
| Scraper name | What it extracts |
|---|---|
| Amazon Search Scraper By Country & Currency | Amazon search results across country and currency variants |
| Amazon Product Details Scraper (Bestsellers & New Releases) | Full Amazon product detail pages, bestseller and new-release listings |
| Amazon Price Tracker — Title, Image & Product Updates | Amazon product title, image and price changes over time |
| Amazon DE Sellers Leads Scraper — Product Price & Ratings | Amazon.de seller product listings with price and rating data |
| Walmart Reviews Scraper With Seller & Variant Details | Walmart product reviews plus seller and variant detail |
| Shopify Products Scraper With Variant & SKU Rows | Shopify storefront products broken out by variant and SKU |
How to extract eBay data programmatically
This Actor runs as a standard Apify Actor: one authenticated call starts the run, and structured JSON comes back from its dataset — no eBay-side API key involved.
Python example
from apify_client import ApifyClientclient = ApifyClient("<APIFY_API_TOKEN>")run = client.actor("YOUR_USERNAME/ebay-product-listing-scraper-with-sold-price-data").call(run_input={"priceCheckUrls": ["https://www.ebay.com/sch/i.html?_nkw=nike+air+max+270"],"soldListingsOnly": True,"includePriceSummary": True,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item["type"] == "listing":print(item["product_title"], item["price"], item["soldStatus"])elif item["type"] == "priceSummary":print("Median sold price:", item["medianSoldPrice"])
Export to spreadsheets or CRM
Use the Apify Console's dataset "Export" button, or the API's dataset export endpoint, to pull results as CSV or Excel. Map product_title → product name, price → list price, soldStatus/soldDate → sale status columns, and product_url/itemId → the unique key you join back to inventory or CRM records on.
Is it legal to scrape eBay?
Scraping publicly listed eBay product data is generally legal — eBay listings are published specifically so buyers can find and evaluate them, and this Actor only reads what any visitor to eBay's public search pages can already see. The records this Actor returns are business and product data — titles, prices, conditions, sold status — not personal data about identifiable individuals, so this falls under eBay's Terms of Service and general database-rights considerations rather than GDPR or CCPA, which govern personal data specifically. You are still responsible for complying with eBay's Terms of Service for how you use the collected data, particularly for commercial redistribution. Consult legal counsel for commercial applications involving bulk storage of personal data.
❓ FAQ
Does this Actor tell me if a listing is still active or has ended?
Yes — soldStatus is set directly from which mode produced the row: "active" for the normal listing-search view, "sold" for the sold/completed-items view. It reflects the search mode used at scrape time, not a live re-check of the listing afterward, so treat it as accurate as of scrapedAt.
Can I get sold-price data along with the main listing records?
Yes. Turn on soldListingsOnly to pull the sold/completed view (each row gets soldStatus: "sold", soldDate and the realized price), and leave includePriceSummary on (its default) to also get one priceSummary row per input URL with sampleSize, avgSoldPrice, medianSoldPrice, minSoldPrice and maxSoldPrice. Summary fields are null, never guessed, when the run collected zero sold rows for that URL.
How accurate is the price data?
The Actor returns the price exactly as it appears on eBay's public listing card at request time — it does not interpret, adjust, or estimate it. Because eBay listing prices and availability change continuously, treat older runs as a historical snapshot and re-run for current data before acting on it.
How many listings can I get per run?
There is no maxItems/limit input. Each URL you provide returns the listings present on that one eBay search-results page — the Actor does not auto-paginate a single URL further. To collect more, add more input URLs (different keywords, categories, or narrower filters) rather than expecting one URL to return unlimited results.
What is the soldListingsOnly filter actually doing?
It rewrites your URL with eBay's own LH_Complete=1&LH_Sold=1 query parameters — the same pair eBay's own site uses for its sold/completed-items search — and fetches that instead of the plain listing page. Both parameters are required together; eBay does not honor LH_Sold on its own.
⚠️ Why did my sold-listings run return 0 sold rows?
eBay serves a genuine sign-in or verification page for the sold/completed-items view to anonymous or proxied traffic instead of results — a real platform-level restriction, not a bug in this Actor. When that happens the run logs it explicitly per page and returns 0 sold rows for that URL rather than fabricating results; the request itself still succeeded. Re-running later, or switching that URL to the standard (non-sold) view, are the two practical workarounds.
Is there legal precedent for scraping eBay?
Yes — the earliest and best-known case is eBay, Inc. v. Bidder's Edge, Inc., N.D. Cal., decided in 2000, where eBay obtained an injunction against an aggregator's automated access under a trespass-to-chattels theory. It predates today's public API landscape and turned on the volume and manner of access rather than scraping being categorically prohibited; it is still the case most commonly cited in discussions of eBay scraping.
Does eBay Sold Listings Scraper work with Claude, ChatGPT, and AI agent frameworks?
It is callable as a standard Apify Actor run — any agent framework that can make an authenticated HTTP call or use the apify-client SDK can trigger a run and read back the resulting dataset rows. No MCP server is documented for this Actor.
Can I use this Actor without an eBay API key or developer account?
Yes. You only need an Apify account to run the Actor. No eBay account, API key, OAuth token, or developer application of any kind is required — the Actor reads eBay's own public search and listing pages directly.
Conclusion
eBay Sold Listings Scraper turns any eBay search or category URL into structured listing data — title, price, condition, shipping and buying-format details — and, on demand, the realized sold price and a locally computed price summary that eBay's own restricted Marketplace Insights API would otherwise require business approval to access. It fits resellers pricing inventory, agencies benchmarking client categories, researchers mapping a category's price distribution, and agent pipelines that need current eBay pricing without an API key. Add your eBay URLs in the Apify Console or via the API and run it to get your first dataset.