eBay Search Results Scraper - Prices & Sold Data avatar

eBay Search Results Scraper - Prices & Sold Data

Pricing

from $3.00 / 1,000 results

Go to Apify Store
eBay Search Results Scraper - Prices & Sold Data

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

Daniel Valev

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

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

  1. Enter a keyword - e.g. iphone 15 (or paste any eBay search URL).
  2. Pick filters (optional) - marketplace, condition, price range, sold & completed.
  3. 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), parsed discountPercent, 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 soldCount and 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.

ScrapeListingsCost
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.

FieldTypeDefaultDescription
searchQueriesstring[]-Keywords; each runs its own search. Required unless startUrls is provided.
startUrlsarray[]Direct eBay search URLs (category pages, sold listings, etc.). Your parameters are preserved; the Actor forces 60/page and paginates.
marketplaceenumebay.comWhich eBay domain to search (keyword searches only).
maxProductsPerSearchinteger100Cap per query/Start URL. 0 = unlimited.
maxSearchPagesinteger5Max result pages per search (max 20; eBay caps results around 20 pages).
sortenumbest_matchbest_match, ending_soonest, newly_listed, price_low, price_high.
conditionenum[][]new, open_box, certified_refurbished, seller_refurbished, used, for_parts. Empty = all.
listingTypeenumallall, auction, buy_it_now, best_offer.
listingStatusenumactiveactive, or sold for sold & completed listings (real sale prices).
minPrice / maxPricenumber-Price range in the marketplace currency (decimals allowed, e.g. 19.99).
freeShippingOnlybooleanfalseOnly listings with free shipping.
sellerLocationenumallall, domestic_only, worldwide.
deduplicateItemsbooleantrueSkip item IDs already scraped in this run.
proxyConfigurationproxyResidentialProxy settings. Residential strongly recommended.
maxRequestRetriesinteger5Retries per blocked/failed request (1–10).
debugLogbooleanfalseVerbose 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

FieldTypeNotes
typestringAlways "product".
itemIdstringeBay item ID.
titlestringListing title.
pricenumber|nullFirst/lowest numeric price.
priceStringstring|nullRaw price text.
listPriceStringstring|nullRaw strikethrough/original price.
shippingCoststring|nullRaw shipping text.
returnPolicystring|nullRaw returns text.
couponstring|nullCoupon text, if shown.
discountTextstring|nullRaw discount text (e.g. "40% off").
conditionstring|nullCondition text.
listingTypestring|null"Buy It Now" or "Auction".
bidCountnumber|nullAuction bids.
timeLeftstring|nullAuction time-left text.
bestOfferbooleanBest Offer accepted.
soldCountstring|nullRaw sold text (e.g. "93+").
sellerNamestring|nullSeller username.
sellerFeedbackPercentstring|nullRaw (e.g. "99.3%").
sellerFeedbackCountstring|nullRaw (e.g. "153.4K").
isSponsoredbooleanSponsored placement.
thumbnailstring|nullThumbnail image URL.
imagesstring[]Image URLs available on the card.
urlstringCanonical listing URL (tracking stripped).
scrapedAtstringISO timestamp.

Enriched fields (extra value)

FieldTypeNotes
currencystring|nullISO code inferred from the price / marketplace.
priceMin / priceMaxnumber|nullFor range prices ("$100 to $200").
shippingCostValuenumber|nullNumeric shipping ("Free" → 0).
totalPricenumber|nullprice + shippingCostValue - the key field for price monitoring.
listPricenumber|nullNumeric original price.
discountPercentnumber|nullParsed from text or computed from list vs. price.
soldCountValuenumber|null"93+" → 93, "1.2K" → 1200.
soldCountIsMinimumbooleanTrue when the source used "+".
soldDatestring|nullSale date on sold/completed listings (e.g. "Sold Jul 11, 2026").
sellerFeedbackPercentValuenumber|null99.3.
sellerFeedbackCountValuenumber|null"153.4K" → 153400.
itemLocationstring|nullItem location text.
subtitlestring|nullSecondary description line.
isFreeShippingboolean|nullDerived from shipping text.
isFreeReturnsboolean|nullDerived from returns text.
conditionCategorystring|nullNormalized condition bucket across languages: NEW, OPEN_BOX, REFURBISHED, USED, FOR_PARTS, OTHER.
imageLargestring|nullHigher-resolution image URL (thumbnail bumped to s-l1600).
priceDropTextstring|nullPrice-drop promo on the card (e.g. "NEW LOW PRICE").
availabilityTextstring|nullLow-stock / urgency text ("Last one", "Almost gone", "Letzter Artikel").
badgesstring[]Card badges (Top Rated Plus, eBay Refurbished, …).
watchersTextstring|null"24 watchers" text, when shown.
listedDatestring|nullListed date text, when shown.
searchQuerystringWhich query/Start URL produced the item.
pageNumbernumberResult page (rank tracking).
positionOnPagenumber1-based rank on that page.
marketplacestringe.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 ApifyClient
client = 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 maxProductsPerSearch to 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, and sellerLocation - 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 searchQueries instead 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.


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.