# eBay Sold Listings Scraper with Validated Data (`whoareyouanas/ebay-sold-listings-scraper`) Actor

Collect eBay sold listings with displayed prices, sold dates, local filters, exact result caps, deduplication, and source provenance. Caffein fallback uses your Apify account and adds upstream fees. US tested; UK beta.

- **URL**: https://apify.com/whoareyouanas/ebay-sold-listings-scraper.md
- **Developed by:** [Anas Nadeem](https://apify.com/whoareyouanas) (community)
- **Categories:** E-commerce, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 validated sold listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## eBay Sold Listings Scraper with Validated Data

Collect eBay sold listings with displayed prices, sold dates, shipping, seller details and source provenance. Use the records for resale research, comparable listing analysis and pricing workflows. The Actor validates identities and dates, reapplies supported filters, removes duplicates and enforces your result limits.

**Source and cost disclosure:** hybrid mode tries native public retrieval, then calls [Caffein's eBay Sold Listings Actor](https://apify.com/caffein.dev/ebay-sold-listings) through your Apify account when needed. API mode calls that provider directly. Its fees are additional to this Actor's pricing and have a separate `upstreamBudgetUsd` limit. Native sold search currently encounters access blocks; successful tested results use the provider. These are provider-reported listing observations, not independently verified transactions.

### Start with a small search

Enter a keyword, select a marketplace and set your result limit. Run the Actor, then export its dataset as JSON, CSV, Excel or another format supported by Apify. You can also call the Actor through Apify's API or schedule repeat searches.

```json
{
  "keywords": ["nintendo switch oled"],
  "ebaySites": ["ebay.com"],
  "daysToScrape": 30,
  "maxResultsPerKeyword": 5,
  "maxResults": 5,
  "retrievalMode": "hybrid",
  "upstreamBudgetUsd": 0.05,
  "maxConcurrency": 1
}
```

`ebay.com` has passed small live retrieval checks. UK (`ebay.co.uk`) is beta. Result limits are maximums; source availability, filters and budgets can produce fewer rows. Defaults are 20 matches per keyword/site, 100 unique rows across the run, 30 calendar days and a $1 separate upstream event budget.

### What you get

| Field | Meaning |
| --- | --- |
| `itemId`, `url`, `title`, `marketplace` | Canonical listing identity and title |
| `displayedPrice`, `currency`, `priceKind` | Source-displayed amount as a decimal string and its interpretation |
| `soldDate`, `soldDatePrecision` | Displayed sold-date label; day precision is preserved |
| `shippingPrice`, `shippingType`, `displayedTotal` | Supplied shipping and item-plus-shipping total when the currency and amount are known |
| `condition`, `sellerUsername`, feedback fields | Source-supplied condition and seller details, when available |
| `sourceType`, `sourceProvider`, `sourceRunId`, `soldEvidence` | Where the observation came from and its sold assertion |
| `qualityFlags` | Unknown offers, fees, timezone or missing fields |

`actualSalePrice` is always `null`: a displayed amount does not reveal a hidden accepted offer or verify payment. `soldAt` stays `null` for day-level dates. Unknown shipping remains unknown; explicit free shipping is represented as zero. A total does not imply that taxes or buyer fees are included.

This preview is a subset of a real US output row:

```json
{
  "itemId": "820190412353",
  "url": "https://www.ebay.com/itm/820190412353",
  "title": "Nintendo Switch OLED 64 GB White + Case, Dock, Joycons, and Original Cables",
  "marketplace": "ebay.com",
  "displayedPrice": "170",
  "currency": "USD",
  "actualSalePrice": null,
  "bestOfferAccepted": null,
  "soldDate": "2026-10-01",
  "soldAt": null,
  "sourceType": "upstream_actor",
  "sourceProvider": "caffein.dev/ebay-sold-listings",
  "sourceRunId": "kqLvZHG0kqto6K0Ig"
}
```

### Pricing

This Actor charges **$2 per 1,000 unique eligible observations saved**, or $0.002 per observation. Overlapping query matches and summary records do not incur another listing event. The automatic startup event is $0.00005 per allocated GB, with a minimum of one event. This Actor's runtime platform usage is included in its event pricing; post-run storage access follows Apify's normal billing rules.

**Caffein charges separately for fetched rows and child-run startup.** Its published per-1,000 rates checked on October 2, 2026 were $4 for FREE, $3.50 for BRONZE, $3 for SILVER and $2.50 for GOLD and higher. Check its current Pricing tab before running. A one-to-one fallback on the FREE tier therefore costs about $6 per 1,000 rows across both Actors, plus startup events. Locally excluded or duplicate source rows can make the total higher.

There are two spending controls:

- **Max cost per run** in Apify limits this Actor's event charges.
- **`upstreamBudgetUsd`** limits aggregate requested Caffein event charges across child runs. It is separate from the parent limit and is conservatively reserved before a child starts.

Retrieval stops when the remaining parent budget cannot cover another listing. Provider requests are also bounded by remaining billable output capacity. A startup fee can apply to a failed or empty run. Listing events apply to eligible unique observations; interrupted writes or charges are reported as unresolved rather than blindly retried. The minimum selectable parent charge limit is $0.01; it is a cap setting, not a minimum invoice charge.

### Filters and retrieval modes

Use `daysToScrape` for 1–90 displayed calendar days, or supply inclusive `dateFrom` / `dateTo` bounds. Dates are compared against the UTC date at run start; no exact transaction timezone is inferred. Price, condition and buying-format filters are checked against the fields supplied by the source. Search matches can include accessories, bundles or parts.

The API fallback currently supports category `0` and item location `default`. Other category/location settings require verified native controls and stop before a paid fallback call. Provider price ranges are excluded by the temporary adapter. `includeBestOffers: false` excludes detected accepted offers but cannot identify undisclosed offers.

| Mode | Behavior |
| --- | --- |
| `hybrid` (default) | Attempt native public retrieval, then use the disclosed provider if access or source checks fail |
| `api` | Use Caffein directly, avoiding the native attempt |
| `native` | Use only native retrieval; sold searches currently encounter blocks |

API retrieval can run up to two searches together. Paid hybrid searches may run sequentially to avoid buying rows beyond the remaining output budget. Proxy settings apply only to the native attempt. Child runs and cached rows are reused after an interrupted retrieval; ambiguous paid starts stop further provider calls.

### Check coverage

The default dataset contains listing observations. Additional artifacts are available in the run's key-value store:

- `RUN_SUMMARY`: saved rows, confirmed charges, exclusions, coverage and run status.
- `QUERY_RESULTS`: per-query matches, overlapping results and stop reasons.
- `UPSTREAM_DIAGNOSTICS`: provider runs, requested/fetched/rejected rows and spending reservations.
- `COMPS_SUMMARY`: optional conservative cohorts. Statistics can be null when offer or fee context is unknown.

`complete` means the requested processing scope finished. It does not establish exhaustive eBay history. `partial` and `budget_limited` preserve usable rows and explain the stopping condition. `no_results` requires observed empty sold-search evidence; an empty or invalid provider response is a retrieval failure, not proof that nothing sold.

### FAQ

**Is this an official eBay API?** No. This is an Apify workflow with native retrieval and a disclosed external Actor dependency.

**Does validated mean the sale was independently verified?** It means the observation passed contract, identity, date and applicable filter checks. Payment, fulfillment and hidden offer values are not verified.

**Why use this alongside the provider?** It adds conservative normalization, global deduplication, output limits, local checks, durable recovery and explicit provenance around provider results. The provider remains separately maintained and separately billed.

**Can I scrape all completed listings?** This Actor returns supported sold observations. It does not claim to return every ended unsold listing or all transactions.

**How do I get support?** Open an issue on this Actor's Apify Store page with the run ID, relevant input and expected behavior. Avoid including API tokens or proxy credentials.

For developers: the full observation contract is in [specs/listing.schema.json](specs/listing.schema.json). Requires Node.js 22.18+; run `npm ci`, `npm run check` and `npm run validate:schemas` for local verification. Implementation evidence and remaining qualification limits are recorded in [IMPLEMENTATION\_STATUS.md](IMPLEMENTATION_STATUS.md).

# Actor input Schema

## `keywords` (type: `array`):

One to 100 searches. Shared filters apply to each keyword/site pair.

## `ebaySites` (type: `array`):

US (ebay.com) has passed live retrieval checks. UK (ebay.co.uk) is beta; results and GBP fields require successful source validation.

## `maxResultsPerKeyword` (type: `integer`):

Maximum matched unique items for each keyword/site query, including overlap already emitted elsewhere.

## `maxResults` (type: `integer`):

Exact global cap on unique marketplace/item observations. Summaries and repeated query matches do not count.

## `daysToScrape` (type: `integer`):

Displayed calendar-date window anchored to UTC date at run start; each explicit bound overrides its corresponding rolling bound.

## `dateFrom` (type: `string`):

Inclusive YYYY-MM-DD displayed calendar-date label within the supported public window. Not an exact UTC transaction boundary.

## `dateTo` (type: `string`):

Inclusive YYYY-MM-DD displayed calendar-date label; cannot exceed the UTC date at run start.

## `categoryId` (type: `string`):

Use 0 for the API fallback. Other categories require verified native controls and stop before a paid fallback call.

## `minPrice` (type: `number`):

eBay source price filter, in each marketplace display currency. Not a hidden accepted-offer amount.

## `maxPrice` (type: `number`):

Upper eBay displayed-price filter. Must be >= minPrice.

## `itemCondition` (type: `string`):

Initial broad eBay condition filter. Preserve observed condition labels and derived-ID provenance.

## `buyingFormat` (type: `string`):

Filter tested on the supported source: all, auction, or fixed-price listings.

## `itemLocation` (type: `string`):

Use default for the API fallback. Domestic/worldwide require verified native controls and stop before paid fallback retrieval.

## `includeBestOffers` (type: `boolean`):

Include explicitly detected Best Offer records with asking-price labels. False cannot exclude undisclosed offers.

## `includeRaw` (type: `boolean`):

Preserve short non-secret price/date/shipping/status strings for auditing. No full-page HTML in listing rows.

## `includeAnalytics` (type: `boolean`):

Included key-value-store summary of conservative currency-separated cohorts; never an extra billable row.

## `maxConcurrency` (type: `integer`):

At most two API searches run together. Paid hybrid searches may run sequentially to protect the remaining output budget.

## `proxyConfiguration` (type: `object`):

Apify proxy for the native attempt only. API mode does not use your proxy configuration. Hybrid can use its paid fallback if proxy setup fails.

## `dateWindowPolicy` (type: `string`):

Strict excludes undated/ambiguous-year rows. Include unknown emits them with DATE\_WINDOW\_UNVERIFIABLE and uncertain date matching.

## `retrievalMode` (type: `string`):

Hybrid tries native retrieval first, then caffein.dev/ebay-sold-listings. API calls that provider directly; native has no fallback and currently encounters access blocks. Caffein fees are separate and limited by upstreamBudgetUsd.

## `upstreamBudgetUsd` (type: `number`):

Separate aggregate event-charge limit for Caffein child runs, including startup and fetched rows later excluded or deduplicated. This does not replace the Actor’s own max cost per run. Uncertain starts stop additional paid calls.

## Actor input object example

```json
{
  "keywords": [
    "nintendo switch oled"
  ],
  "ebaySites": [
    "ebay.com"
  ],
  "maxResultsPerKeyword": 20,
  "maxResults": 100,
  "daysToScrape": 30,
  "categoryId": "0",
  "itemCondition": "any",
  "buyingFormat": "all",
  "itemLocation": "default",
  "includeBestOffers": true,
  "includeRaw": true,
  "includeAnalytics": true,
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "dateWindowPolicy": "strict",
  "retrievalMode": "hybrid",
  "upstreamBudgetUsd": 1
}
```

# Actor output Schema

## `listings` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `queryResults` (type: `string`):

No description

## `comps` (type: `string`):

No description

## `upstreamDiagnostics` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "nintendo switch oled"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("whoareyouanas/ebay-sold-listings-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "keywords": ["nintendo switch oled"] }

# Run the Actor and wait for it to finish
run = client.actor("whoareyouanas/ebay-sold-listings-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "nintendo switch oled"
  ]
}' |
apify call whoareyouanas/ebay-sold-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,whoareyouanas/ebay-sold-listings-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/zF9FOfO37UqidKbcU/builds/JJCZi9RWMGW7mRjXy/openapi.json
