eBay Search Results Scraper - Prices & Sold Data
Pricing
from $3.00 / 1,000 results
eBay Search Results Scraper - Prices & Sold Data
Turn eBay searches into clean JSON: total price (item + shipping), condition, seller ratings, sold counts, images, search rank. Active or sold & completed listings across 8 marketplaces. Fast, no browser - built for price monitoring, repricing, and market research.
Pricing
from $3.00 / 1,000 results
Rating
0.0
(0)
Developer
Daniel Valev
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Turn any eBay search into clean, structured data. Give the Actor keywords (or paste eBay search URLs) and it returns every listing on the results pages - title, price, shipping, condition, seller rating, sold counts, and more - ready for price monitoring, market research, repricing, and dropshipping.
Search results only. The Actor reads each results page in a single request and never opens product, seller, or any secondary pages. That keeps it fast, cheap, and gentle - while still extracting 30+ fields from every listing card.
Try it in 30 seconds
- Enter a keyword - e.g.
iphone 15(or paste any eBay search URL). - Pick filters (optional) - marketplace, condition, price range, sold & completed.
- Start - results land in your dataset as JSON, CSV, or Excel.
{ "searchQueries": ["iphone 15"], "maxProductsPerSearch": 20 }
Every listing comes back like this (30+ fields in total):
{"title": "Apple iPhone 15 128GB Unlocked","totalPrice": 412.49,"condition": "Pre-Owned","soldCountValue": 1200,"sellerFeedbackPercentValue": 99.3,"positionOnPage": 3,"url": "https://www.ebay.com/itm/..."}
A test run like the one above costs about $0.06 - full pricing below.
Why this scraper
- 60 listings per request. Uses eBay's 60-per-page layout, so a page of data costs one request.
- Rich, computed fields out of the box. Beyond raw text, you get numeric
totalPrice(item + shipping), parseddiscountPercent,soldCountValue, seller feedback as numbers, currency codes, price ranges, and rank tracking (pageNumber,positionOnPage) - all derived from the same HTML, no extra requests. - Native eBay filters. Sort, condition, listing type, price range, free-shipping-only, and seller location are applied as URL parameters - zero extra requests.
- 8 marketplaces.
ebay.com,.co.uk,.de,.fr,.it,.es,.com.au,.ca. Currency is detected per listing. - Sold / completed listings. Set
listingStatus: "sold"to analyze real sale prices - no URL crafting needed. - Built to survive. Residential proxy support, session rotation, automatic retries with backoff, block/captcha detection, and de-duplication across queries and pages.
Who it's for
- Resellers & repricers monitoring competitor prices and
totalPrice. - Market researchers measuring demand via
soldCountand price distributions. - Dropshippers sourcing products and tracking availability.
- Analysts studying sold/completed listings for real market value.
How much does it cost to scrape eBay?
Pricing is pay-per-event: a flat $0.001 per run start plus $3.00 per 1,000 results ($0.003 per listing). All platform costs - compute, residential proxies, storage - are included. No subscription, no separate usage bill.
| Scrape | Listings | Cost |
|---|---|---|
| Test run (1 keyword, 10 products) | 10 | ~$0.03 |
| 1 keyword, 2 pages | ~120 | ~$0.36 |
| 5 keywords, 3 pages each | ~900 | ~$2.70 |
| Full search (20 pages, eBay's cap) | ~1,200 | ~$3.60 |
The Actor honors your maximum cost per run: set a cap in the run options and it stops cleanly the moment the cap is reached - you are never charged past it.
Input
Configure from the Apify Console UI or via the API. All fields are optional except that you must provide searchQueries or startUrls.
| Field | Type | Default | Description |
|---|---|---|---|
searchQueries | string[] | - | Keywords; each runs its own search. Required unless startUrls is provided. |
startUrls | array | [] | Direct eBay search URLs (category pages, sold listings, etc.). Your parameters are preserved; the Actor forces 60/page and paginates. |
marketplace | enum | ebay.com | Which eBay domain to search (keyword searches only). |
maxProductsPerSearch | integer | 100 | Cap per query/Start URL. 0 = unlimited. |
maxSearchPages | integer | 5 | Max result pages per search (max 20; eBay caps results around 20 pages). |
sort | enum | best_match | best_match, ending_soonest, newly_listed, price_low, price_high. |
condition | enum[] | [] | new, open_box, certified_refurbished, seller_refurbished, used, for_parts. Empty = all. |
listingType | enum | all | all, auction, buy_it_now, best_offer. |
listingStatus | enum | active | active, or sold for sold & completed listings (real sale prices). |
minPrice / maxPrice | number | - | Price range in the marketplace currency (decimals allowed, e.g. 19.99). |
freeShippingOnly | boolean | false | Only listings with free shipping. |
sellerLocation | enum | all | all, domestic_only, worldwide. |
deduplicateItems | boolean | true | Skip item IDs already scraped in this run. |
proxyConfiguration | proxy | Residential | Proxy settings. Residential strongly recommended. |
maxRequestRetries | integer | 5 | Retries per blocked/failed request (1–10). |
debugLog | boolean | false | Verbose logs + dump first page HTML to the key-value store. |
Example input
{"searchQueries": ["mechanical keyboard", "ergonomic mouse"],"marketplace": "ebay.com","maxProductsPerSearch": 120,"maxSearchPages": 3,"sort": "price_low","condition": ["new", "open_box"],"freeShippingOnly": true,"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }}
Output
Each dataset item is one listing. Baseline fields use the familiar names shared by popular eBay scrapers, so switching takes minutes; enriched fields are computed from the same HTML (no extra requests).
Baseline fields
| Field | Type | Notes |
|---|---|---|
type | string | Always "product". |
itemId | string | eBay item ID. |
title | string | Listing title. |
price | number|null | First/lowest numeric price. |
priceString | string|null | Raw price text. |
listPriceString | string|null | Raw strikethrough/original price. |
shippingCost | string|null | Raw shipping text. |
returnPolicy | string|null | Raw returns text. |
coupon | string|null | Coupon text, if shown. |
discountText | string|null | Raw discount text (e.g. "40% off"). |
condition | string|null | Condition text. |
listingType | string|null | "Buy It Now" or "Auction". |
bidCount | number|null | Auction bids. |
timeLeft | string|null | Auction time-left text. |
bestOffer | boolean | Best Offer accepted. |
soldCount | string|null | Raw sold text (e.g. "93+"). |
sellerName | string|null | Seller username. |
sellerFeedbackPercent | string|null | Raw (e.g. "99.3%"). |
sellerFeedbackCount | string|null | Raw (e.g. "153.4K"). |
isSponsored | boolean | Sponsored placement. |
thumbnail | string|null | Thumbnail image URL. |
images | string[] | Image URLs available on the card. |
url | string | Canonical listing URL (tracking stripped). |
scrapedAt | string | ISO timestamp. |
Enriched fields (extra value)
| Field | Type | Notes |
|---|---|---|
currency | string|null | ISO code inferred from the price / marketplace. |
priceMin / priceMax | number|null | For range prices ("$100 to $200"). |
shippingCostValue | number|null | Numeric shipping ("Free" → 0). |
totalPrice | number|null | price + shippingCostValue - the key field for price monitoring. |
listPrice | number|null | Numeric original price. |
discountPercent | number|null | Parsed from text or computed from list vs. price. |
soldCountValue | number|null | "93+" → 93, "1.2K" → 1200. |
soldCountIsMinimum | boolean | True when the source used "+". |
soldDate | string|null | Sale date on sold/completed listings (e.g. "Sold Jul 11, 2026"). |
sellerFeedbackPercentValue | number|null | 99.3. |
sellerFeedbackCountValue | number|null | "153.4K" → 153400. |
itemLocation | string|null | Item location text. |
subtitle | string|null | Secondary description line. |
isFreeShipping | boolean|null | Derived from shipping text. |
isFreeReturns | boolean|null | Derived from returns text. |
conditionCategory | string|null | Normalized condition bucket across languages: NEW, OPEN_BOX, REFURBISHED, USED, FOR_PARTS, OTHER. |
imageLarge | string|null | Higher-resolution image URL (thumbnail bumped to s-l1600). |
priceDropText | string|null | Price-drop promo on the card (e.g. "NEW LOW PRICE"). |
availabilityText | string|null | Low-stock / urgency text ("Last one", "Almost gone", "Letzter Artikel"). |
badges | string[] | Card badges (Top Rated Plus, eBay Refurbished, …). |
watchersText | string|null | "24 watchers" text, when shown. |
listedDate | string|null | Listed date text, when shown. |
searchQuery | string | Which query/Start URL produced the item. |
pageNumber | number | Result page (rank tracking). |
positionOnPage | number | 1-based rank on that page. |
marketplace | string | e.g. ebay.com. |
Missing data is never fabricated: absent values are
null(or[]/false).
Example output
{"type": "product","itemId": "266123456789","title": "Mechanical Keyboard RGB 87-Key Hot-Swappable","price": 39.99,"priceString": "$39.99","shippingCost": "Free delivery","condition": "Brand New","listingType": "Buy It Now","soldCount": "1.2K sold","soldCountValue": 1200,"sellerName": "keebs_store","sellerFeedbackPercent": "99.3%","sellerFeedbackPercentValue": 99.3,"sellerFeedbackCountValue": 153400,"currency": "USD","shippingCostValue": 0,"totalPrice": 39.99,"isFreeShipping": true,"badges": ["Top Rated Plus"],"url": "https://www.ebay.com/itm/266123456789","searchQuery": "mechanical keyboard","pageNumber": 1,"positionOnPage": 3,"marketplace": "ebay.com","scrapedAt": "2026-07-10T12:00:00.000Z"}
Run via API
Node.js (apify-client):
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('valev-lab/ebay-search-scraper').call({searchQueries: ['laptop'],maxProductsPerSearch: 100,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Python (apify-client):
from apify_client import ApifyClientclient = ApifyClient("YOUR_TOKEN")run = client.actor("valev-lab/ebay-search-scraper").call(run_input={"searchQueries": ["laptop"],"maxProductsPerSearch": 100,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item)
cURL:
curl -X POST "https://api.apify.com/v2/acts/valev-lab~ebay-search-scraper/runs?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"searchQueries":["laptop"],"maxProductsPerSearch":100}'
Scheduling & integrations
- Schedule recurring runs from the Console (Schedules) for daily price snapshots.
- Integrations: push results to Google Sheets, Slack, Zapier, Make, or your own webhook/API. The dataset exports to JSON, CSV, Excel, and XML.
Recipes
Sold / completed listings - analyze real sale prices with the listingStatus filter:
{ "searchQueries": ["iphone 13"], "listingStatus": "sold" }
(Equivalent Start URL also works: https://www.ebay.com/sch/i.html?_nkw=iphone+13&LH_Sold=1&LH_Complete=1.)
Multi-marketplace - run the same keyword across domains by using Start URLs from each domain, or run separate jobs per marketplace. Currency is detected per listing.
Tips for best results
- Start small. Set
maxProductsPerSearchto 10-20 while testing a new query or filter combo, then scale up once the results look right. - Use specific keywords.
"apple airpods pro 2nd generation"returns tighter, more relevant results than"airpods". - Stack native filters. Combine
condition,listingType,minPrice/maxPrice,freeShippingOnly, andsellerLocation- they're all applied as URL parameters, so stacking them costs nothing extra. - Keep residential proxies on. Datacenter IPs get blocked quickly; the default residential proxy group is what keeps runs reliable.
- Batch queries in one run. List multiple keywords in
searchQueriesinstead of starting a separate run per keyword - cheaper and faster than many small jobs. - Cap pages to control cost.
maxSearchPages× 60 listings is the ceiling per query; lower it if you only need the first page or two of results.
FAQ
Some prices are null. Auction-only cards, "see price in cart" items, or unusual formats can lack a parseable price. Raw text is still in priceString.
Why ~60 items per page? eBay serves up to 60 listings per results page; the Actor uses that maximum. eBay also caps search results at roughly 20 pages, so a single search yields up to ~1,200 listings.
Duplicates? With deduplicateItems (default on), an item ID scraped earlier in the run is skipped, so overlapping queries/pages don't repeat listings.
Getting blocked / few results? eBay commonly blocks datacenter IPs. Use residential proxies (default) and keep concurrency modest (the Actor already rate-limits itself).
Does it open product pages? No. Every field comes from the search-results HTML - one request per page.
Legal
This Actor collects only publicly available search-results data. You are responsible for using the output in compliance with eBay's Terms of Service and applicable laws (including data-protection rules). Do not use it to collect personal data unlawfully.