# Mercari Japan Scraper: New Listings & Sold Prices (`accountable_eel/mercari-jp-listing-lookup`) Actor

Mercari Japan (jp.mercari.com) scraper by keyword or search URL: one row per listing with JPY price, condition, brand, status and seller type, plus a sold-items mode for price comps and optional new-listing and price-drop alerts. No login. Pay per listing.

- **URL**: https://apify.com/accountable\_eel/mercari-jp-listing-lookup.md
- **Developed by:** [Adrian Voss](https://apify.com/accountable_eel) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 listing returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Mercari Japan Scraper: New Listings & Sold Prices

Watch a search, get only what's new. This actor runs your search on **Mercari Japan**
(jp.mercari.com), Japan's biggest flea-market app, and returns one clean row per listing: title,
JPY price, condition, brand, status, seller type and a permanent link. Switch to **sold** mode and
the same search becomes a price-comps feed: what things actually sold for, most recently sold
first. Turn on monitoring and it becomes a watchlist: new listings, new sales and price drops since
your last run, charged per new row, free on quiet days.

### Who it's for

Resellers and importers who price by what sold last week, not by asking prices. Proxy-buying and
export shops sourcing trading cards, games, cameras and fashion from Japan. Market researchers who
need a bulk export of a Mercari search in a spreadsheet, and n8n, Make or Sheets workflows that act
the moment a new listing appears. Paste a list of searches (Japanese or English keywords, or a
search URL copied from your browser), get back a flat row per listing, and pay only for listings
returned. A search that finds nothing costs nothing.

Mercari already sends its own app alerts to individual buyers. This actor is for the jobs the app
doesn't do: sold-price comps in bulk, a structured export, and monitoring many searches at once on
your own schedule.

### Why this one

- **Sold price comps built in.** Set "Listing type" to Sold and you get items that already sold
  (or are mid-transaction), most recently sold first, with the price they went for. Combine with
  monitoring for a running log of every new sale in a search.
- **Monitoring first, not a one-off dump.** It remembers every item ID it has shown you and only
  bills what's new or cheaper since the last run. A quiet run costs only the run fee.
- **Mercari's own filters, not an approximation.** Condition, category, brand and price are sent
  to Mercari's search as Mercari's own filters, so a price cap is applied before you pay, not after.
- **Readable condition labels.** Mercari's six condition grades come back as an ID plus an English
  and a Japanese label (新品、未使用 through 全体的に状態が悪い), taken from Mercari's own filter UI.
- **Private or business seller.** Mercari Shops listings (business sellers) are flagged
  `sellerType: business` and link to their Shops page; ordinary C2C listings are `private`.
- **Never charged for a miss or a quiet monitoring run.**

### What you get

One row per listing by default (turn off "Expand rows" in Advanced for one row per search, with the
listings nested under `listings`).

| Field | Type | Description |
|---|---|---|
| `query` | text | The search you submitted, echoed back |
| `found` | boolean | `true` if Mercari returned a search response |
| `status` | text | `OK`, or `NOT_FOUND` / `BLOCKED` / `BAD_FORMAT` on a miss |
| `searchQuery` | text | The keyword actually searched (read from a pasted URL if you gave one) |
| `listingType` | text | `active`, `sold` or `all` for this search |
| `listingCount` | number | Listings returned and billed for this search |
| `totalAvailable` | number | Matches Mercari reports (Mercari caps this figure at 15,000) |
| `truncated` | boolean | `true` if more results existed than were returned |
| `newCount` / `priceDropCount` | number | New listings and price drops this run (monitoring only) |
| `listingId` | text | Mercari item ID (`m...` for C2C, a longer ID for Mercari Shops) |
| `url` | link | `jp.mercari.com/item/<id>`, or `jp.mercari.com/shops/product/<id>` for Mercari Shops |
| `title` | text | Listing title |
| `price` | number | Price in JPY (for an auction listing, the current highest bid) |
| `currency` | text | Always `JPY` |
| `listingStatus` | text | `on_sale`, `trading` (bought, transaction in progress) or `sold_out` |
| `conditionId` | number | Mercari condition grade, 1 (new) to 6 (poor overall) |
| `conditionName` / `conditionNameJa` | text | The grade in English and in Mercari's Japanese wording |
| `category` | text | Mercari category ID |
| `brand` | text | Brand, when the seller tagged one |
| `sellerType` | text | `business` for Mercari Shops, otherwise `private` |
| `shippingPaidBy` | text | `seller` (送料込み) or `buyer` (着払い); empty for Mercari Shops |
| `isAuction` / `auctionEndsAt` | boolean / date | Mercari's auction-format listings and their bid deadline |
| `postedAt` | date | When the listing was created |
| `updatedAt` | date | Last status or price change; for sold items, roughly when it sold |
| `imageUrl` | link | First listing photo |
| `sellerHash` | text | Anonymous, stable hash of the seller ID |
| `sellerId` | text | **Only with "Include raw seller ID" on** |
| `isNew`, `changeType`, `previousPrice`, `priceDropPct`, `firstSeenAt` | mixed | Monitoring fields |
| `scrapedAt` | date | When this row was fetched |

### Pricing

Pay-per-event. A flat per-run fee covers session/proxy warmup; you're billed
per item only when data is actually found and returned — see
`.actor/pay_per_event.json` for exact prices. A miss is never charged.

### Monitoring / only new results

Turn on **"Only return results that are new or dropped in price since the last run"** and a search
line becomes a watchlist:

- A listing is **new** the first time this watchlist sees its Mercari item ID. In Sold mode that
  means **newly sold** since the last run.
- A **price drop** fires when a fixed-price, on-sale listing's price falls by at least "Minimum
  price drop" (5% by default). Auction bids and sold items never fire one.
- Already-seen, unchanged listings are dropped before billing. A quiet run returns one free row.
- The first run has nothing to compare against, so it returns everything as new. Turn on **"Skip
  alerts on the first run"** to bank the first run silently and start alerting from run two.

**Schedule recipe.** Save the actor as an Apify **Task** with `deltaMode: true` and your own
`deltaName`, add an hourly or daily **Schedule**, and point the task's **webhook** at Slack,
Discord, Google Sheets or an n8n / Make webhook.

**Limitation.** Each run reads up to 1,000 listings per search (newest first, 120 per page). A
very busy keyword can post more than that between two runs, and a price drop is only seen on a
listing that is still inside that window. Narrow busy searches with a category, brand or price cap,
or schedule them more often.

### How to use

1. **In the Apify Console.** Open the actor page and click **Start** — the `searches` field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
2. **Via the API.** Call it directly with a POST request — no Console needed once you have an API token:
   ```bash
   curl "https://api.apify.com/v2/acts/accountable_eel~mercari-jp-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"searches":["ポケモンカード"]}'
   ```
3. **On a schedule.** Save this actor as an Apify **Task** with the input you want, then add a **Schedule** (hourly, daily, weekly) so it runs on its own — no server of your own required.

4) For sold comps, set "Listing type" to **Sold**. For monitoring, turn on the Monitoring section.

