# Mercari US Sold Listings Scraper (`devilscrapes/mercari-sold-listings`) Actor

Search Mercari US listings by keyword with a first-class sold/completed-listing filter — one row per item with price, condition, brand, category, seller, and photos. Built for reseller-arbitrage comps. No login; we handle the retries.

- **URL**: https://apify.com/devilscrapes/mercari-sold-listings.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

from $2.50 / 1,000 results

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

<div align="center">
  <img src=".actor/icon.svg" width="160" alt="Devil Scrapes mark" />

## Mercari US Sold Listings Scraper

**💰 $2.51 / 1 000 results**  ·  pay only for results  ·  no credit card to try

*We do the dirty work so your dataset stays clean.* 😈

Search Mercari US listings by keyword with a first-class sold/completed-listing filter — one row per item with price, condition, brand, category, seller, and photos. Built for reseller-arbitrage comps. No login; we handle the retries.

</div>

***

### 🎯 What this scrapes

Mercari US (`mercari.com`) doesn't publish a clean "sold comps" view — resellers digging for real recent sale prices are stuck scrolling active listings. This Actor reads Mercari's own server-rendered category pages (the same pages Google indexes, not a private reverse-engineered endpoint) with a first-class **sold / completed-listing filter** and an optional sold-within-days window, so arbitrageurs and flippers get exactly the comps they need without wading through active inventory.

Give it a `keyword` — optionally a `category`, a condition, a price band, and a "sold within the last N days" window — and it hands back one clean row per matching item: price, condition, brand, category, seller, photos, and (optionally) exact listing/sold dates and seller rating.

### 🔥 What we handle for you

- 🛡️ **Browser fingerprint rotation** — `curl-cffi` impersonates real Chrome / Firefox TLS handshakes so Mercari sees a browser, not Python.
- 🔁 **Retries with exponential backoff** on rate-limits and transient errors — up to 5 attempts, `Retry-After` honoured.
- 🧱 **Rate-limit-aware pacing** — when the target pushes back, we slow down instead of getting banned.
- 🌐 **Proxy on standby** — `proxyConfiguration` is available as an escape hatch, ready to flip on if Mercari tightens later, with no code changes on your end.
- 🧊 **Clean, typed dataset rows** — Pydantic-validated, ISO-8601 timestamps, stable item IDs, deduplicated even when a keyword fans out across departments.
- 💰 **Pay-Per-Event pricing** — you only pay for results that hit your dataset. No data, no charge (beyond the small `actor-start` warm-up fee).

### 💡 Use cases

- **Reseller-arbitrage comps** — check what an item actually sold for recently before buying stock to flip.
- **Liquidation / dropship pricing** — price a pallet or lot against real completed Mercari sales, not asking prices.
- **Demand tracking** — watch how fast a keyword's listings move from active to sold within a rolling window.
- **Sourcing research** — see which condition and price bands are actually selling versus sitting active.

### ⚙️ How to use it

1. Click **Try for free** at the top of the page.
2. Set `keyword` to whatever you're pricing (e.g. `"nintendo"`).
3. Optionally pick a `category` — leave it unset to fan out across all 17 departments (uses more requests per run).
4. Turn on `soldOnly` and set `soldWithinDays` for a recent-comps window.
5. Turn on `includeDetails` if you want listing/sold dates and seller rating per row (one extra request per item).
6. Click **Start**. Rows stream into the run's dataset as they're found.
7. Export from **Storage → Dataset** as JSON, CSV, or Excel — or fetch via the API.

### 📥 Input

