# eBay Product & Listings Scraper (`devilscrapes/ebay-product-listings-scraper`) Actor

Search eBay's live active listings by keyword. Get title, price, condition, buying format, item URL, and thumbnail per card. Filter by category, condition, price range, and buying format. We handle the warm-up cookies and retries so you get clean rows every run.

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

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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

<img src=".actor/icon.svg" width="160" alt="eBay Product & Listings Scraper" />

## eBay Product & Listings Scraper

*The devil's in the data.* 😈

**$1.25 / 1,000 results** — pay only for results that land, no credit card to try.

Search eBay's live "for sale" listings by keyword and get back structured rows: title, price, condition, buying format, item URL, and thumbnail — ready for reseller pricing tools, price-intelligence pipelines, and market research. eBay's search page fights back with a first-request block; we handle the warm-up cookies, the retries, and the fingerprint rotation so your dataset stays clean.

### 🎯 What this scrapes

One row per active eBay listing card matching your search. Sponsored placeholder cards ("Shop on eBay") and malformed cards are filtered out automatically — you only get real listings.

| Field | Type | Description |
|---|---|---|
| `item_id` | string | eBay item ID, parsed from the item link |
| `title` | string | Listing title, accessibility suffix stripped |
| `price` | number | null | Listing price in USD; `null` on an unresolvable range/text price |
| `currency` | string | Fixed `"USD"` for v1 (`ebay.com` only) |
| `condition` | string | null | Item condition (e.g. `"Pre-Owned"`, `"Open Box"`) |
| `buying_format` | string | null | One of `"auction"`, `"fixed_price"`, `"best_offer"`, `"unknown"` |
| `bids_count` | integer | null | Bid count, auction listings only |
| `item_url` | string | Canonical `https://www.ebay.com/itm/<item_id>` link |
| `image_url` | string | null | Thumbnail image URL |
| `query` | string | Echo of your search query |
| `scraped_at` | string | ISO 8601 UTC timestamp |

### 🔥 Features

- **Keyword search, no login required** — search eBay's live listings the same way a shopper does, no account or API key needed on your end.
- **Filter by category, condition, price range, and buying format** — narrow results before you pay for a single row.
- **Sponsored and malformed cards filtered automatically** — placeholder "Shop on eBay" cards and broken cards never reach your dataset.
- **We rotate browser fingerprints** — `curl-cffi` with Chrome/Firefox/Safari TLS impersonation, so eBay's servers see real-browser traffic, not raw Python.
- **We handle the warm-up dance** — eBay's search endpoint 403s a cold request; we collect the bot-manager cookie first, then reuse that session for every search page.
- **We retry with exponential backoff** — `408 / 429 / 5xx` trigger a retry sequence (2s → 30s cap, up to 5 attempts), honouring `Retry-After`.
- **We rotate proxies and sessions on every block** — a fresh `session_id` and a fresh impersonation profile on every 403, through Apify Proxy.
- **Clean, Pydantic-validated rows** — every dataset row passes schema validation before it lands. ISO 8601 timestamps, stable column names.
- **Pay only for results that land** — no data, no charge beyond the small `actor-start` warm-up fee.

### 💡 Use cases

- **Reseller price-checking** — pull live asking prices for a product line before you list or restock, filtered by condition and price band.
- **Price-intelligence pipelines** — feed `price` / `condition` / `buying_format` into a downstream pricing model, refreshed on a schedule.
- **Market research** — sweep a category for buying-format mix (auction vs. fixed-price vs. best-offer) and price distribution.
- **Arbitrage scouting** — compare `price` across `min_price`/`max_price` bands to spot underpriced listings worth flipping.
- **Competitive monitoring** — track how many active listings and what price range a competitor's product category holds right now.

### ⚙️ How to use it

1. Open the Actor input form in Apify Console.
2. Enter your `query` (required) — the same keywords you'd type into eBay's search box.
3. Optionally narrow with `categoryId`, `conditionIds`, `minPrice`/`maxPrice`, or `buyingFormat`.
4. Set `maxResults` to cap how many rows to collect (default 100, up to 1000).
5. Leave `proxyConfiguration` on Apify Proxy (default) for stable, unblocked runs.
6. Click **Start**. Results stream into the default dataset as JSON, CSV, Excel, or XML.

#### Basic keyword search

```json
{
  "query": "iphone 13",
  "maxResults": 100
}
```

#### Filtered search — condition, price band, buying format

```json
{
  "query": "fender stratocaster",
  "maxResults": 50,
  "conditionIds": ["3000"],
  "minPrice": 200,
  "maxPrice": 1200,
  "buyingFormat": "fixed_price"
}
```

### 📥 Input

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `query` | string | yes | — | Search keywords, 1-200 characters |
| `maxResults` | integer | no | `100` | Cap on rows collected, 1-1000 |
| `categoryId` | string | no | — | eBay numeric category ID |
| `conditionIds` | string\[] | no | — | eBay numeric condition IDs |
| `minPrice` | number | no | — | Lowest price to include, USD |
| `maxPrice` | number | no | — | Highest price to include, USD (must be >= `minPrice`) |
| `buyingFormat` | string | no | `"any"` | One of `"any"`, `"fixed_price"`, `"auction"`, `"best_offer"` |
| `proxyConfiguration` | object | no | `{"useApifyProxy": true}` | Apify Proxy configuration |