### Input

```json
{
  "searches": [
    "ポケモンカード"
  ]
}
```

One search per line: keywords like "ポケモンカード" or "nintendo switch", or paste a jp.mercari.com search URL (its own filters for status, sort, condition, category, brand and price are kept). Accepted formats: ポケモンカード, nintendo switch, https://jp.mercari.com/search?keyword=iphone\&status=sold\_out%7Ctrading.

Pasted search URLs keep their own filters: `status=on_sale` or `status=sold_out|trading`,
`sort`/`order`, `item_condition_id`, `category_id`, `brand_id`, `price_min` and `price_max`
override the matching inputs for that one search.

### Sample output

| query | found | status | searchQuery | listingType | listingCount | totalAvailable | truncated | newCount | priceDropCount | listings | listingId | url | title | price | currency | listingStatus | conditionId | conditionName | conditionNameJa | category | brand | sellerType | shippingPaidBy | isAuction | auctionEndsAt | postedAt | updatedAt | imageUrl | sellerHash | sellerId | isNew | changeType | previousPrice | priceDropPct | firstSeenAt | scrapedAt |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| ポケモンカード | true | OK | <search> | \<listing type (active / sold / all)> | <listings returned> | \<total matching on mercari (capped at 15,000)> | <more results were available> | <new listings this run> | <price drops this run> | \<all listings found (full list)> | <mercari item id> | <listing link> | <title> | \<price (jpy)> | <currency> | \<status (on\_sale / trading / sold\_out)> | \<condition id (1 best to 6 worst)> | <condition> | \<condition (japanese)> | <category id> | <brand> | \<seller type (private / mercari shops business)> | <shipping paid by> | <auction listing> | <auction ends> | <listed at> | \<last updated (sold time for sold items)> | <image> | \<seller (anonymous hash)> | \<seller id (only with seller info on)> | \<is this listing new?> | <change type> | \<previous price (jpy)> | \<price drop %> | <first seen on a run> | 1970-01-01T00:00:00.000Z |

A search that finds nothing comes back as a row with `"found": false` and is never charged.

### Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

```bash
curl "https://api.apify.com/v2/acts/accountable_eel~mercari-jp-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"searches":["ポケモンカード"]}'
```

**n8n.** Add an HTTP Request node: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~mercari-jp-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body Content Type `JSON`, JSON Body `{"searches":["ポケモンカード"]}` (swap in an expression from an earlier node for a real value).

