# Japan Tokushoho Scraper - Online Shop Seller Contacts (`scrapersdelight/jp-tokushoho-contact-scraper`) Actor

Turn Japanese online-shop domains into seller leads from each shop's 特定商取引法に基づく表記 page: legal name, responsible person, address, phone, email, 法人番号 and T-number. Reads Rakuten and Yahoo! store pages too; BASE/STORES platform offices are flagged, never billed.

- **URL**: https://apify.com/scrapersdelight/jp-tokushoho-contact-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** Lead generation, E-commerce, Business
- **Stats:** 9 total users, 8 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$6.00 / 1,000 per japanese shop seller returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

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

## Japan Tokushoho Scraper — Online Shop Seller Contacts

Give it a list of Japanese online-shop domains. For each shop it finds the **特定商取引法に基づく表記** page — the seller disclosure every Japanese mail-order shop publishes — and returns **one row per shop**: the seller's legal name, the responsible person, address, phone (as printed and in +81 form), email, fax, invoice T-number and 法人番号 when printed, plus the shop's payment methods, shipping fees, delivery time and returns policy as printed.

It also takes **Rakuten Ichiba and Yahoo!ショッピング store URLs** — each store's `info.html` is its disclosure — and follows a corporate site to its own shop on another host (`ec.example.co.jp`, a Color Me or BASE shop, a Rakuten store).

You pay only for rows that **name the seller and carry its address or phone**. Everything else comes back in the same dataset, unbilled, with a status that says why.

### What one row is

One shop domain → one row. A billed row (`status: "ok"`) — a real row from the verification run on 2026-10-16:

```json
{
  "domain": "wargo.jp",
  "status": "ok",
  "billed": true,
  "sellerName": "株式会社和心",
  "representative": "最上 夢人",
  "address": "〒151-0051 東京都渋谷区千駄ヶ谷3-20-12和心ビル",
  "postalCode": "151-0051",
  "prefecture": "東京都",
  "phone": "03-5785-0556",
  "phoneE164": "+81357850556",
  "email": "cs2@wagokoro.co.jp",
  "disclosureUrl": "https://wargo.jp/policies/legal-notice",
  "ecPlatform": "shopify",
  "platformProxied": false
}
```

### Measured coverage (2026-10-16)

Measured on **140 Japanese online-shop domains the scraper had never seen**, drawn at random from two independent lists — the Tranco top-1M `.jp` domains (75) and OpenStreetMap shops in Japan with a website (65) — each verified as a live storefront from its homepage before the run, and run through the same network path the Actor uses on Apify.

| | billed row returned |
|---|---|
| Tranco `.jp` domains | 70 of 75 = **93.3%** |
| OpenStreetMap shops | 60 of 65 = **92.3%** |
| **all 140** | **130 = 92.9%** |

| shop platform | billed |
|---|---|
| Shopify | 49 of 51 |
| own-built shop sites | 36 of 42 |
| EC-CUBE | 16 of 17 |
| BASE (own domain and `*.thebase.in`) | 6 of 6 |
| futureshop · WooCommerce · MakeShop · おちゃのこネット · ecbeing · Salesforce Commerce · STORES | 23 of 23 |

Why the other 10 returned no billed row — each one re-checked by crawling the shop in a real browser: 5 publish no disclosure page reachable from their homepage · 2 hosts did not answer within the per-shop deadline · 1 page carries only a shop template's sample values (株式会社テストショップ / ◯◯◯◯) · 1 page sits behind an age gate · 1 page sat behind a "ショップ案内" link the scraper did not follow then (it does now). **Of the shops that publish a readable disclosure, 130 of 133 = 97.7% returned a billed row.**

On the 200-domain sample measured on 2026-09-29 (163 = 81.5% on the previous build) this build returns 177 = 88.5% using only the free network route (no residential IPs, no Unblocker).

Field fill over the 131 billed rows of the first pass on the 140 shops: seller name 98% · responsible person 93% · address 98% · prefecture 97% · phone 87% · postcode 76% · email 65% · payment methods 91% · returns policy 92% · extra fees 83% · delivery time 79% · hours 30% · fax 18% · licence (古物商 etc.) 10% · invoice T-number 3% · 法人番号 3%.

