# Japan Horse Racing Scraper - JRA Odds, Race Cards & Results (`datamill/netkeiba-race-scraper`) Actor

Scrape JRA horse racing data from netkeiba: race cards, live win and place odds, results and every payout as clean English JSON.

- **URL**: https://apify.com/datamill/netkeiba-race-scraper.md
- **Developed by:** [Data Mill](https://apify.com/datamill) (community)
- **Categories:** Other, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### What does Japan Horse Racing Scraper do?

This Actor extracts **Japanese (JRA) horse racing data** from [netkeiba](https://race.netkeiba.com), Japan's leading racing portal, and returns it as clean **English-keyed JSON**. You get daily race schedules, full race cards with every horse, jockey and weight, **live win & place odds pulled from the official odds API**, and finished results with **every payout type including trifecta (三連単)**.

Japan runs the largest horse racing betting market on earth — JRA turnover exceeds ¥3 trillion a year — yet almost all of its data is locked behind Japanese-only pages. This Actor unlocks it. Run it from the Apify Console, call it via **API**, **schedule** it around post times, or plug it into an AI agent through **MCP**.

### Why use Japan Horse Racing Scraper?

- **Build and backtest betting models** — join race cards, odds snapshots and results into training data using stable netkeiba IDs.
- **Track odds movement** — schedule the `odds` mode every few minutes before post time and watch the market shift.
- **Power apps and dashboards** — English field names mean no Japanese knowledge is required downstream.
- **Feed AI agents** — let an agent pull live Japanese racing data on demand.
- **Research and media** — structured data on the circuit that produced Equinox, Almond Eye and the Deep Impact line.

### How to use Japan Horse Racing Scraper

1. Click **Try for free** and open the Input tab.
2. Pick a **Data type**: race list, race card, result, or odds.
3. Either set a **Date** (to sweep a whole race day) or paste specific **Race IDs**.
4. Click **Start** and watch the log.
5. When the run finishes, open the **Output** tab and export as JSON, CSV, Excel or HTML — or fetch it from the API.

New to netkeiba race IDs? Run `raceList` mode first with today's date; every returned race includes its `raceId`, ready to paste into the other modes.

### Input

| Field | Type | Description |
|---|---|---|
| `dataType` | select | `raceList`, `raceCard`, `result` or `odds` |
| `date` | string | Race day in JST, e.g. `2026-08-09`. Defaults to today |
| `raceIds` | array | Specific 12-digit race IDs. Overrides `date` |
| `includeOdds` | boolean | Merge live odds into each race card entry |
| `maxRaces` | integer | Safety cap when sweeping a full day (default 40) |
| `maxConcurrency` | integer | Parallel requests, 1–5 |

```json
{
  "dataType": "raceCard",
  "raceIds": ["202601010611"],
  "includeOdds": true
}
```

### Output

Every item carries decoded race metadata (`venue`, `meeting`, `dayOfMeeting`, `raceNumber`), so you never have to parse a race ID yourself. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

```json
{
  "raceId": "202601010611",
  "venue": "Sapporo",
  "raceName": "UHB賞",
  "surface": "turf",
  "distanceMeters": 1200,
  "weather": "晴",
  "going": "良",
  "results": [
    {
      "finishPosition": 1,
      "number": 10,
      "name": "ナムラクララ",
      "sexAge": "牝4",
      "carriedWeightKg": 55.0,
      "jockey": "浜中",
      "time": "1:08.4",
      "last3f": 34.1,
      "winOdds": 3.6,
      "popularity": 1,
      "trainer": "長谷川",
      "trainingCenter": "Ritto",
      "bodyWeightKg": 478,
      "bodyWeightDiff": 6
    }
  ],
  "payouts": {
    "win": { "combinations": ["10"], "payoutsYenPer100": [360] },
    "trifecta": { "combinations": ["10-13-2"], "payoutsYenPer100": [19480] }
  }
}
```

### Data you can extract

| Field | Modes | Description |
|---|---|---|
| `raceId`, `venue`, `raceNumber` | all | Decoded from the 12-digit netkeiba race ID |
| `raceName`, `grade` | all | Race title and G1/G2/G3/Listed grade |
| `surface`, `distanceMeters`, `direction` | card, result | Turf / dirt / jump, distance, track direction |
| `weather`, `going` | card, result | Weather and track condition |
| `horses[]` | card | Frame, number, name, sex/age, carried weight, body weight ± diff |
| `jockey`, `trainer`, `trainingCenter` | card, result | With stable `jockeyId` / `trainerId` |
| `winOdds`, `placeOddsMin/Max`, `popularity` | card, odds | Live odds with official timestamp |
| `finishPosition`, `time`, `margin`, `last3f` | result | Finishing order and sectional times |
| `payouts` | result | Win, place, bracket quinella, quinella, quinella place, exacta, trio, **trifecta** |

### How much does it cost to scrape netkeiba?

This Actor uses **pay per event**, so you pay only for the data you actually pull:

| Event | Price |
|---|---|
| Race card scraped | $0.006 |
| Race result scraped | $0.006 |
| Odds snapshot | $0.003 |
| Race list for a day | $0.01 |

A full JRA Saturday (36 races, cards + results) costs about **$0.43**. Polling odds for one race every 5 minutes across a 3-hour window costs about **$0.11**. Apify's free tier includes $5 of monthly usage, which is enough to try every mode.

### Tips

- **JRA races run mostly on Saturdays, Sundays and public holidays (JST)**, roughly 09:40–16:30, at two or three venues of 12 races each. Weekday runs will simply return nothing.
- A practical schedule: `raceList` in the morning → `raceCard` before post time → `odds` every few minutes → `result` after 17:00 JST.
- Use `raceCard` (not `result`) for upcoming races; results only exist once a race has been run.
- Keep `maxConcurrency` at 3 or lower to stay polite to the source site — the data is the same, and runs rarely get blocked.

### FAQ

**Is scraping netkeiba legal?**
This Actor reads only public pages and a public JSON endpoint — no login, no paywall bypass, and a handful of polite requests per race. Web scraping of publicly available data is generally lawful in many jurisdictions, but you are responsible for complying with the source site's terms and your local regulations. It is analytics tooling, not betting advice.

**Does it cover local (NAR) racing?**
Currently JRA (central) racing only. Open an issue if you need NAR — it is on the roadmap.

**Why is `passageOrder` sometimes missing?**
netkeiba does not render passage positions on the standard result view for every race. All other result fields are always populated once a race has run.

**Something broke or you need another field?**
Use the **Issues** tab on this Actor. Site layouts change, and fixes usually ship within a day. Custom Japanese data sources can also be built on request.

### Other Actors by Data Mill

- [YouTube Transcript Scraper](https://apify.com/datamill/youtube-transcript-scraper) — bulk transcripts, subtitles and RAG chunks from videos, playlists and channels
- [Mercari Sold Price Scraper](https://apify.com/datamill/mercari-sold-price-scraper) — verified sold prices across Mercari, Yahoo Auctions and PayPay Flea Market
- [Japan Hotel Scraper](https://apify.com/datamill/jalan-hotel-scraper) — Jalan rates, ratings and plans, including ryokan the global OTAs never list

All of them return clean English-keyed JSON and are maintained the same way.

# Actor input Schema

## `dataType` (type: `string`):

What to scrape: `raceList` (all races for a date), `raceCard` (shutuba entries with horses, jockeys, weights), `result` (finishing order, times, payouts) or `odds` (live win/place odds from the official odds API).

## `date` (type: `string`):

Race day in JST, e.g. `2026-08-09`. Used to discover race IDs when `raceIds` is empty. Defaults to today (Japan time). JRA races run mostly on weekends.

## `raceIds` (type: `array`):

Specific netkeiba race IDs (12 digits, e.g. `202601010611`). When provided, `date` is ignored. Find IDs in netkeiba URLs (`race_id=...`) or run this Actor in `raceList` mode first. Clear this field to sweep a whole race day instead.

## `includeOdds` (type: `boolean`):

When scraping race cards, also fetch live win/place odds from the odds API and merge them into each horse entry.

## `maxRaces` (type: `integer`):

Safety cap when scraping a whole day by date (a busy JRA Saturday has ~36 races). Ignored when you pass explicit `raceIds`.

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

Parallel requests against netkeiba. Keep low to stay polite.

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

Proxy settings. Netkeiba is generally accessible without proxies; enable Apify Proxy if you run into blocking.

## Actor input object example

```json
{
  "dataType": "raceCard",
  "raceIds": [
    "202601010611"
  ],
  "includeOdds": true,
  "maxRaces": 40,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "raceIds": [
        "202601010611"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datamill/netkeiba-race-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 = {
    "raceIds": ["202601010611"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("datamill/netkeiba-race-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 '{
  "raceIds": [
    "202601010611"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call datamill/netkeiba-race-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datamill/netkeiba-race-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/PDszURLcRJp7dsbct/builds/zAkO5bxtvkTXhFSer/openapi.json