**Clay.** Add an "HTTP API" column: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~mercari-jp-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body `{"searches":["{{search}}"]}`, mapping the row's search into the `searches` array.

**MCP.** In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Mercari Japan Scraper: Sold Prices & New Listing Alerts" — the agent will find and run this actor.

### Tips

- Price a card, lens or console by running the same keyword in **Sold** mode with a condition
  floor ("Like new or better"). The median of `price` over the last few dozen rows is a fair comp.
- `totalAvailable` reads 15,000 on any broad keyword: that is Mercari's own display cap, not a
  real count. Narrow the search if you need everything.
- Category and brand IDs are the numbers after `category_id=` and `brand_id=` in a jp.mercari.com
  search URL. Easiest path: set the filters on the site, then paste the URL as your search.
- A `BLOCKED` status means Mercari returned 401, 403, 429 or 503. Lower "Max concurrency" or retry
  later. No proxy is needed by default.

### vs. other Mercari scrapers

The busiest Mercari Japan actor on the Apify Store (fatihtahta's) has about 30 monthly users and is
a one-off search export. Japan Alerts is a paid external alert service across several Japanese
platforms, and Mercari's own app alerts cover one buyer's saved searches.

| | What it costs | What you get | Trade-off |
|---|---|---|---|
| **This actor** | $2 per 1,000 listings; nothing for a miss or a quiet run | Sold comps mode, monitoring (new, newly sold, price drop), condition labels, seller type, up to 1,000 listings per search | No listing descriptions or seller location (Mercari's search doesn't return them) |
| Mercari app alerts | Free | Push alerts for your own saved searches | No export, no sold history in bulk, no automation |
| Paid alert services | Monthly subscription | Alerts across several platforms | Not your data pipeline |

### Data & privacy

This actor reads public search results that anyone can see without logging in. It doesn't log in,
solve CAPTCHAs or reveal hidden contact details. Seller identity is off by default: you get a
private/business flag and an anonymous seller hash so you can group listings by seller without
names. Turning on seller info makes you responsible for having a lawful reason to process it. Not
affiliated with Mercari.

Seller phone numbers and emails are never collected.

### FAQ

**Is this allowed?**
It collects the same public listing data your browser shows, for the searches you choose. It's
built for monitoring a search, not for copying the marketplace. Check that your use fits Mercari's
terms and your local law.

**Does it need a Mercari account or login?**
No. Mercari's web client signs each search request with a key pair it generates itself (a "DPoP"
proof). This actor does the same with a fresh key pair per run. No account, login or token is
involved. If Mercari ever requires a login for search, the actor reports it instead of working
around it.

**What does `trading` mean in Sold mode?**
The item was bought and the transaction is still in progress. Mercari's own "sold" filter includes
these, so this actor does too; filter them out on `listingStatus` if you only want completed sales.

**Why is `shippingPaidBy` empty on some rows?**
Mercari Shops listings don't report who pays shipping in search results.

**Am I charged for a quiet monitoring run?**
No. When nothing is new you get one row with `listingCount: 0` and no listing charge.

**Can an AI agent call this directly?**
Yes. It's available through the Apify MCP server and the REST endpoint above.

# Actor input Schema

## `searches` (type: `array`):

One search per line: keywords like "ポケモンカード" or "nintendo switch", or paste a jp.mercari.com search URL (its own filters for status, sort, condition, category, brand and price are kept). Accepted formats: ポケモンカード, nintendo switch, https://jp.mercari.com/search?keyword=iphone\&status=sold\_out%7Ctrading. You're only charged for the ones we actually find — a miss costs nothing.

## `testRun` (type: `boolean`):

Turn this on to test your input on a small sample before running the full list. Turn it off to process everything.

## `onlyFound` (type: `boolean`):

Only keep rows where something was actually found. Misses are always free, whether or not you show them here.

## `includeKeywords` (type: `array`):

Optional. Only keep results that mention at least one of these words (e.g. a job title, a city, a product name). Leave empty to keep everything.

## `excludeKeywords` (type: `array`):

Optional. Drop any result that mentions one of these words. Leave empty to skip nothing.

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

Optional. Stop the run once this many results have been found — useful for a quick, cheap sample. Leave blank for no limit.

## `maxListingsPerSearch` (type: `integer`):

Mercari returns 120 listings per request; this actor pages automatically above that, up to 1000 per search. You pay per listing returned, so this is also your budget control.

## `listingType` (type: `string`):

On sale now: listings you can still buy. Sold: items that already sold (or are mid-transaction), most recently sold first, with the price they sold at: the comps feed for resellers. Both: no status filter.

## `sort` (type: `string`):

Mercari's own sort orders. Keep "Newest first" for monitoring. Sold searches are re-sorted by sold time after fetching.

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