Network: 125 of the 130 billed rows opened on Apify's own datacenter egress; 5 needed Japanese residential IPs. Two large retailers refuse every route, the Apify Unblocker included (zozo.jp, mediplus-lab.jp) and come back as `blocked`.

### Input

| field | what it does | default |
|---|---|---|
| `domains` | Shop domains, homepage URLs, the 特定商取引法 page URL itself, or a Rakuten / Yahoo!ショッピング store URL. Any TLD. | 5-shop demo |
| `startUrls` | The same list as URLs (Make, Zapier, Clay, Google Sheets). Merged and deduplicated. | — |
| `maxItems` | Cap on **billed** rows. Unbilled rows never count. 0 = no cap. | 1000 |
| `maxRequestsPerDomain` | Requests spent finding one shop's page, homepage included. | 14 |
| `perDomainTimeoutSecs` | Deadline for one shop. | 150 |
| `requestConcurrency` | Shops worked in parallel (lowered automatically if memory is short). | 16 |
| `requestTimeoutSecs` | Timeout for a single request. | 20 |
| `includeUnbilledRows` | Return a row for every input, billed or not. | on |
| `includeTermsFields` | Payment methods, extra fees, delivery time, returns policy. | on |
| `useSitemap` · `useWordPressSearch` · `followWwwVariants` · `followShopLinks` | Discovery channels: the sitemaps `robots.txt` names, WordPress page search, the other host form, the shop's own store on another host. | on |
| `useDatacenterProxy` · `escalateToResidential` · `escalateToUnblocker` · `residentialCountry` | Transport ladder: direct first, then the Apify datacenter pool (only when your account has one), then Japanese residential IPs, then the Apify Unblocker — each only when a host refuses. | on · on · on · JP |
| `proxyConfiguration` | Your own proxy for the first attempt. | none |
| `maxBodyKb` | Pages are streamed and cut at this size (head and end kept). | 1500 |
| `saveRawPages` | Store the exact page each row was read from (gzipped) in the run's key-value store. | off |

```json
{ "domains": ["kinto.co.jp", "https://www.yoshikawa-k.co.jp/", "https://www.rakuten.co.jp/biccamera/"] }
```

### How each shop's page is found

In this order, stopping at the first page that names the seller with an address or phone:

