eBay Product Listing Scraper With Sold Price Data avatar

eBay Product Listing Scraper With Sold Price Data

Pricing

from $2.99 / 1,000 results

Go to Apify Store
eBay Product Listing Scraper With Sold Price Data

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

SimpleAPI

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

0

Monthly active users

2 days ago

Last modified

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-l1600 full-resolution image where available), item ID, and a canonical product_url
  • Sold-status tagging and price analyticssoldStatus, 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:

FieldExample valueUse 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 nullRealized sale date, when eBay's card carries one
soldCount109 or nullPopularity badge ("109 sold") parsed from the card
sampleSize12Number of sold rows the price summary was computed from (priceSummary row only)
avgSoldPrice61.4 or nullAverage realized price across sampled sold rows (priceSummary row only)
medianSoldPrice58.99 or nullMedian realized price (priceSummary row only)
minSoldPrice24.0 or nullLowest realized price in the sample (priceSummary row only)
maxSoldPrice119.99 or nullHighest 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.

FeatureeBay's official APIseBay Sold Listings Scraper
Access to sold/completed listing dataOnly via Marketplace Insights API — Limited Release, requires eBay business approvalBuilt in via the sold/completed-view toggle, no approval process
SetupDeveloper account, app registration, OAuth token; sold data requires a separate approval applicationPaste eBay URLs, run
Access to active listingsFree (Browse API), requires an OAuth token per requestNo eBay account, API key or OAuth token required
Output shapePer-API response schema, separate integration for active vs. sold dataOne consistent JSON row shape for both listing and sold-price-summary rows
Price analyticsNot provided — computed by the caller from raw API responsesavgSoldPrice / 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

ParameterRequiredTypeConstraintsDescription
priceCheckUrlsNoarray (stringList)Paste one or more eBay search or category URLs. Example: search results for "Nike shoes", a category page, or saved searches.
urlsNoarray (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.
soldListingsOnlyNobooleandefault falseON 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".
includePriceSummaryNobooleandefault trueWhen 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.
proxyConfigurationNoobject (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:

  1. 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.
  2. Active vs. sold scopesoldListingsOnly: false (default) gets you current asking prices and live inventory; soldListingsOnly: true re-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.
  3. 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.
  4. Volume via more URLs, not a result-count parameter — there is no maxItems/limit input; 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 nameWhat it extracts
Amazon Search Scraper By Country & CurrencyAmazon 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 UpdatesAmazon product title, image and price changes over time
Amazon DE Sellers Leads Scraper — Product Price & RatingsAmazon.de seller product listings with price and rating data
Walmart Reviews Scraper With Seller & Variant DetailsWalmart product reviews plus seller and variant detail
Shopify Products Scraper With Variant & SKU RowsShopify 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 ApifyClient
client = 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.

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.

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.