# eBay Sold Items Scraper (`apt_marble/ebay-sold-items-scraper`) Actor

Pull eBay's own record of completed and sold listings for any keyword or search link: the real sold date and sale price, plus condition, format, delivery cost and item location. Filter by price, condition, category and date, choose the eBay site, and get results in that site's own currency.

- **URL**: https://apify.com/apt\_marble/ebay-sold-items-scraper.md
- **Developed by:** [Hamza](https://apify.com/apt_marble) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.20 / 1,000 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## eBay Sold Items Scraper

Turn any list of keywords or eBay search links into a clean dataset of completed and sold listings — the sold date and the price each one actually changed hands for, straight from eBay's own public record of finished sales. It is built for anyone who prices against real transactions instead of asking prices: resellers valuing stock, sellers setting a competitive price, analysts building comparables, and brands watching what their products really sell for.

### What you can do with it

- **Value inventory against real sold prices** — see what identical items actually sold for, not just what sellers are asking today.
- **Track a market over time** by scheduling a run with a date cutoff, so each run picks up only the sales that closed since the last one.
- **Build price comparables** for a product from its recent completed sales, with the sold date, condition and buying format on every row.
- **Compare sold prices across conditions** — new, used and refurbished — with a single filter.
- **Research demand** by pulling the recent sold history behind a keyword or category and counting how many units moved.
- **Feed realized-price data** into your own pricing model, valuation tool or spreadsheet.

### What you get

One row per sold listing. Abridged sample:

```json
{
  "query": "iphone 15",
  "marketplace": "US",
  "itemId": "327313873278",
  "title": "Apple iPhone 15 128GB Unlocked - Very Good Condition",
  "soldDate": "2026-08-17",
  "soldPrice": { "amount": 512.0, "currency": "USD" },
  "bestOfferAccepted": false,
  "priceIsListingPrice": false,
  "condition": "Used",
  "buyingFormat": "BUY_IT_NOW",
  "shippingCost": 0,
  "location": "United States",
  "imageUrl": "https://i.ebayimg.com/images/g/1x8AAOSwabcDeFgh/s-l500.webp",
  "url": "https://www.ebay.com/itm/327313873278",
  "scrapedAt": "2026-08-18T12:00:00.000Z"
}
```

### Input reference

| Setting | Type | Default | What it does |
| --- | --- | --- | --- |
| Search queries | list of text | `iphone 15` | The keywords to look up in eBay's sold and completed listings. Each entry can also be a full eBay search link — its keyword, site, category, price band and condition are picked up automatically. **Required.** |
| Maximum sold records per query | whole number | `200` | Stop after this many sold records for each query. Results come back newest first, so a small limit returns the most recent sales. Maximum 10,000. |
| Only sales on or after (YYYY-MM-DD) | text | — | A date such as `2026-08-01`. Only sales on or after it are returned, and collection stops as soon as it reaches older sales — ideal for scheduled runs that pick up only what is new since the last one. Leave empty for no cutoff. |
| Item condition | choice | `Any condition` | Only return sales of items in this condition: any, new, used or refurbished. |
| Category | text | — | A numeric eBay category id (for example `9355` for cell phones) to scope every query to one category, applied together with the keyword. Leave empty for all categories. |
| Minimum sold price | whole number | — | Only return sales at or above this price, in the selected site's own currency. Leave empty for no minimum. |
| Maximum sold price | whole number | — | Only return sales at or below this price. Leave empty for no maximum. |
| eBay site | choice | `United States (ebay.com)` | Which country's eBay site to read. Sold history and prices differ between sites, and prices come back in that site's own currency. |
| Parallel queries | whole number | `4` | How many queries to work on at the same time. Higher is faster on runs with many queries. Maximum 10. |

### Output fields

| Field | Type | Description |
| --- | --- | --- |
| `query` | text | The keyword or link this row was found by, so results are easy to join back. |
| `marketplace` | text | The eBay site the row was read from. |
| `itemId` | text | eBay's listing identifier for the sold item. |
| `title` | text | Listing title as shown to shoppers. |
| `soldDate` | text | The date the sale completed, as `YYYY-MM-DD`. |
| `soldPrice` | object | The sale price and its currency: `{ amount, currency }`. |
| `bestOfferAccepted` | true/false | True when the sale closed as an accepted best offer. |
| `priceIsListingPrice` | true/false | True when the shown amount is the original listing price rather than the amount actually paid. This is only ever true on accepted best-offer sales, where eBay keeps the accepted amount private. |
| `condition` | text | Item condition, taken from eBay's own condition labels. |
| `buyingFormat` | text | How it was bought: `AUCTION`, `BUY_IT_NOW` or `BEST_OFFER`. |
| `shippingCost` | number | Delivery cost shown on the sold listing, when one is shown. |
| `location` | text | Where the item was located. |
| `imageUrl` | text | Thumbnail image link. |
| `url` | text | Clean listing link. |
| `scrapedAt` | text | When the row was collected. |

### Pricing

You pay per result, with no monthly minimum.

| What you are charged for | Price |
| --- | --- |
| Sold listing — one sold record added to your dataset | **$1.20 per 1,000** |

There is nothing else to pay. Every field above is included in that one charge.

**Worked example.** Five keywords, each collecting the 200 most recent sales, produce 1,000 rows: 1,000 × $0.0012 = **$1.20 per run**. Run daily for a month it is about $36. A one-off deep pull of 10,000 sold records costs $12. Queries that turn out to have no completed sales are reported in the run summary and are not charged.

### Limits & what this actor cannot do

- Sold results are eBay's own public record of completed and sold listings. eBay shows a rolling recent window of finished sales, not the entire lifetime history of a product, so this returns recent sales rather than every sale ever made.
- On an accepted best-offer sale, eBay publishes the original listing price with a line through it and keeps the amount actually paid private. Those rows are flagged with `bestOfferAccepted` and `priceIsListingPrice` set to true, and the price shown is the listing price — never the realized amount. Standard sales carry the true price paid.
- Seller details are not part of a sold record — eBay does not publish the seller on completed-listing results, so no seller information is returned.
- eBay's own headline result total for a search is a rounded estimate and is not shown on sold pages at all; the actor returns the individual sold records eBay actually serves rather than a summary count.
- A multi-quantity listing can sell more than once, and each completed sale is returned as its own row.
- Sold history and prices differ between eBay sites; results reflect the site you choose, in that site's own currency.
- A sold record describes a completed sale; the live market keeps moving, so a past sale price is history, not a quote for what the same item would fetch today.
- A query with no completed sales behind it returns no rows for that query — a real answer, reported in the run summary, not an error.
- Speed depends on the size of the job and on eBay's own response times; no fixed throughput is promised.
- eBay's terms govern automated access. You are responsible for using the data lawfully and in line with the source site's terms, and for handling any personal data in line with applicable privacy law.

### FAQ

**Do I need an eBay account?**
No. The actor reads only what eBay shows the public.

**Does it need my login or password?**
No. There is nothing to connect and nothing to configure — paste your keywords and press start.

**Are these the actual prices items sold for?**
For standard sales, yes — the realized sale price. For accepted best-offer sales eBay keeps the agreed amount private and shows the original listing price instead, so those rows are clearly flagged and their price is the listing price, not what the buyer paid.

**How far back does the sold history go?**
eBay publishes a rolling recent window of completed listings, so this returns recent sales, not a product's entire lifetime history. Use the date cutoff to keep scheduled runs to only what has sold since the last one.

**Can I schedule it?**
Yes. Schedule it hourly, daily or weekly from the Apify console, and pair it with the date cutoff so each run collects only new sales.

**Is the data complete?**
It is complete for the recent completed sales eBay publishes openly. Where eBay withholds something — the accepted amount on a best-offer sale, sales older than its public window — the actor says so instead of guessing.

# Actor input Schema

## `queries` (type: `array`):

Keywords to look up in eBay's sold and completed listings. Each entry can also be a full eBay search link — its keyword, site, category, price band and condition are picked up automatically. Every row says which query found it.

## `maxItemsPerQuery` (type: `integer`):

Stop after this many sold records for each query. Results come back newest first, so a small limit returns the most recent sales.

## `soldAfter` (type: `string`):

A date such as 2026-08-01. Only sales on or after this date are returned, and collection stops as soon as it reaches older sales — ideal for scheduled runs that only pick up what is new since the last one. Leave empty for no cutoff.

## `condition` (type: `string`):

Only return sales of items in this condition.

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

A numeric eBay category id (for example 9355 for cell phones) to scope every query to one category. Applied together with the keyword. Leave empty for all categories.

## `priceMin` (type: `integer`):

Only return sales at or above this price, in the selected eBay site's own currency. Leave empty for no minimum.

## `priceMax` (type: `integer`):

Only return sales at or below this price. Leave empty for no maximum.

## `marketplace` (type: `string`):

Which country's eBay site to read. Sold history and prices differ between sites, and prices come back in that site's own currency.

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

How many queries to work on at the same time. Higher is faster on runs with many queries. Leave at 4 unless you have a reason.

## Actor input object example

```json
{
  "queries": [
    "iphone 15"
  ],
  "maxItemsPerQuery": 200,
  "soldAfter": "",
  "condition": "any",
  "categoryId": "",
  "marketplace": "US",
  "maxConcurrency": 4
}
```

# Actor output Schema

## `results` (type: `string`):

Every sold record this run produced.

## `runSummary` (type: `string`):

What this run collected, and anything it could not read.

# 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 = {
    "queries": [
        "iphone 15"
    ],
    "maxItemsPerQuery": 200,
    "soldAfter": "",
    "condition": "any",
    "categoryId": "",
    "marketplace": "US",
    "maxConcurrency": 4
};

// Run the Actor and wait for it to finish
const run = await client.actor("apt_marble/ebay-sold-items-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 = {
    "queries": ["iphone 15"],
    "maxItemsPerQuery": 200,
    "soldAfter": "",
    "condition": "any",
    "categoryId": "",
    "marketplace": "US",
    "maxConcurrency": 4,
}

# Run the Actor and wait for it to finish
run = client.actor("apt_marble/ebay-sold-items-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 '{
  "queries": [
    "iphone 15"
  ],
  "maxItemsPerQuery": 200,
  "soldAfter": "",
  "condition": "any",
  "categoryId": "",
  "marketplace": "US",
  "maxConcurrency": 4
}' |
apify call apt_marble/ebay-sold-items-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,apt_marble/ebay-sold-items-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/Y0jQtMERoD2WfuEvR/builds/wGd7tcWF28hqp80O0/openapi.json