1. the URL you gave, when it is the disclosure page (or a Rakuten / Yahoo! store's `info.html`)
2. the homepage's own links — and links the browser shows but the server HTML only carries as data (a commented-out footer link, a footer built from script JSON)
3. the shop platform's standard page (Shopify `/policies/legal-notice`, futureshop `/p/about/terms`, EC-CUBE `/help/tradelaw`, MakeShop `/view/contract`, Color Me `?mode=sk`, BASE `/law`, STORES `/tokushoho`, ecforce `/shop/law_info`, おちゃのこネット `/info` …)
4. Shopify's own page search, for pages with free-form handles
5. the sitemaps the shop's `robots.txt` names (content pages only)
6. WordPress page search
7. the shop's own store on another host
8. one hop into a ご利用ガイド / 会社概要 page
9. conventional paths (`/law`, `/tokushoho`, `/legal` …)

When the 特定商取引法 page names the seller but prints no address or phone (or the reverse), the shop's own 会社概要 page fills **only the missing fields**, and only when it names the same company; `companyPageUrl` and `supplementedFields` say so on the row.

### Output fields

`domain` · `inputUrl` · `status` · `billed` · `sellerName` (販売業者) · `shopName` (ショップ名 / ブランド名) · `representative` (運営統括責任者 / 代表者) · `representativeRole` · `address` (所在地) · `postalCode` · `prefecture` · `phone` · `phoneE164` · `phones` · `email` · `emails` · `fax` · `corporateNumber` (法人番号) · `corporateNumberSource` · `invoiceRegistrationNumber` (T-number) · `hours` · `license` · `paymentMethods` · `extraFees` · `deliveryTime` · `returnsPolicy` · `siteUrlPrinted` · `disclosureUrl` · `companyPageUrl` · `supplementedFields` · `ecPlatform` · `platformProxied` · `platformOperator` · `contactWithheld` · `labelsFound` · `missReason` · `requests` · `transport` · `secondsSpent` · `rawPageKey` · `scrapedAt`

- **Values are as printed.** A phone keeps the page's own separators (`0724689631` stays unhyphenated); `phoneE164` is the same digits with the national 0 dropped (`+81…`), nothing completed or guessed.
- **English pages are read too** ("Notation based on the Act on Specified Commercial Transactions": Company Name, Representative, Address …); the prefecture of an English address is given in Japanese (`Osaka` → `大阪府`).
- **法人番号 and T-number are check-digit verified.** A number that fails the National Tax Agency check digit is never returned. 法人番号 is rarely printed on these pages; when a **corporation** prints its invoice T-number, `corporateNumber` carries its 13 digits and `corporateNumberSource` says `invoice-registration-number`.
- **`platformProxied: true`** — BASE and STORES micro-shops may print the platform's office instead of their own. Those rows are returned with this flag and are **never billed**.
- **`ecPlatform`** — the shop's cart platform read from its homepage (shopify, makeshop, futureshop, eccube, colorme, woocommerce, salesforce-commerce, rakuten, yahoo-shopping, own-stack …).

### Status values

| status | billed | meaning |
|---|---|---|
| `ok` | **yes** | seller named + address or phone printed |
| `platform_proxied` | no | the page prints the hosting platform's office, not the seller's |
| `no_disclosure_found` | no | no 特定商取引法 page reachable from the homepage, platform path, page search, sitemap, the shop's own store, guide pages or conventional paths |
| `disclosure_unreadable` | no | the page exists but its values are filled in by JavaScript or behind a gate |
| `disclosure_image` | no | the seller block is printed as images |
| `incomplete_disclosure` · `contact_withheld` | no | the page names no seller, or the seller withholds address and phone |
| `blocked` · `unreachable` · `dead_host` | no | the host refused every transport rung, timed out, or does not resolve |

`RUN_SUMMARY` in the run's key-value store counts every status, the field fill over billed rows and the transport used.

### Pricing

Pay per event: **$6 per 1,000 seller rows** (`seller-scraped`, $0.006 each). No start fee. Unbilled rows are free.

### Limits

- Some small shops publish no disclosure page at all; they return `no_disclosure_found`.
- A host that answers only Japanese IPs is retried on Japanese residential IPs, which is slower; a few large retailers refuse every route and return `blocked`.
- Pages whose values only appear after JavaScript runs, or behind an age gate, return `disclosure_unreadable`.

# Actor input Schema

## `domains` (type: `array`):

One entry per online shop. Accepts a bare domain ("kinto.co.jp"), a homepage URL ("https://www.yoshikawa-k.co.jp/") or the shop's 特定商取引法に基づく表記 page itself. Any TLD works — Japanese shops trade on .jp, .co.jp, .com, .shop and .tokyo. Each domain returns exactly one row; only rows that name the seller AND carry its address or phone are billed. Leave empty to run a built-in 5-shop demo.

## `startUrls` (type: `array`):

The same list handed over as URLs, so Make, Zapier, Clay or a Google Sheet can pass it natively. Merged with the domains above and deduplicated.

## `maxItems` (type: `integer`):

Hard cap on seller rows DELIVERED AND BILLED this run. Unbilled rows (no disclosure page, platform-proxied, unreachable) never count toward it. 0 = no cap.

## `maxRequestsPerDomain` (type: `integer`):

Hard cap on requests spent finding one shop's disclosure, homepage included. The ladder stops at the first page that parses, so most shops use 2–4; a shop with no disclosure page uses the whole cap on free requests.

## `perDomainTimeoutSecs` (type: `integer`):

Wall-clock deadline for one shop, every request included (no request starts with less than 3 s left). A shop that hits it is reported as unreachable and not billed.

## `requestConcurrency` (type: `integer`):

How many shops are worked in parallel (one request in flight per shop). Lowered automatically when the run's memory is short.

## `requestTimeoutSecs` (type: `integer`):

Timeout for a single HTTP request.

## `includeUnbilledRows` (type: `boolean`):

Emit a row for every domain that produced no billable seller — platform-proxied micro-shops (with platformProxied: true), shops with no disclosure page, pages printed as images, unreachable hosts — with its status and missReason, so the dataset accounts for every input. These rows are never billed.

## `includeTermsFields` (type: `boolean`):

Also return the shop's payment methods, extra fees (shipping / COD), delivery time and returns policy as printed on the same page.

## `useSitemap` (type: `boolean`):

When the footer has no link, read the shop's sitemap (Shopify lists every page handle there, Japanese handles included) for the disclosure page. Two small requests at most.

## `useWordPressSearch` (type: `boolean`):

On a WordPress / WooCommerce shop, ask the site's own page index for a 特定商取引 page. One small JSON request.

## `followWwwVariants` (type: `boolean`):

If the homepage fails, retry the other host form (www.x.jp to x.jp and back).

## `followShopLinks` (type: `boolean`):

When the domain is a corporate site whose online shop lives on another host (ec.example.co.jp, a Color Me / BASE / STORES shop, a Rakuten or Yahoo!ショッピング store), read the disclosure on that shop. One to three requests.

## `useDatacenterProxy` (type: `boolean`):

The first request to each host goes out directly. On a refusal (403 / 429 / challenge / reset) the host is retried through the Apify datacenter pool — only when the account running the Actor has an Apify datacenter group; otherwise this rung is skipped.

## `escalateToResidential` (type: `boolean`):

A host that refused the free rungs is retried on an Apify RESIDENTIAL exit in the country below, reusing one working session per host, at most five pages per shop and inside the per-run budget. Guessed paths never escalate.

## `escalateToUnblocker` (type: `boolean`):

A host that refused every earlier rung (direct, datacenter, Japanese residential, each with a Firefox and a Chrome fingerprint) gets one more attempt through the Apify Unblocker, at most three pages per shop. Both paid rungs share one per-run budget tied to the rows billed, so they can never cost more than the run earns.

## `residentialCountry` (type: `string`):

ISO country code for the residential rung. JP by default: several Japanese retailers answer only Japanese IPs.

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

Leave as is for the measured default (direct, then datacenter, then residential JP only on a block). Supply your own proxy URLs or an Apify proxy group to route the FIRST attempt through them instead.

## `maxBodyKb` (type: `integer`):

Pages are streamed and cut at this size. 1,500 KB keeps every footer seen in testing.

## `saveRawPages` (type: `boolean`):

Store the exact page each billed or unbilled seller row was parsed from, gzipped, in this run's key-value store (key page\_<domain>; the row's rawPageKey names it), so any row can be re-checked against its bytes. Adds storage; off by default.

