# Trefac Scraper – Treasure Factory Japan Secondhand Fashion (`tokyo-select-jp/trefac-search-scraper`) Actor

Scrape Trefac ONLINE (トレファク, Treasure Factory) — Japan's largest secondhand fashion chain. Search by brand, category, price or new arrivals; get normalized size, condition rank, measurements and images. Part of the JP Data Works series (Mercari, Yahoo Auctions, Komehyo coming).

- **URL**: https://apify.com/tokyo-select-jp/trefac-search-scraper.md
- **Developed by:** [JP Data Works](https://apify.com/tokyo-select-jp) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Trefac (トレファク) Scraper – Treasure Factory Japan Secondhand Fashion

Scrape **Trefac ONLINE (トレファク, [trefac.jp](https://www.trefac.jp/))** — the online store of **Treasure Factory**, Japan's largest secondhand / vintage fashion chain (used clothing, 古着, ブランド古着). Search by **brand, category, price range, condition rank or new arrivals** and get **normalized size, condition rank (★1–6), measurements in cm and full-size images** as clean JSON / CSV. Part of the **JP Data Works** series of Japanese marketplace scrapers (Mercari, Yahoo! Auctions, KOMEHYO coming).

**Keywords:** Treasure Factory scraper · トレファク スクレイピング · Japan secondhand fashion data · Japanese vintage clothing API · used clothing Japan · resale sourcing (eBay, Grailed, Depop) · KAPITAL, visvim, Comme des Garçons, Yohji Yamamoto, Levi's price monitoring.

Search **[trefac.jp](https://www.trefac.jp/)** — the online store of Treasure Factory, one of Japan's largest second-hand fashion chains — by keyword **or by brand, category, price range, condition rank, gender and sort order** (for example *new arrivals under ¥20,000 for KAPITAL*) and get clean, structured listings. Optionally open each item page to add the **condition rank (★1–6)**, **measurements in cm**, the **staff comment** and all gallery images.

Typical uses: vintage / brand sourcing for resale (eBay, Grailed, Mercari), price monitoring for Japanese brands (KAPITAL, visvim, Comme des Garçons, Yohji Yamamoto …), size-filtered alerts, market research on the Japanese used-clothing market.

### What you get

For every listing:

- `itemId`, `url`, `title`, `brand`, `itemName`, `color`
- `priceJpy` (integer, tax included)
- `sizeRaw` (as shown on the tag, e.g. `W28`, `L`, `SIZE M（ 参考サイズ：M ）`) and `sizeNorm` — a machine-friendly interpretation: `{ kind: "waist", value: 28 }`, `{ kind: "alpha", value: "M" }`, `{ kind: "numeric", value: 38 }`, `{ kind: "cm", value: 26.5 }`, `{ kind: "free" }`
- `gender` (メンズ / レディース), `badges` (`NEW`, `SALE`), `storeName` (the physical shop that holds the item)
- `imageUrls` (full-size image), `fetchedAt`, `keyword`

With **Enrich with item detail pages** enabled, each item additionally has:

- `conditionRank` 1–6 (number of ★) and `conditionLabel` (e.g. `やや傷や汚れがあり`)
- `conditionNotes` — the staff-written 状態 notes on stains, fading, wear
- `measurementsCm` — `shoulder` 肩幅, `chest` 身幅, `sleeve` 袖丈, `length` 着丈, `waist` ウエスト, `inseam` 股下, `rise` 股上, `thigh` わたり, `hem` 裾幅, `totalLength` 総丈, `hip` ヒップ …
- `staffComment`, `category`, `material`, `madeIn`
- `imageUrls` — every gallery image at full resolution
- `detailFetchedAt`

#### Example item (enriched)

```json
{
  "source": "trefac",
  "itemId": "1048009921949391",
  "url": "https://www.trefac.jp/store/1048009921949391/c4211375/",
  "title": "THE REAL McCOY'S 半袖スウェット グリーン",
  "brand": "THE REAL McCOY'S",
  "itemName": "半袖スウェット",
  "color": "グリーン",
  "priceJpy": 6600,
  "sizeRaw": "SIZE M（ 参考サイズ：M ）",
  "sizeNorm": { "kind": "alpha", "value": "M" },
  "gender": "メンズ",
  "badges": [],
  "conditionRank": 3,
  "conditionLabel": "やや傷や汚れがあり",
  "conditionNotes": "こちらの商品は中古品の為…\n※全体的にヨゴレが見受けられます。\n※軽い生地ヤケが見受けられます。\n※スレが見受けられます。",
  "measurementsCm": { "shoulder": 43, "chest": 50.5, "sleeve": 20, "length": 59 },
  "staffComment": "THE REAL McCOY'S 半袖スウェット グリーン プリント柄 波モチーフ",
  "category": "トップス > Tシャツ/半袖カットソー",
  "material": "綿 100%",
  "madeIn": "日本",
  "imageUrls": [
    "https://www.trefac.jp/image/item/1048009921949391/1048009921949391_01_6991w.jpeg",
    "https://www.trefac.jp/image/item/1048009921949391/1048009921949391_03_2575w.jpeg"
  ],
  "storeName": "上福岡店",
  "fetchedAt": "2026-10-30T04:54:35.273Z",
  "detailFetchedAt": "2026-10-30T04:54:38.285Z",
  "keyword": "KAPITAL",
  "search": {
    "label": "KAPITAL ¥–20000 ★4+ newest",
    "keyword": "KAPITAL",
    "brandId": null,
    "brand": null,
    "categoryId": null,
    "kindId": null,
    "categoryPath": null,
    "gender": "any",
    "priceMinJpy": null,
    "priceMaxJpy": 20000,
    "sort": "newest",
    "conditionMin": 4,
    "storeName": null,
    "clientSideFilters": [],
    "effectiveKeyword": "KAPITAL",
    "url": "https://www.trefac.jp/store/tcpsb/?srchword=KAPITAL&selecte=20000&gcondition=4,5,6&step=1&order=new"
  }
}
```

`search` records the resolved parameters of the search that produced the item (and the first page URL), so rows from several searches in one dataset stay distinguishable. `keyword` is the keyword, or the search label when the search had no keyword.

Without enrichment the detail fields are `null` / `{}` / `[]`, so the dataset always has the same columns.

### Output modes — listings or a market summary

`outputMode` chooses what the dataset contains:

- **`items`** (default) — one row per listing, as above.
- **`summary`** — one **market-summary row per search** instead of the listings. The Actor still walks the search pages (up to `maxItemsPerSearch` listings, with `enrichDetail` if set), but stores only the aggregate — so a run that answers "what does X go for on Trefac?" costs one `summary` event per search rather than hundreds of result events.
- **`both`** — the listings plus the summary row.

A summary row (`recordType: "summary"`) has the same shape in every JP Data Works Actor, so you can put several sites side by side:

```json
{
  "recordType": "summary",
  "source": "trefac",
  "search": { "label": "…", "url": "…", "…": "the resolved search parameters" },
  "fetchedAt": "2026-11-02T03:00:00.000Z",
  "sampleSize": 180, "totalOnSite": 1243, "scanned": 190, "filteredOut": 10, "withDetail": 0,
  "status": { "on_sale": 180, "sold": 0, "unknown": 0 },
  "price": { "count": 180, "min": 3300, "p25": 9800, "median": 16500, "mean": 19840, "p75": 25300, "max": 128000, "stddev": 15210 },
  "priceOnSale": { "…": "same statistics for on-sale listings" }, "priceSold": { "…": "and for sold ones (sites that list them)" },
  "priceHistogram": { "bucketJpy": 10000, "buckets": [ { "fromJpy": 0, "toJpy": 10000, "count": 46 }, "…" ] },
  "conditionRank": { "6": 12, "5": 40, "4": 71, "3": 30, "unknown": 27 }, "conditionLabels": { "…": "the site's own labels" },
  "sizes": { "M": 48, "L": 41, "W32": 12, "…": 0 }, "sizeKinds": { "alpha": 120, "waist": 30, "numeric": 20, "unknown": 10 },
  "brands": { "KAPITAL": 180 }, "categories": { "メンズ > ジャケット/アウター": 95, "…": 0 }, "gender": { "mens": 170, "unknown": 10 },
  "listed": { "last24h": 9, "last7d": 41, "last30d": 120 }, "sold": null,
  "cheapest": [ { "itemId": "…", "title": "…", "url": "…", "priceJpy": 3300, "conditionRank": 4, "size": "M", "status": "on_sale" }, "…" ],
  "cheapestGoodCondition": [ "… cheapest with condition rank ≥ 4 …" ],
  "newest": [ "… most recently listed (sites that expose listing times) …" ]
}
```

Trefac lists in-stock items only, so `status` is always `on_sale`, `priceSold` is empty and `listed` / `sold` are `null` (the site has no listing time); use `sort: newest` plus scheduled runs for arrival tracking.

### Input

Two ways to describe what to search, which can be combined in one run:

- **`keywords`** — simple: one search per keyword (`KAPITAL`, `リーバイス 501`, …).
- **`searches`** — structured: a list of objects with any of `keyword`, `brand` / `brandId`, `categoryPath` / `categoryId`, `priceMinJpy`, `priceMaxJpy`, `sort`, `conditionMin`, `gender`, `storeName`.

Top-level `sort`, `priceMinJpy`, `priceMaxJpy` and `conditionMin` are defaults for every keyword and search; a value inside a search wins.

| Field | Type | Default | Notes |
|---|---|---|---|
| `keywords` | string\[] | — | One search per keyword. Japanese or English. Optional when `searches` is given. |
| `outputMode` | `items` | `summary` | `both` | `items` | Listings, one market-summary row per search, or both (see "Output modes"). |
| `searches` | object\[] | — | Structured searches, see the table below. Each needs at least a keyword, brand or category. |
| `sort` | `relevance` | `newest` | `priceAsc` | `priceDesc` | `relevance` | Default sort order. `newest` = 新着順 (new arrivals first). |
| `priceMinJpy` / `priceMaxJpy` | integer | none | Default price bounds (tax included). |
| `conditionMin` | integer 1–6 | none | Default minimum condition rank (6 未使用品, 5 未使用に近い, 4 使用感をあまり感じない, 3 やや傷や汚れがあり, 2 傷や汚れがあり, 1 all). |
| `maxItemsPerKeyword` | integer | 60 | 1–500 listings per keyword / search. The site shows 90 per page. |
| `maxTotalItems` | integer | none | Hard cap on listings saved per run, across all searches. |
| `dedupeAcrossSearches` | boolean | true | Save a listing only once when several searches return it (same `itemId`). |
| `enrichDetail` | boolean | false | Open each item page (one extra request + one `detail-page` event per item). |
| `maxDetailPages` | integer | 100 | Cap on item pages per run. Items beyond the cap are returned without detail fields. |
| `requestDelayMs` | integer | 3000 | Minimum pause between requests. Please keep ≥ 3000. |
| `proxyConfiguration` | object | none | Optional Apify Proxy. Not needed under normal use. |
| `outputFields` | string\[] | all | Keep only these top-level fields (`itemId` and `url` are always kept). |

Fields of one `searches` entry (all optional):

| Field | Example | How it is applied |
|---|---|---|
| `keyword` | `"デニムジャケット"` | Site search (`srchword`). |
| `brand` | `"KAPITAL"`, `"キャピタル"` | Looked up in the site's brand list (English or katakana name, exact match) and sent as the brand id. If the name is not in the list it is searched as a keyword and results are filtered by brand name. |
| `brandId` | `17171` | The site's brand id — the number in `https://www.trefac.jp/store/tcpsb<ID>/` on [trefac.jp/brand](https://www.trefac.jp/brand/). Examples: 17171 KAPITAL, 36518 VISVIM, 18847 LEVI'S, 7738 COMME des GARCONS, 37924 YOHJI YAMAMOTO. |
| `categoryPath` | `"アウター・ジャケット > デニムジャケット"`, `"pants > デニムパンツ"`, `"shoes"`, `"スニーカー"` | Top-level category (`トップス`, `アウター・ジャケット`, `コート`, `パンツ`, `スカート`, `ワンピース`, `スーツ/ネクタイ`, `バッグ`, `シューズ`, `帽子`, `時計`, `財布/小物`, `アクセサリー`, `ファッション小物`, `その他`; English aliases `tops`, `jackets`, `coats`, `pants`, `skirts`, `dresses`, `suits`, `bags`, `shoes`, `hats`, `watches`, `wallets`, `accessories`, `other`) optionally followed by `>` and a sub-category name as shown on the site. A bare sub-category name also works. Unknown paths are used as an extra keyword. |
| `categoryId` | `92`, `154` | The site's category id (top level `gcateg` or sub category `kind`). |
| `priceMinJpy` / `priceMaxJpy` | `5000` / `20000` | Site price filter, re-checked on the client. |
| `sort` | `"newest"` | `relevance` (関連度順), `newest` (新着順), `priceAsc` (価格の安い順), `priceDesc` (価格の高い順). |
| `conditionMin` | `4` | Site condition filter (`conditionMin` … 6); re-checked after detail enrichment. |
| `gender` | `"mens"` | `mens`, `ladies`, `kids`, `any`. |
| `storeName` | `"練馬"` | **Client-side only**: keeps items whose shop name contains the text. The Actor walks up to 12 pages per search to fill the quota. |

#### Examples

Keyword only (unchanged from 0.1):

```json
{ "keywords": ["KAPITAL", "visvim"], "maxItemsPerKeyword": 60 }
```

Structured searches:

```json
{
  "searches": [
    { "brand": "KAPITAL", "categoryPath": "アウター・ジャケット > デニムジャケット", "gender": "mens", "conditionMin": 4 },
    { "keyword": "501", "brandId": 18847, "priceMinJpy": 5000, "priceMaxJpy": 15000, "sort": "priceAsc" },
    { "categoryPath": "shoes > スニーカー", "storeName": "下北沢", "sort": "newest" }
  ],
  "maxItemsPerKeyword": 90,
  "maxTotalItems": 200,
  "enrichDetail": true
}
```

New arrivals under ¥20,000 for one brand (run it on a schedule and diff `itemId`s):

```json
{
  "searches": [{ "brand": "visvim", "sort": "newest", "priceMaxJpy": 20000 }],
  "maxItemsPerKeyword": 90
}
```

Requests are strictly sequential: a run with 2 searches × 60 items + detail = about 122 requests ≈ 6 minutes at the default delay (+1 request when brand names need to be resolved).

#### Search URL parameters (how the filters map to trefac.jp)

Discovered from the site's search form and its `search_result.js` (2026-10-30). The search URL is

```
https://www.trefac.jp/store/t{gtype}c{gcateg}ps{spsort}b{brandID}/?srchword=…&kind=…&selects=…&selecte=…&gcondition=4,5,6&order=new&step=1&key=2
```

| Actor field | Site parameter | Values |
|---|---|---|
| `keyword` | `srchword` (query) | free text |
| `gender` | `t…` path segment (`gtype`) | `1` mens, `2` ladies, `5` all kids (`3` boys, `4` girls), empty = any |
| `categoryId` / `categoryPath` | `c…` path segment (`gcateg`) + `kind` query | gcateg 90 トップス, 92 アウター・ジャケット, 140 コート, 86 パンツ, 18 スカート, 21 ワンピース, 22 スーツ/ネクタイ, 94 バッグ, 93 シューズ, 141 帽子, 26 時計, 25 財布/小物, 24 アクセサリー, 23 ファッション小物, 95 その他; `kind` = sub category id (e.g. 154 デニムジャケット, 170 デニムパンツ, 192 スニーカー) |
| `brandId` | `b…` path segment (`brandID`) | id from `/brand/` links `/store/tcpsb<ID>/` |
| `priceMinJpy` / `priceMaxJpy` | `selects` / `selecte` | JPY |
| `conditionMin` | `gcondition` | comma list of ranks to include, 6 未使用品 … 1; the Actor sends `n,…,6` |
| `sort` | `order` | empty 関連度順, `new` 新着順, `pdown` 価格の安い順, `phigh` 価格の高い順 |
| (always) | `step` | `1` in stock only (default), `all` include sold out |
| (pagination) | `key` | page number, 90 cards per page (`disp_num` 30/60/90) |
| `storeName` | — | the site has `shop=<id>[,<id>]` but only by numeric shop id, so the Actor filters by name client-side |
| not exposed | `gsize`, `cid`, `price_type`, `market`, `tag`, `spsort` | tag size list, colour id 1–15, 値下げ品のみ, SELECTED LUXURY / ヴィンテージ古着, tag, unused-only flag |

### FAQ

**What is Trefac / Treasure Factory?**
Treasure Factory (トレジャー・ファクトリー) is a Japanese reuse-shop chain with 300+ stores. Trefac ONLINE (trefac.jp) is its web store, listing used clothing, bags, shoes, watches and accessories from the physical shops — Japanese and international brands, from fast fashion to KAPITAL, visvim, Yohji Yamamoto and Comme des Garçons. Prices are in JPY, tax included; most items are one-of-a-kind.

**Do I need a proxy?**
No. The site serves the public search and item pages without blocking; the Actor runs on Apify's shared datacenter IPs with a 3-second delay. `proxyConfiguration` exists for users who want their own proxy.

**How are sizes normalized?**
`sizeRaw` keeps the tag text; `sizeNorm` interprets it (`waist` in inches for `W32` / bare `26–44`, `alpha` for `S/M/L/LL→XL`, `numeric` for JP `1–5` and EU numbers, `cm` for shoes, `free`). `size` is the short label (`W32`, `L`, `JP3`, `26.5cm`).

**What does condition rank mean?**
Trefac grades every item ★1–6: 6 未使用品 (unused), 5 未使用に近い (like new), 4 使用感をあまり感じない (little wear), 3 やや傷や汚れがあり (some wear), 2 傷や汚れがあり (visible wear), 1 (heavy wear). The rank is on the item page, so it is only filled with `enrichDetail: true`; `conditionMin` filters server-side.

**Can I monitor new arrivals?**
Yes — use `"sort": "newest"` with a brand / category / price cap, schedule the Actor (hourly or daily) and diff `itemId` against your previous run. Trefac lists hundreds of new items per day.

**Can I get sold items or price history?**
Not in this Actor: the site only shows in-stock listings (`step=1`). Keep your own history by scheduling runs; a listing that disappears has sold or been pulled.

**Is this legal?**
The Actor collects public product data only, obeys robots.txt, identifies itself and throttles requests. How you use the data is your responsibility — see the fair-use note below.

**How do I call it from code or from an AI agent?**
Any Apify client works. For example with the JavaScript client:

```js
import { ApifyClient } from "apify-client";
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor("tokyo-select-jp/trefac-search-scraper").call({
  searches: [{ brand: "KAPITAL", categoryPath: "pants", sort: "newest", priceMaxJpy: 20000 }],
  maxItemsPerKeyword: 90,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

or with plain HTTP (`run-sync-get-dataset-items` returns the results directly):

```
POST https://api.apify.com/v2/acts/tokyo-select-jp~trefac-search-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN
Content-Type: application/json

{ "keywords": ["visvim"], "maxItemsPerKeyword": 30 }
```

The Actor is also exposed through Apify's MCP server (`https://mcp.apify.com`), so Claude, ChatGPT, Cursor and other MCP-capable assistants can search Trefac by calling this Actor as a tool.

### Roadmap — JP Data Works

This Actor is the first of a series of scrapers for Japanese secondhand and auction marketplaces, all with the same normalized shape (`priceJpy`, `sizeNorm`, `conditionRank`, `measurementsCm`, `imageUrls`) so results can be merged:

- **KOMEHYO (コメ兵)** — luxury / brand resale
- **Yahoo! Auctions (ヤフオク!)** — including sold listings
- **Mercari Japan (メルカリ)** — listings and sold prices
- **2nd STREET (セカンドストリート)**, **RAGTAG** — planned
- A cross-site aggregator (one query → all stores)

Requests and bug reports: use the Issues tab of this Actor.

### Pricing (pay per event)

This Actor uses Apify's **pay-per-event** model. You only pay for what it produces:

| Event | Charged when | Price |
|---|---|---|
| Result (`apify-default-dataset-item`, charged automatically by Apify) | one listing is saved to the dataset | $0.002 |
| Detail page (`detail-page`) | that listing was enriched from its item page | $0.005 (in addition to the result) |
| Market summary (`summary`) | one summary row is saved (outputMode `summary` / `both`) | $0.03 per search |
| Actor start (`apify-actor-start`) | each run starts | $0.00005 |

Example: 100 listings with detail ≈ 100 × $0.002 + 100 × $0.005 = **$0.70**. Without detail: **$0.20**.
A `summary`-only run over 3 searches ≈ 3 × $0.03 = **$0.09**, whatever the number of listings sampled.
Set **Max total charge** on the run to cap spending — the Actor stops cleanly when the limit is reached and you keep everything collected so far.

### Legal / fair-use note

- `https://www.trefac.jp/robots.txt` allows search and item pages for all user agents (only the login page is disallowed). The Actor re-reads robots.txt on every run and refuses URLs that become disallowed.
- The Actor identifies itself with a descriptive User-Agent that includes a contact address, makes one request at a time, and waits `requestDelayMs` (≥ 1 s, default 3 s) between requests.
- Only publicly available product data is collected: no login, no personal data, no cart or purchase actions.
- You are responsible for how you use the data. Respect the site's terms of use, do not overload it (keep the delay high, keep runs small, schedule rather than loop), and do not republish its photos or texts as your own.

***

### 日本語

**トレファク ONLINE（trefac.jp、トレジャー・ファクトリー運営の古着通販）をキーワード、またはブランド・カテゴリ・価格帯・コンディション・性別・並び順（新着順など）で検索し、構造化された商品データを返す Actor です。** 例:「visvim の新着で ¥20,000 以下」。 オプションで各商品ページを開き、**コンディションランク（★1〜6）・採寸（cm）・スタッフコメント・全画像**を付加します。

用途: 古着・ブランド品の仕入れリサーチ（eBay / メルカリ転売）、国内ブランド（KAPITAL、visvim、ヨウジヤマモト…）の価格モニタリング、サイズ指定の入荷監視、など。

#### 出力（1 商品 = 1 行）

- `itemId` / `url` / `title` / `brand` / `itemName` / `color`
- `priceJpy`（税込、整数）
- `sizeRaw`（タグ表記そのまま）と `sizeNorm`（`{ kind: "waist", value: 28 }` = W28、`{ kind: "alpha", value: "M" }`、`{ kind: "numeric", value: 38 }`、`{ kind: "cm", value: 26.5 }`、`{ kind: "free" }`）
- `gender`（メンズ/レディース）、`badges`（NEW / SALE）、`storeName`（出品店舗）、`imageUrls`、`fetchedAt`、`keyword`
- `search`（その商品を見つけた検索条件の解決結果: keyword / brandId / categoryId / 価格帯 / sort / conditionMin / クライアント側フィルタ / 1 ページ目の URL）

**「商品ページで補完」(enrichDetail) を ON にすると追加で:**

- `conditionRank`（★の数 1〜6）と `conditionLabel`（例: やや傷や汚れがあり）
- `conditionNotes`（「状態」欄: ヨゴレ・ヤケ・スレ等の記載）
- `measurementsCm`（`shoulder` 肩幅 / `chest` 身幅 / `sleeve` 袖丈 / `length` 着丈 / `waist` ウエスト / `inseam` 股下 / `rise` 股上 / `thigh` わたり / `hem` 裾幅 / `totalLength` 総丈 / `hip` ヒップ）
- `staffComment` / `category` / `material` / `madeIn`、全ギャラリー画像（フルサイズ）

#### 入力

`keywords`（キーワードだけの簡単な検索）と `searches`（構造化検索）を併用できます。トップレベルの `sort` / `priceMinJpy` / `priceMaxJpy` / `conditionMin` は全検索の既定値で、各検索内の指定が優先されます。

| 項目 | 既定 | 説明 |
|---|---|---|
| `keywords` | — | 検索キーワード（1 行 1 件）。`searches` があれば省略可 |
| `searches` | — | 構造化検索の配列（下表）。各要素にキーワード・ブランド・カテゴリのいずれかが必要 |
| `sort` | `relevance` | 既定の並び順: `relevance` 関連度順 / `newest` 新着順 / `priceAsc` 価格の安い順 / `priceDesc` 価格の高い順 |
| `priceMinJpy` / `priceMaxJpy` | なし | 既定の価格帯（税込） |
| `conditionMin` | なし | 既定のコンディション下限 1〜6（6 未使用品、5 未使用に近い、4 使用感をあまり感じない、3 やや傷や汚れがあり、2 傷や汚れがあり） |
| `maxItemsPerKeyword` | 60 | 検索ごとの最大件数（1〜500、1 ページ 90 件） |
| `maxTotalItems` | なし | 1 実行で保存する件数の上限（全検索合計） |
| `dedupeAcrossSearches` | true | 複数の検索で同じ商品（itemId）が出たら 1 回だけ保存 |
| `enrichDetail` | false | 商品ページを開いて補完（1 商品につき +1 リクエスト） |
| `maxDetailPages` | 100 | 1 実行あたりに開く商品ページ数の上限 |
| `requestDelayMs` | 3000 | リクエスト間隔（ms）。3000 以上を推奨 |
| `proxyConfiguration` | なし | 通常は不要 |
| `outputFields` | 全項目 | 残すフィールドを限定 |

`searches` の各要素（すべて任意）:

| 項目 | 例 | 動作 |
|---|---|---|
| `keyword` | `"デニムジャケット"` | サイトのキーワード検索（`srchword`） |
| `brand` | `"KAPITAL"`, `"キャピタル"` | サイトのブランドリスト（英語名・カナ名の完全一致）でブランド ID に変換してサーバー側で絞り込み。見つからない場合はキーワードとして検索し、ブランド名で結果をフィルタ |
| `brandId` | `17171` | サイトのブランド ID（[trefac.jp/brand](https://www.trefac.jp/brand/) のリンク `/store/tcpsb<ID>/` の数字）。例: 17171 KAPITAL、36518 VISVIM、18847 LEVI'S、7738 COMME des GARCONS、37924 YOHJI YAMAMOTO |
| `categoryPath` | `"アウター・ジャケット > デニムジャケット"`, `"pants > デニムパンツ"`, `"シューズ"`, `"スニーカー"` | 大カテゴリ（トップス / アウター・ジャケット / コート / パンツ / スカート / ワンピース / スーツ/ネクタイ / バッグ / シューズ / 帽子 / 時計 / 財布/小物 / アクセサリー / ファッション小物 / その他、英語名も可）に `>` で小カテゴリ名を続ける。小カテゴリ名だけでも可。不明な値は追加キーワードとして扱う |
| `categoryId` | `92`, `154` | サイトのカテゴリ ID（大カテゴリ `gcateg` または小カテゴリ `kind`） |
| `priceMinJpy` / `priceMaxJpy` | `5000` / `20000` | サイトの価格フィルタ（取得後にも再チェック） |
| `sort` | `"newest"` | `relevance` / `newest` / `priceAsc` / `priceDesc` |
| `conditionMin` | `4` | サイトのコンディションフィルタ（指定ランク以上） |
| `gender` | `"mens"` | `mens` / `ladies` / `kids` / `any` |
| `storeName` | `"練馬"` | **クライアント側のみ**: 店舗名にこの文字列を含む商品だけ残す（サイトは店舗 ID でしか絞れないため）。件数を満たすため最大 12 ページまで読みます |

##### 入力例

キーワードのみ（0.1 と同じ）:

```json
{ "keywords": ["KAPITAL", "visvim"], "maxItemsPerKeyword": 60 }
```

構造化検索:

```json
{
  "searches": [
    { "brand": "KAPITAL", "categoryPath": "アウター・ジャケット > デニムジャケット", "gender": "mens", "conditionMin": 4 },
    { "keyword": "501", "brandId": 18847, "priceMinJpy": 5000, "priceMaxJpy": 15000, "sort": "priceAsc" },
    { "categoryPath": "シューズ > スニーカー", "storeName": "下北沢", "sort": "newest" }
  ],
  "maxItemsPerKeyword": 90,
  "maxTotalItems": 200,
  "enrichDetail": true
}
```

ブランド X の新着で ¥20,000 以下（スケジュール実行して `itemId` の差分を取る用途）:

```json
{
  "searches": [{ "brand": "visvim", "sort": "newest", "priceMaxJpy": 20000 }],
  "maxItemsPerKeyword": 90
}
```

サイトの URL パラメータとの対応は英語セクション「Search URL parameters」を参照してください（性別・カテゴリ・ブランド・価格帯・コンディション・並び順はサーバー側、店舗名はクライアント側で適用）。

#### 料金（従量課金 / Pay per event）

| イベント | 課金タイミング | 価格 |
|---|---|---|
| 結果（`apify-default-dataset-item`、Apify が自動課金） | 商品 1 件をデータセットに保存したとき | $0.002 |
| 商品ページ（`detail-page`） | その商品を商品ページで補完したとき（結果に加算） | $0.005 |
| 相場サマリー（`summary`） | `outputMode` が `summary` / `both` のとき、検索 1 件につきサマリー行 1 行 | $0.03 |
| Actor 起動（`apify-actor-start`） | 実行ごと | $0.00005 |

例: 100 件を詳細付きで取得 ≈ $0.70、詳細なし ≈ $0.20。`outputMode: "summary"` なら検索 1 件あたり $0.03 だけで相場（件数・価格の中央値 / 四分位 / 分布・状態ランク / サイズ / ブランド内訳・最安値）が返ります。実行時に「Max total charge」を設定すると上限で安全に停止し、それまでの結果は残ります。

#### 利用上の注意

- trefac.jp の robots.txt は検索・商品ページのクロールを許可しています（ログインページのみ不許可）。本 Actor は毎回 robots.txt を確認し、連絡先付きの User-Agent で、1 リクエストずつ、既定 3 秒間隔でアクセスします。
- 取得するのは公開されている商品情報のみです（ログイン・カート・購入操作は一切行いません）。
- データの利用はご自身の責任で、サイトの利用規約を守り、過度なアクセス（短い間隔・大量の繰り返し実行）や画像・文章の無断転載はお控えください。

# Changelog

This Actor's version history is a separate document: https://apify.com/tokyo-select-jp/trefac-search-scraper/changelog.md

# Actor input Schema

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

Simple keyword searches, one per line — brand names, item types, Japanese or English (e.g. `KAPITAL`, `リーバイス 501`, `visvim`). Each keyword is one search and inherits the default sort / price range / condition below. Optional when `searches` is set.

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

Advanced searches as JSON objects. Every field is optional, but each search needs at least one of `keyword`, `brand`, `brandId`, `categoryId`, `categoryPath`.

- `keyword` — free text (`srchword`).
- `brand` — brand name as listed on trefac.jp/brand (English or katakana, e.g. `KAPITAL`, `キャピタル`); resolved to the site's brand id. `brandId` — that id directly (the number in `/store/tcpsb<ID>/`, e.g. 17171 = KAPITAL, 36518 = VISVIM, 18847 = LEVI'S).
- `categoryPath` — `トップス`, `アウター・ジャケット > デニムジャケット`, `pants > デニムパンツ`, `shoes`, `デニムパンツ` …; `categoryId` — the site's category id (top level `gcateg` such as 92, or sub category `kind` such as 154).
- `priceMinJpy` / `priceMaxJpy` — tax-included price bounds.
- `sort` — `relevance` (default), `newest` (新着順), `priceAsc`, `priceDesc`.
- `conditionMin` — minimum condition rank 1–6 (6 = unused, 5 = like new, 4 = little sign of use).
- `gender` — `mens`, `ladies`, `kids`, `any`.
- `storeName` — keep only items held by a shop whose name contains this text (client-side).

Values set here override the defaults below.

## `outputMode` (type: `string`):

`items` (default): one dataset row per listing. `summary`: one market-summary row per search instead of the listings — sample size, price min / p25 / median / mean / p75 / max, price histogram, condition-rank, size, brand and category breakdowns, cheapest listings — billed once per search as the `summary` event (listings are not billed). `both`: listings plus the summary row.

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

Applied to every keyword / search that does not set its own `sort`. `newest` = 新着順 (new arrivals first), `priceAsc` = 価格の安い順, `priceDesc` = 価格の高い順.

## `priceMinJpy` (type: `integer`):

Lower price bound (tax included) for every search without its own `priceMinJpy`. Leave empty for no lower bound.

## `priceMaxJpy` (type: `integer`):

Upper price bound (tax included) for every search without its own `priceMaxJpy`. Leave empty for no upper bound.

## `conditionMin` (type: `integer`):

Only listings with this condition rank (★) or better: 6 未使用品, 5 未使用に近い, 4 使用感をあまり感じない, 3 やや傷や汚れがあり, 2 傷や汚れがあり, 1 全体的に使用感あり. Leave empty (or 1) for all.

## `maxItemsPerKeyword` (type: `integer`):

Stop after this many listings for each keyword / search. The site shows 90 listings per page, so up to 6 pages are fetched (12 when a client-side filter such as storeName is active).

## `maxTotalItems` (type: `integer`):

Hard cap on listings saved in one run, across all keywords and searches. Leave empty for no cap (each search is still limited by Max items per search).

## `dedupeAcrossSearches` (type: `boolean`):

When several keywords / searches return the same listing (same itemId), save it only once — with the first search that found it. Turn off to get one row per search.

## `enrichDetail` (type: `boolean`):

Also open each item's page to get the condition rank (★1–6 + label), measurements in cm (肩幅/身幅/袖丈/着丈/ウエスト/股下 …), staff comment, material, country and full-size image URLs. Costs one extra request (and one `detail-page` event) per item.

## `maxDetailPages` (type: `integer`):

Upper bound on item pages opened in one run (across all searches) when enrichDetail is on. Items beyond this limit are still returned, just without detail fields.

## `requestDelayMs` (type: `integer`):

Minimum pause between consecutive requests to trefac.jp. Keep it at 3000 ms or more to stay polite — the site is a small retailer and its robots.txt asks search engines for a 30 s crawl delay.

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

Optional. trefac.jp serves pages without a proxy, so leave this off unless your runs get blocked. Apify Proxy (datacenter or residential) is supported.

## `outputFields` (type: `array`):

Optional list of top-level fields to keep in each dataset item (itemId and url are always kept). Leave empty for the full item.

## Actor input object example

```json
{
  "keywords": [
    "KAPITAL"
  ],
  "searches": [
    {
      "brand": "KAPITAL",
      "categoryPath": "メンズ/パンツ",
      "priceMaxJpy": 20000,
      "sort": "newest"
    }
  ],
  "outputMode": "items",
  "sort": "relevance",
  "maxItemsPerKeyword": 60,
  "dedupeAcrossSearches": true,
  "enrichDetail": false,
  "maxDetailPages": 100,
  "requestDelayMs": 3000
}
```

# Actor output Schema

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

All scraped items (default dataset)

# 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": [
        "KAPITAL"
    ],
    "searches": [
        {
            "brand": "KAPITAL",
            "categoryPath": "メンズ/パンツ",
            "priceMaxJpy": 20000,
            "sort": "newest"
        }
    ],
    "sort": "relevance",
    "maxItemsPerKeyword": 60,
    "dedupeAcrossSearches": true,
    "enrichDetail": false,
    "maxDetailPages": 100,
    "requestDelayMs": 3000
};

// Run the Actor and wait for it to finish
const run = await client.actor("tokyo-select-jp/trefac-search-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": ["KAPITAL"],
    "searches": [{
            "brand": "KAPITAL",
            "categoryPath": "メンズ/パンツ",
            "priceMaxJpy": 20000,
            "sort": "newest",
        }],
    "sort": "relevance",
    "maxItemsPerKeyword": 60,
    "dedupeAcrossSearches": True,
    "enrichDetail": False,
    "maxDetailPages": 100,
    "requestDelayMs": 3000,
}

# Run the Actor and wait for it to finish
run = client.actor("tokyo-select-jp/trefac-search-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": [
    "KAPITAL"
  ],
  "searches": [
    {
      "brand": "KAPITAL",
      "categoryPath": "メンズ/パンツ",
      "priceMaxJpy": 20000,
      "sort": "newest"
    }
  ],
  "sort": "relevance",
  "maxItemsPerKeyword": 60,
  "dedupeAcrossSearches": true,
  "enrichDetail": false,
  "maxDetailPages": 100,
  "requestDelayMs": 3000
}' |
apify call tokyo-select-jp/trefac-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tokyo-select-jp/trefac-search-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/40KMAHEuFJkYepyhh/builds/zPDGa6dsJftZ6Vx3P/openapi.json