| Field | Type | Required | Default | Notes |
|---|---|:--:|---|---|
| `keyword` | `string` | **yes** | — | Free-text search term, e.g. `"nintendo"`. |
| `category` | `string` | no | fans out over all 17 | One Mercari department — women, men, kids, home, vintage\_collectibles, beauty, electronics, sports\_outdoors, handmade, other, arts\_crafts, books, pet\_supplies, toys\_collectibles, garden\_outdoor, office, tools. |
| `conditionIds` | `array` | no | — | 1=New … 5=Poor. Applied client-side after fetch. |
| `priceMin` / `priceMax` | `number` | no | — | USD. Applied client-side after fetch. |
| `soldOnly` | `boolean` | no | `false` | Only trading/sold\_out listings — Mercari's own "Sold" facet. |
| `soldWithinDays` | `integer` | no | — | Only items sold in the last N days (1-365). Requires `soldOnly`. |
| `includeDetails` | `boolean` | no | `false` | Fetch each item's detail page for listing/sold dates + seller rating. |
| `maxResults` | `integer` | no | `100` | Cap on total emitted rows per run, 1-2000. |
| `proxyConfiguration` | `object` | no | `{"useApifyProxy": false}` | Not required for this target; kept as a forward-looking escape hatch. |

#### Example input