## Actor input object example

```json
{
  "domains": [
    "kinto.co.jp",
    "yoshikawa-k.co.jp",
    "hayni.jp",
    "mariagefreres.co.jp",
    "kamada.co.jp"
  ],
  "maxItems": 1000,
  "maxRequestsPerDomain": 14,
  "perDomainTimeoutSecs": 150,
  "requestConcurrency": 16,
  "requestTimeoutSecs": 20,
  "includeUnbilledRows": true,
  "includeTermsFields": true,
  "useSitemap": true,
  "useWordPressSearch": true,
  "followWwwVariants": true,
  "followShopLinks": true,
  "useDatacenterProxy": true,
  "escalateToResidential": true,
  "escalateToUnblocker": true,
  "residentialCountry": "JP",
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "maxBodyKb": 1500,
  "saveRawPages": false
}
```

# Actor output Schema

## `sellers` (type: `string`):

One row per shop domain — billed rows carry the seller's name, address and phone from its 特定商取引法に基づく表記 page.

## `summary` (type: `string`):

Counts per status (billed, platform-proxied, no disclosure, unreachable), field fill over billed rows and transport statistics.

# 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 = {
    "domains": [
        "kinto.co.jp",
        "yoshikawa-k.co.jp",
        "hayni.jp",
        "mariagefreres.co.jp",
        "kamada.co.jp"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/jp-tokushoho-contact-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 = {
    "domains": [
        "kinto.co.jp",
        "yoshikawa-k.co.jp",
        "hayni.jp",
        "mariagefreres.co.jp",
        "kamada.co.jp",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/jp-tokushoho-contact-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 '{
  "domains": [
    "kinto.co.jp",
    "yoshikawa-k.co.jp",
    "hayni.jp",
    "mariagefreres.co.jp",
    "kamada.co.jp"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call scrapersdelight/jp-tokushoho-contact-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/jp-tokushoho-contact-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/dm8cukZK2Iq5cL4Tb/builds/aOfjlpIFleZOToXPD/openapi.json