### 📤 Output

One row per real (non-sponsored) listing card, up to `maxResults`. Export to JSON, CSV, Excel, or XML from the Apify Console.

Example row:

```json
{
  "item_id": "196123456789",
  "title": "Apple iPhone 13 Pro Max 256GB Unlocked",
  "price": 270.74,
  "currency": "USD",
  "condition": "Pre-Owned",
  "buying_format": "best_offer",
  "bids_count": null,
  "item_url": "https://www.ebay.com/itm/196123456789",
  "image_url": "https://i.ebayimg.com/images/g/abc123/s-l500.jpg",
  "query": "iphone 13 pro max",
  "scraped_at": "2026-08-13T12:00:00+00:00"
}
```

### 💰 Pricing

This Actor is priced **per-event** — you pay only for results that land in your dataset.

| Event | Price (USD) | When charged |
|---|---|---|
| `actor-start` | $0.05 | Once at the start of each run |
| `result-row` | $0.0012 | Per listing row written to the dataset |

A 100-row run costs **$0.17 total**. A full 1,000-row run costs **$1.25** — inside the $1.00-1.50/1,000 band the current eBay-scraper category charges, with a cleaner, actively-maintained dataset behind it.

### 🚧 Limitations

- **Active listings only** — this Actor covers eBay's live "for sale" search. Sold/completed listings are a separate product.
- **`ebay.com` (US) only, v1** — other eBay marketplaces and non-USD currencies are out of scope for this version.
- **Card-level data only** — description, seller feedback score, shipping cost, item specifics, and return policy require a detail-page fetch and aren't included.
- **No seller identity** — seller username, store name, and feedback score aren't exposed on the search-result card.
- **Point-in-time runs** — this Actor doesn't monitor for new listings continuously; schedule repeat runs via Apify's Scheduler if you need that.
- **Unresolvable prices ship as `null`** — a range or starting-bid price that can't resolve to one number ships `price: null` rather than a guessed value.

### ❓ FAQ

**Q: Do I need an eBay account or API key?**
No. This Actor searches eBay's public listings the same way a shopper does — no login, no eBay Developer API key required.

**Q: Can I filter by condition and price at the same time?**
Yes — `conditionIds`, `minPrice`, `maxPrice`, and `buyingFormat` all combine in a single search.

**Q: What happens if eBay blocks the request?**
We rotate the session and browser fingerprint and retry the warm-up-then-search flow automatically. If a run ends with zero results, you'll see a clear status message explaining why (no matches vs. block-exhausted) rather than a silent empty dataset.

**Q: Does this cover sold or completed listings?**
No — this Actor covers active, currently-listed items only. Sold/completed listing data is a separate Devil Scrapes Actor.

**Q: Can I get more than 1,000 results per run?**
Not in a single run — `maxResults` caps at 1000. Narrow your `query` or split by `categoryId`/price band and run multiple queries for larger coverage.

### 💬 Your feedback

This Actor is built and maintained by [Devil Scrapes](https://apify.com/DevilScrapes). If a search returns fewer rows than expected, or you notice eBay's markup has shifted, [open an issue on the Actor page](https://apify.com/DevilScrapes/ebay-product-listings-scraper/issues) and we'll patch it within a release cycle. The target blocks; we get back up.

# Actor input Schema

## `query` (type: `string`):

Search keywords, passed to eBay's search box (e.g. <code>iphone 13</code>, <code>fender stratocaster</code>). 1-200 characters.

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

Cap on how many result rows to collect across pages. Range 1-1000.

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

eBay numeric category ID to narrow the search (e.g. <code>9355</code> for cell phones). Leave blank to search all categories.

## `conditionIds` (type: `array`):

eBay numeric item-condition IDs to filter by (e.g. <code>1000</code> for New, <code>3000</code> for Used). Leave blank for all conditions.

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

Lowest price to include, in USD. Leave blank for no lower bound.

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

Highest price to include, in USD. Must be >= Minimum price when both are set. Leave blank for no upper bound.

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

Restrict results to a specific buying format.

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

Apify Proxy spec. No group is forced here -- eBay's warm-up-then-search flow works on datacenter IPs; a cloud run can still opt into a residential group at call time.

## Actor input object example

```json
{
  "query": "iphone 13",
  "maxResults": 100,
  "categoryId": "9355",
  "conditionIds": [
    "1000",
    "3000"
  ],
  "buyingFormat": "any",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

All dataset items as JSON.

## `datasetItemsCsv` (type: `string`):

Same data exported to CSV.

## `datasetView` (type: `string`):

Open the run dataset in the Console.

# 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 = {
    "query": "iphone 13",
    "maxResults": 100,
    "buyingFormat": "any",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("devilscrapes/ebay-product-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 = {
    "query": "iphone 13",
    "maxResults": 100,
    "buyingFormat": "any",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("devilscrapes/ebay-product-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 '{
  "query": "iphone 13",
  "maxResults": 100,
  "buyingFormat": "any",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call devilscrapes/ebay-product-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,devilscrapes/ebay-product-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/Wtg6vkMzv7gD1oWK1/builds/PxTQUadswx04Nl8OZ/openapi.json