```json
{
  "keyword": "nintendo",
  "category": "men",
  "soldOnly": true,
  "soldWithinDays": 7,
  "includeDetails": true,
  "maxResults": 5,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

### 📤 Output

One dataset row per matched item:

| Field | Type | Notes |
|---|---|---|
| `item_id` | `string` | Mercari's own item ID, e.g. `m96557170766`. |
| `title` | `string` | Listing title. |
| `price` / `original_price` | `number \| null` | Current / original asking price, USD. |
| `currency` | `string` | Always `"USD"`. |
| `status` | `string` | `on_sale`, `trading`, `sold_out`, `stop`, or `cancel`. |
| `sold` | `boolean` | Derived: `status` is `trading` or `sold_out`. |
| `condition` / `brand` | `string \| null` | Item condition and brand tag. |
| `category` / `category_id` | `string` / `integer` | The item's own (usually leaf-level) category — not an echo of the requested department. |
| `seller_id` | `integer` | Seller's numeric Mercari ID. |
| `seller_username`, `seller_rating_avg`, `seller_rating_count` | mixed, nullable | Enrichment only (`includeDetails: true`). |
| `item_url` | `string` | Canonical `mercari.com/us/item/{id}/` URL. |
| `thumbnail_url` / `photo_urls` | `string \| null` / `array` | First photo, and the full photo list. |
| `shipping_payer` | `string \| null` | Who pays shipping. |
| `listing_date` / `sold_date` | `string \| null` | Enrichment only. `sold_date` is a last-status-change proxy, not a guaranteed sale instant. |
| `scraped_at` | `string` | ISO-8601 UTC timestamp for this row. |

#### Example output

```json
{
  "item_id": "m96557170766",
  "title": "Mario Hanafuda card T-shirt (Size XXL) - Nintendo Japan exclusive (NEW)",
  "price": 59.0,
  "original_price": 58.0,
  "currency": "USD",
  "status": "trading",
  "sold": true,
  "condition": "New",
  "brand": "Nintendo",
  "category": "T-Shirts for Men",
  "category_id": 303,
  "seller_id": 348351597,
  "item_url": "https://www.mercari.com/us/item/m96557170766/",
  "thumbnail_url": "https://u-mercari-images.mercdn.net/photos/m96557170766_1.jpg?1773934282&width=200&height=200",
  "listing_date": null,
  "sold_date": null,
  "scraped_at": "2026-07-21T06:40:00.000Z"
}
```

### 💰 Pricing

Pay-Per-Event — you pay only when these events fire:

| Event | USD | What it is |
|---|---:|---|
| `actor-start` | $0.01 | One-off warm-up charge per run |
| `item-result` | $0.0025 | Per listing row written to the dataset |
| `item-detail-enrichment` | $0.0015 | Per row, only when `includeDetails` is on |

Example: 1 000 results ≈ **$2.51** base, ≈ **$4.01** with detail enrichment on. No subscription, no minimum, no card to start — Apify gives every new account $5 of free credit.

### 🚧 Limitations

`sold_date` is a last-status-change proxy (the item detail page's own "updated" timestamp) — not a guaranteed exact sale instant. Mercari retires sold-item history after roughly a year; older sold items return a purge signal and are skipped, not faked. `conditionIds` / `priceMin` / `priceMax` are applied client-side after fetch, not as a confirmed server-side filter — a narrow filter combined with a broad keyword and no `category` can cost extra pagination. Custom sort order isn't supported; results follow Mercari's own default relevance ranking. Mercari Japan (`jp.mercari.com`) is a different site and out of scope.

### ❓ FAQ

**What counts as "sold" here?**

Mercari's own UI groups `itemStatuses` 2 (trading / in escrow) and 3 (sold\_out) under one "Sold" facet — `soldOnly=true` matches that same definition, not just fully closed-out listings.

**Is `sold_date` the exact moment of sale?**

It's a proxy — the item detail page's own last-updated timestamp, which moves when status flips to sold/trading. Close, not certified exact-to-the-second.

**Do I need a proxy?**

No — Mercari's category pages are keyless and server-rendered, so `proxyConfiguration` defaults off. It stays present as a forward-looking escape hatch.

**What happens with old, purged sold items?**

Mercari retires sold-item history after roughly a year; those return a purge signal and are skipped, not silently faked.

### 💬 Your feedback

Spotted a bug, a field that doesn't match reality, or a Mercari category we're missing? Open an issue on the Actor's **Issues** tab on Apify Console — the devil's in the data, and we'd rather fix it than let it slide.

***

<div align="center">

Built by **[Devil Scrapes](https://apify.com/DevilScrapes)** 😈 — a small fleet of
opinionated public-data Actors. Honest pricing, real engineering, zero fine print.

</div>

# Actor input Schema

## `keyword` (type: `string`):

Free-text search term, e.g. "nintendo".

## `category` (type: `string`):

Restrict the search to one Mercari department. Leave unset to fan out across all 17 departments (uses more requests per run).

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

Client-side filter on item condition: 1=New, 2=Like new, 3=Good, 4=Fair, 5=Poor. Leave empty for any condition.

## `priceMin` (type: `number`):

Client-side filter — drop rows priced below this, in USD.

## `priceMax` (type: `number`):

Client-side filter — drop rows priced above this, in USD.

## `soldOnly` (type: `boolean`):

When on, only trading/sold\_out listings are returned — Mercari's own "Sold" facet.

## `soldWithinDays` (type: `integer`):

Only include items sold in the last N days (1-365). Requires "Sold listings only".

## `includeDetails` (type: `boolean`):

Fetch each item's detail page for listing date, sold date, and seller username/rating. One extra request per row.

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

Cap on total emitted rows per run.

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

Not required for this target — Mercari's category pages are keyless and server-rendered. Present as a forward-looking escape hatch.

## Actor input object example

```json
{
  "keyword": "nintendo",
  "category": "men",
  "soldOnly": true,
  "soldWithinDays": 7,
  "includeDetails": false,
  "maxResults": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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 = {
    "keyword": "nintendo",
    "category": "men",
    "soldOnly": true,
    "soldWithinDays": 7,
    "maxResults": 100,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("devilscrapes/mercari-sold-listings").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 = {
    "keyword": "nintendo",
    "category": "men",
    "soldOnly": True,
    "soldWithinDays": 7,
    "maxResults": 100,
    "proxyConfiguration": { "useApifyProxy": False },
}

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

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

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

```

## CLI example

```bash
echo '{
  "keyword": "nintendo",
  "category": "men",
  "soldOnly": true,
  "soldWithinDays": 7,
  "maxResults": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call devilscrapes/mercari-sold-listings --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=devilscrapes/mercari-sold-listings",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/wwPSLsMryAbw60j3N/builds/wmIrryY1FVEmzw42m/openapi.json