Uses Mercari's own six condition grades. Picking one returns that grade and every better one.

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

Optional. One or more Mercari category IDs, comma-separated (the number after category\_id= in a jp.mercari.com search URL, e.g. 1289 for Pokémon cards). Leave empty for all categories.

## `brand` (type: `string`):

Optional. A Mercari brand ID (the number after brand\_id= in a search URL) is sent to Mercari as a filter. A brand name (e.g. "Canon") instead keeps only listings whose brand contains it.

## `minPrice` (type: `integer`):

Optional. Sent to Mercari as its own price filter. Leave empty for no minimum.

## `maxPrice` (type: `integer`):

Optional. Sent to Mercari as its own price filter. Leave empty for no maximum.

## `deltaMode` (type: `boolean`):

Turns this actor into a monitor. A listing counts as new when its Mercari item ID hasn't been returned by a previous run of the same watchlist; a price drop counts when a previously-seen fixed-price listing's price has fallen (see "Minimum price drop" below). With "Sold" listing type, new means newly sold since the last run: a running sold-comps log. Already-reported listings are dropped before you're billed, so a run with nothing new costs only the run fee. The first run returns and remembers everything; from the second run on you get only what changed.

## `deltaName` (type: `string`):

Leave empty and we derive one from this run's filters, so two schedules with different filters keep separate memories. Type your own name to keep one memory across a filter change, or to have two schedules share one.

## `alertOnNew` (type: `boolean`):

Part of "Alert on" (split into two checkboxes so the Console can render it as a plain toggle pair). On by default.

## `alertOnPriceDrop` (type: `boolean`):

Part of "Alert on". On by default.

## `minPriceDropPct` (type: `integer`):

Only fixed-price listings count: auction bids and sold items never fire a price drop. Default 5%.

## `skipFirstRun` (type: `boolean`):

On: the run that first starts a watchlist banks every listing silently — no rows, no charge — instead of reporting everything that already existed as "new". Off (default): the first run returns everything it finds, all marked new.

## `includeSellerInfo` (type: `boolean`):

Off by default. On: adds the seller's raw Mercari user ID to every row, in addition to the always-on anonymous seller hash. Mercari's search results carry no seller name, phone or email, and none is ever collected. Turning this on makes you responsible for having a lawful reason to process that personal data.

## `columns` (type: `array`):

Choose which pieces of information to include in each result row. All are included by default.

## `expandRows` (type: `boolean`):

When on, each listing found gets its own row instead of being grouped under its search. You're still only charged once per search, no matter how many rows it produces.

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

Parallel requests. Keep conservative — this target has no browser fallback, so getting blocked costs more than slow-and-steady.

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

Apify Proxy config. Residential recommended for anti-bot-sensitive targets.

## Actor input object example

```json
{
  "searches": [
    "ポケモンカード"
  ],
  "testRun": false,
  "onlyFound": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "maxListingsPerSearch": 100,
  "listingType": "active",
  "sort": "newest",
  "condition": "any",
  "categoryId": "",
  "brand": "",
  "deltaMode": false,
  "deltaName": "",
  "alertOnNew": true,
  "alertOnPriceDrop": true,
  "minPriceDropPct": 5,
  "skipFirstRun": false,
  "includeSellerInfo": false,
  "columns": [
    "searchQuery",
    "listingType",
    "listingCount",
    "totalAvailable",
    "truncated",
    "newCount",
    "priceDropCount",
    "listings",
    "listingId",
    "url",
    "title",
    "price",
    "currency",
    "listingStatus",
    "conditionId",
    "conditionName",
    "conditionNameJa",
    "category",
    "brand",
    "sellerType",
    "shippingPaidBy",
    "isAuction",
    "auctionEndsAt",
    "postedAt",
    "updatedAt",
    "imageUrl",
    "sellerHash",
    "sellerId",
    "isNew",
    "changeType",
    "previousPrice",
    "priceDropPct",
    "firstSeenAt"
  ],
  "expandRows": true,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (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 = {
    "searches": [
        "ポケモンカード"
    ],
    "includeKeywords": [],
    "excludeKeywords": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("accountable_eel/mercari-jp-listing-lookup").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 = {
    "searches": ["ポケモンカード"],
    "includeKeywords": [],
    "excludeKeywords": [],
}

# Run the Actor and wait for it to finish
run = client.actor("accountable_eel/mercari-jp-listing-lookup").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 '{
  "searches": [
    "ポケモンカード"
  ],
  "includeKeywords": [],
  "excludeKeywords": []
}' |
apify call accountable_eel/mercari-jp-listing-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,accountable_eel/mercari-jp-listing-lookup"
        }
    }
}
```

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/Gk2EKIEFuJ51im9iu/builds/BcSztgZd5BFYv8IzD/openapi.json
