eBay Seller Scraper API - Inventory & Sales
Pricing
from $2.50 / 1,000 results
eBay Seller Scraper API - Inventory & Sales
Scrape any eBay seller's entire active inventory as JSON - 25,000+ listings reachable per seller, with price, condition, shipping, watchers and sold counts. Switch to sales mode for confirmed order prices. No login.
Pricing
from $2.50 / 1,000 results
Rating
0.0
(0)
Developer
Blackcube Agency AB
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
31 minutes ago
Last modified
Categories
Share
| eBay Data Suite • 7 Actors, one codebase, one result billed once | ||
| eBay Scraper API Sold Prices, Listings & Sellers | eBay Watch Count Scraper API Watchers & Sold | eBay Seller Scraper API ➤ You are here |
| eBay Sold Prices API Confirmed Sale Prices | eBay Card Comps API PSA, BGS, CGC & Raw | eBay Price Tracker API Monitor Listings |
| eBay Motors Scraper API Cars, Parts & Bikes | ||
More from this account: YouTube Transcript Suite · Website Contact & Email Suite · Career Site & ATS Jobs Suite · Google News Suite · Keyword Research Suite · Shopify Store Intelligence Suite · Amazon Reviews Suite · Reddit · Meta Ad Library · Vinted
Everything one eBay seller has listed, plus what their buyers actually paid.
Point it at a username and get their whole active inventory — measured at more than 25,000
listings reachable for a large seller, far past the few hundred most tools stop at. Switch
mode to sales and the same actor returns their confirmed completed orders with the price
paid on each one.
Competitor tracking, supplier research and reseller due diligence in one input.
Unofficial and not affiliated with, endorsed by, or sponsored by eBay Inc. Public, unauthenticated pages only.
What you get
| Mode | Give it | Get back |
|---|---|---|
| Search | keywords, or any eBay search URL | every matching active listing, up to Max results |
| Item | item numbers or /itm/ URLs | everything on the item page |
| Seller | a username | that seller's whole active inventory |
| Sales | a username (+ optional keyword) | confirmed orders with the price paid |
Most runs also get a price summary row — min, 25th percentile, median, 75th, 90th, max, mean, standard deviation, total value and graded share. It is billed once per query, not per result, and it is skipped entirely when a query returned fewer than 10 priced rows. Item mode does not produce one.
Every run that gets past input validation also gets a free diagnostics row telling you how many pages were fetched, how many were blocked, and exactly why the run stopped.
Listing rows
itemId · url · title · price · priceMax · currency · priceIsRange ·
condition · listingFormat · bestOffer · bids · timeLeft · shippingCost ·
freeShipping · shippingIsEstimate · itemLocation · soldCount · watchers ·
imageUrl · isGraded · gradingCompany · grade · queryTokenOverlap ·
titleMatchesQuery · sellerName · sellerFeedbackScore · sellerPositivePct
Two notes on those last three. eBay does not put the seller on a search result card, so
sellerName is filled in Seller mode (you named them) and on Item rows, and is null on a plain
keyword search rather than guessed. And every field on a row comes from that row's own listing —
nothing is ever borrowed from a neighbouring card, which is the quiet way a comps table gets
corrupted.
titleMatchesQuery is the other rare one. Thin result pages come back mixed with loosely related
listings that no filter catches, and they are the likeliest reason a median comes out wrong. Each
row scores how much of your query its title actually contains, so you can drop the padding
instead of averaging it into your numbers.
watchers is the rarest field here. Reviewing the published output fields of the twenty
largest eBay actors on the Apify Store in August 2026, we found none returning watch counts. It
is the cheapest demand signal eBay publishes, and it costs you nothing extra to receive.
Item rows
itemId · url · title · price · currency · condition · conditionCode ·
soldCount · watchers · shippingCost · sellerName · sellerFeedbackScore ·
sellerPositivePct · isGraded · gradingCompany · grade — plus availability,
quantityAvailable, shippingCurrency, returnsAccepted, returnDays, brand, mpn,
model, color, images[], productRating, productRatingCount, itemSpecifics{} and
categoryPath[].
An item row is not a superset of a listing row: auction-only fields (bids, timeLeft,
bestOffer, listingFormat) and the search-relevance fields live on listing rows only.
Sale rows
feedbackId · seller · price · currency · itemId · itemUrl · itemTitle ·
rating · comment · buyer · buyerFeedbackScore · verifiedPurchase ·
automatedFeedback · periodBucket · recencyRank · isGraded · gradingCompany ·
grade
Honest limits, stated up front
Every actor in this category has these. Most do not tell you.
| Limit | The truth |
|---|---|
| Sold-listing keyword search | Not offered. eBay requires a login for it — see above. |
| Sale dates | eBay publishes only a coarse recency band, never a date, so there is no soldDate field — there is no honest way to fill one. recencyRank gives you exact ordering instead. |
| Sale price coverage | Varies by seller, and recent orders fare best. Measured across five sellers: 100%, 100%, 99%, 100% and 11%. Older feedback tends to keep the price but lose the link to the item. Use the Sales period filter to stay in the high-coverage window, and check rowsFilteredOut and the price fill in your own output rather than assuming. |
| Search depth | Any one query can only be paged so deep. This actor detects the end of the real results, never bills you twice for the same listing, and says so in the diagnostics row. Split a broad query by price band or category to reach more. |
| Seller inventory depth | Far deeper — 25,000+ items reachable for a large seller. |
| Watchers & sold counts | eBay prints these on some cards only, and which one it prints varies by surface. Measured on our own captured pages: watchers on 8-32% of US search cards, 0% of seller-inventory cards and 0% on DE/FR/IT; sold counts are the reverse, 98% on seller inventory. Always null, never guessed — so filter on them, do not assume them. |
| Seller on search rows | eBay does not print the seller on a search card. Use Seller mode, or Item mode, where it is filled. |
| Blocks | eBay challenges some requests. When it does and will not relent, you get a free error row naming the input that failed. This actor never reports success on a page it could not read, and never bills you for one. |
| Filters run after the fetch | excludeKeywords and gradeFilter apply to rows eBay already returned. The diagnostics row reports how many were removed, and if they removed everything you get a free ALL_FILTERED row rather than an empty dataset. |
Pricing
| You are charged for | FREE | BRONZE | SILVER | GOLD+ |
|---|---|---|---|---|
| Each listing row | $4.00 / 1,000 | $3.50 / 1,000 | $3.00 / 1,000 | $2.50 / 1,000 |
| Each full item-detail row | $9.00 / 1,000 | $8.00 / 1,000 | $7.00 / 1,000 | $6.00 / 1,000 |
| Each confirmed sale row | $6.00 / 1,000 | $5.30 / 1,000 | $4.60 / 1,000 | $4.00 / 1,000 |
| Each price-summary row | $0.05 | $0.044 | $0.039 | $0.035 |
The price summary is one row per query, not per result, and it is skipped entirely on a query
that returned fewer than 10 priced rows — a percentile spread over a handful of listings is
noise, and you should not pay for noise. Turn it off with includeMarketSummary: false.
Never charged: pressing Run, error rows, diagnostics rows, duplicate rows, or a run that returns nothing.
Item-detail costs more than a listing row because an item page is roughly 25 times the data. If you only need price, condition, shipping and seller, stay in Search mode — it is the cheap one, and it is what the headline price refers to.
Set maxCostUsd and the run stops before it can exceed it, priced at the highest tier so
the ceiling holds whatever plan you are on. Reviewing the input schemas of the twenty largest
eBay actors in August 2026, we found none exposing a spend ceiling as a run input.
How to scrape eBay sold prices for a seller
Set What to scrape to Sales, put the seller's username in Sellers, and optionally set Filter sales by keyword.
{"mode": "sales","sellers": ["musicmagpie"],"salesKeyword": "vinyl","salesPeriod": "SIX_MONTHS","maxItems": 1000}
Every row is a completed order with the amount paid. Filtering by keyword is how you get comparable sales for one product: pick the sellers who move that product, then read what their buyers actually paid.
How to scrape eBay listings by keyword
{"mode": "search","searchQueries": ["nintendo switch oled", "steam deck oled"],"condition": "used","minPrice": 100,"maxPrice": 400,"sortBy": "price_lowest","maxItems": 500}
There is no limit on how many keywords you can pass — the largest actor in this category
caps its keyword list at six. Note that maxItems is a ceiling for the whole run, shared across
every keyword, so raise it when you pass many. Keywords the run never reached get a free
NOT_REACHED row naming them, rather than vanishing.
How to scrape an eBay seller's entire inventory
{ "mode": "seller", "sellers": ["musicmagpie"], "maxItems": 5000 }
You can add a keyword to search inside that seller's inventory, and any of the price, condition or format filters.
How to get full detail for the results of a search
Search and item detail are two calls on purpose, so you are never billed for detail pages you
did not ask for. Run the search, keep the itemId of the rows you actually care about, then feed
those into Item mode:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const search = await client.actor('vonsensey/ebay-scraper-api').call({mode: 'search', searchQueries: ['nintendo switch oled'], minPrice: 150, maxItems: 200,});const { items } = await client.dataset(search.defaultDatasetId).listItems();const shortlist = items.filter((i) => i.type === 'listing' && (i.watchers ?? 0) > 20).map((i) => i.itemId);if (shortlist.length > 0) {await client.actor('vonsensey/ebay-scraper-api').call({mode: 'item', itemIds: shortlist, maxItems: shortlist.length,});}
Filtering between the two calls is the whole point: an item page costs about 25 times a listing row to fetch, so the cheap pass finds the candidates and the expensive pass runs only on those.
How to scrape eBay item details in bulk
{"mode": "item","itemIds": ["326350933758", "https://www.ebay.com/itm/298593858549"],"maxItems": 200}
Item numbers and full URLs both work, mixed in the same list.
How to scrape eBay for trading card comps (PSA, BGS, CGC, SGC)
Card titles are parsed for a third-party grade, so you can separate slabs from raw cards without keyword guesswork:
{"mode": "search","searchQueries": ["charizard base set holo"],"gradeFilter": "graded","excludeKeywords": ["proxy", "custom", "reprint", "lot"],"maxItems": 1000}
gradeFilter accepts graded, raw or any. Every row carries isGraded,
gradingCompany and grade as separate fields, so you can group by grade in a
spreadsheet. Graders recognised: PSA, BGS/Beckett, CGC, SGC, PCGS and WATA on the name alone; TAG, ACE,
HGA, CSG, MNT, AGS, GMA, KSA, VGA and NGC only when a grade number sits beside them — because
"TAG Heuer" and "ACE Hardware" are not graded slabs, and treating them as such would drop
whole categories out of a raw filter.
Set gradeFilter to raw to get ungraded copies only — the comparison most card sellers
actually want, and the one a keyword blacklist gets wrong because most raw listings never
contain the word "raw".
How to scrape eBay Germany, Italy, France and 16 other marketplaces
Pick the site in eBay marketplace, or just paste a URL from that site — the marketplace is read from the URL and wins over the dropdown. Nineteen sites are supported; four are measured end-to-end, and the table below is exactly what we measured.
ebay.com · ebay.co.uk · ebay.de · ebay.fr · ebay.it · ebay.es · ebay.ca ·
ebay.com.au · ebay.at · ebay.ch · ebay.ie · ebay.nl · ebay.be · ebay.pl ·
ebay.com.sg · ebay.com.my · ebay.ph · ebay.com.hk · ebay.in
Each site is served from its own country, so a German search returns EUR and an Italian search returns EUR quoted the Italian way. Every run also reports the currency it actually saw against the one that site should quote, so a converted price can never pass silently as a native one — which is the difference between a comps table you can trust and one that is quietly wrong.
eBay also writes the condition, the shipping line and the buying format in each site's own
language. So every row carries both eBay's own wording in condition and a conditionCode
that means the same thing on every site we measured — NEW, NEW_OTHER, OPEN_BOX,
REFURBISHED, USED, FOR_PARTS — which is what makes a mixed-market dataset filterable in
one pass.
Measured on live pages from four marketplaces, 18 August 2026:
| Field | ebay.com | ebay.de | ebay.fr | ebay.it |
|---|---|---|---|---|
| title, price, currency | 100% | 100% | 100% | 100% |
| condition + conditionCode | 100% | 100% | 100% | 100% |
| shipping cost or free-shipping flag | 100% | 63% | 100% | 100% |
| buying format | 44% | 48% | 40% | 60% |
| item location | 100% | 2% | 0% | 0% |
Item location is near-zero outside the US because eBay only prints it for cross-border
listings — a domestic German listing on ebay.de simply does not carry one. It is null there,
not guessed.
How to monitor eBay prices on a schedule
Add a Schedule in the Apify Console and point it at a saved input. There is no start fee, so a run that finds five new listings costs you the price of five rows and nothing else.
Use maxCostUsd to put a hard cap on any single scheduled run.
How to call the eBay Scraper API from Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("vonsensey/ebay-scraper-api").call(run_input={"mode": "sales","sellers": ["musicmagpie"],"salesKeyword": "vinyl","maxItems": 500,})for row in client.dataset(run["defaultDatasetId"]).iterate_items():if row["type"] == "sale":print(row["price"], row["currency"], row["itemTitle"])
How to call it from Node.js
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('vonsensey/ebay-scraper-api').call({mode: 'search',searchQueries: ['pokemon card psa 10'],gradeFilter: 'graded',maxItems: 500,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.table(items.filter((i) => i.type === 'listing'));
How to export eBay data to CSV, JSON or Excel
Every run's dataset exports as JSON, CSV, Excel, XML or JSONL from the Console, or from
the API with ?format=csv. The dataset ships with five saved views — All results,
Listings, Confirmed sales, Price summary and Run diagnostics — so a mixed
run opens as a clean table instead of a wall of nulls.
Why not eBay's own API?
Checked against eBay's own developer documentation in August 2026.
| Route | Status |
|---|---|
| Finding API | Decommissioned 4 February 2025. |
| Shopping API | Decommissioned 4 February 2025. |
| Browse API | Active listings only. No sold data. Needs an approved developer account. |
| Marketplace Insights API | The only official sold-price API. Limited Release — closed to new applicants, and capped at 90 days. |
| Terapeak | Free with a seller account, but aggregated only. It never shows you the individual transactions, and there is no API. |
No key, no application, no approval queue. Run it and get rows.
Reading the output
The dataset mixes row types; every row carries a type field.
type | Meaning | Charged |
|---|---|---|
listing | An active listing from a search or a seller's inventory | yes |
item | Full detail from an item page | yes |
sale | A confirmed order with the price paid | yes |
summary | Price distribution over one query | once per query |
error | An input that produced nothing, and why | free |
diagnostics | One per run: pages, blocks, and why it stopped | free |
Error rows carry a stable machine-readable reason, so you can branch on it:
INVALID_INPUT, INVALID_URL, NO_RESULTS, NO_SALES, ITEM_NOT_FOUND, ALL_FILTERED,
NOT_REACHED, FETCH_FAILED, SOLD_SEARCH_LOGIN_GATED, BLOCKED_CHALLENGE,
BLOCKED_REFUSED, BLOCKED_LOGIN_REQUIRED, RUN_FAILED.
Null means "eBay did not publish it here", never "we guessed". A price range gives you
price, priceMax and priceIsRange: true rather than a single made-up number. A card
listing with no grade gives you grade: null, not 0.
Legal and data use
Public, unauthenticated pages only. No logins, no accounts, and no personal data beyond the masked buyer handles eBay publishes publicly. You are responsible for how you use the data, including under GDPR and eBay's terms.
Unofficial. Not affiliated with, endorsed by, or sponsored by eBay Inc.
Support
Open an issue on the Actor's Issues tab. Include the run ID — the diagnostics row in that run's dataset already contains most of what is needed to answer you.
Run it without configuring anything — Scrape everything an eBay seller has listed, a ready-made example you can start as-is or copy.
Use cases
- Price something before you list it. Confirmed sale prices, not asking prices, are what tell you the number a buyer actually paid.
- Track a price over time. Run it on a schedule and the dataset becomes a price history you own.
- Watch a seller. Pull a competitor's whole live inventory and what has been selling out of it.
- Value graded cards. Comps split by PSA, BGS, CGC and raw, so a valuation has evidence behind it.
Run it on a schedule
A one-off pull answers a question; a schedule answers it every day without you. Open Schedules in the Apify Console, point a cron at this Actor, and the dataset keeps filling on its own — no server, no cron box, no babysitting. Everything here is built to be re-run: you are billed per result delivered, so a scheduled run that finds nothing new costs nothing.
FAQ
Can I get sold prices, not just active listings?
Yes. Confirmed sale prices with their dates come back alongside the live listings, in the same run.
Which eBay marketplaces are covered?
19 country marketplaces, chosen per run.
Can I see how many people are watching a listing?
Yes — watcher and sold counts are fields on the row, which is the closest public proxy for real demand.
Do failed or blocked lookups cost me anything?
No. Anything that could not be read comes back as a free diagnostic row rather than silently vanishing.
Something wrong, or a field you need that is missing? Open an issue on the Issues tab — it is read and it gets fixed. If this saved you time, a rating on the Store page helps the next person find it.