# Sporting Life Scraper - Racecards, Results & Odds API (`parseforge/sporting-life-racing-scraper`) Actor

Scrape Sporting Life horse racing: racecards, results, runners, weights, official ratings, Timeform commentary, bookmaker odds, tote payouts, and horse, jockey and trainer profiles. UK, Ireland, France and USA. No login, no API key, no proxy.

- **URL**: https://apify.com/parseforge/sporting-life-racing-scraper.md
- **Developed by:** [ParseForge](https://apify.com/parseforge) (community)
- **Categories:** Other, AI, Developer tools
- **Stats:** 3 total users, 2 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/actors/running/actors-in-store.md#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

[![ParseForge](https://raw.githubusercontent.com/ParseForge/apify-assets/main/banner.jpg)](https://apify.com/parseforge?fpr=vmoqkp)

### Sporting Life Scraper - Racecards, Results & Odds API

**Scrape Sporting Life horse racing: racecards, results, runners, odds, and form.** Every runner comes with its weight, official rating, draw, headgear, trainer, jockey, owner, market price, Timeform commentary, and finishing position. UK, Irish, French, and US cards, with results going back two decades. No login, no API key, no cookies, and no proxy. Export to CSV, JSON, Excel, or XML.

Sporting Life publishes the Press Association and Timeform racing feed to anonymous visitors. This reads that same public feed, filters it by course, country, class, going, price, or connections, and returns each match in one flat schema.

| Who uses it | What they scrape Sporting Life for |
|---|---|
| Betting modellers | Runner-level training data with prices, ratings, and results in one row |
| Tipsters and analysts | Today's cards with Timeform verdicts, market moves, and best available odds |
| Odds comparison sites | Live prices from every bookmaker on the card, refreshed per race |
| Racing media and bloggers | Fast results, tote payouts, and replays minutes after the weigh-in |
| Bloodstock and form researchers | Twenty years of results with pedigree, connections, and full form lines |

### What it does

This Actor collects public Sporting Life racing data from four source types — race days, individual races, profile IDs, and any sportinglife.com racing URL — and returns each runner as a flat row. Every runner carries:

- 🏇 **The runner:** horse name, age, sex, cloth number, draw, weight carried in stones and pounds, official rating, headgear, medication, and jockey's claim.
- 🏁 **The result:** finishing position, distance beaten, winner and placed flags, and the reason a horse did not complete.
- 💷 **The market:** starting price as fraction and decimal, implied probability, opening price, full price history, market move, favourite flag, and market rank.
- 🧠 **Timeform's words:** the pre-race commentary for each runner, the race verdict with its selections, and the in-running comment after the race.
- 👥 **Connections:** trainer, jockey, and owner, each with the ID and profile URL to follow up.
- 🗓️ **Race and meeting context:** course, country, surface, going, distance in yards, class, age band, handicap flag, prize money, field size, weather, and off time.
- 🎟️ **Tote returns:** win, place, exacta, trifecta, tricast, swingers, straight forecast, placepot, and quadpot on settled races.
- 📈 **Computed signals:** decimal odds, implied probability, market rank, lifetime win percentage, and distance in yards, ready to sort.

Results export to CSV, JSON, Excel, or XML, or stream from the API.

### What you can do with Sporting Life data

**🧮 Build a racing model.**

Pull several seasons of results with `includeHorseForm` and get every runner's weight, rating, going, draw, and starting price alongside where it finished.

**📊 Compare bookmaker prices on today's card.**

Tick `includeBookmakerOdds` and each runner arrives with every firm's fractional and decimal price, each-way terms, places paid, and the best price on offer.

**🔔 Watch one trainer or jockey.**

Set `trainerNameContains` or `jockeyNameContains` and schedule the run daily to get only their runners, with prices and results.

**⏱️ Read today's results as they land.**

Sporting Life's fast-results feed settles within a minute of the weigh-in. Run the same day with `raceStages: ["WEIGHEDIN"]` and every finished race arrives with its finishing order, distances beaten, and tote returns.

**🏆 Track a course or a festival.**

Set `courses` and a date range to collect a whole meeting, or use `outputMode: meetings` for one row per race day with its card nested.

**📜 Rebuild a historical archive.**

Results reach back to early 2005, solid from that April. Run a month at a time and page through the years.

### Why choose this scraper

| | What you get |
|---|---|
| **No login, ever** | No account, no cookies, no session to keep alive. Nothing to get banned. |
| **No proxy cost** | Sporting Life serves this feed to anonymous clients, so there is no proxy line on your bill. |
| **Timeform words included** | Per-runner commentary and the race verdict, not just numbers. |
| **Four countries, one run** | Britain, Ireland, France, and the United States on the same card listing. |
| **Twenty years of results** | Racecards run about five days ahead; results go back to early 2005. |
| **Three row shapes** | One row per runner, per race with runners nested, or per meeting with the card nested. |
| **Filters that cut noise** | Course, country, class, surface, going, prize, time, rating, age, price, and connections. Only matching rows are written and billed. |
| **Opt-in extras, off by default** | Bookmaker odds, form history, pedigree, replays, naps, and articles are each a checkbox. Leave them off and you are never billed for them. |

### How it compares

Be clear about the trade-off before you pick this one.

**This Actor covers the cards Sporting Life publishes.** That is Britain, Ireland, France, and a US selection. It is not a global feed: for Japanese, Hong Kong, or Australian racing you need a scraper built on those sites.

| Feature | ParseForge | jungle\_synthesizer | alaricus | 0xgollum |
|---|---|---|---|---|
| Source | Sporting Life (UK, IRE, FR, US) | Equibase (US) | HKJC (Hong Kong) | Mixed feeds |
| Runner-level rows with weights and ratings | Yes | Yes | Yes | Partial |
| Timeform commentary and race verdict | Yes | No | No | No |
| Live bookmaker prices, multiple firms | Optional | No | No | No |
| Tote, exacta, trifecta, placepot returns | Yes | Partial | Yes | No |
| Full form history per runner | Optional | Optional | No | No |
| Horse, jockey, and trainer profile rows | Yes | Yes | No | No |
| Historical archive depth | Back to early 2005 | Recent | Recent | Recent |
| Price per 1,000 runners | $7.00 | ~$1.00 | ~$15.00 | Not published |

The per-runner price is the honest headline: this Actor costs about seven times the cheapest US racing scraper on the Store. What the difference buys is the columns above — Timeform's written analysis, live multi-bookmaker prices, tote returns, and a two-decade archive — on a feed that never needs a proxy. If your job is bulk US chart data at the lowest unit price, use theirs.

### What a runner row looks like

```json
{
  "recordType": "runner",
  "meetingId": 120938,
  "meetingDate": "2026-08-24",
  "courseId": 301,
  "courseName": "Brighton",
  "countryCode": "ENG",
  "countryName": "England",
  "meetingGoing": "Good to Firm (Good in places)",
  "meetingSurface": "Turf",
  "weather": "Fine",
  "raceId": 934627,
  "raceName": "Blackmore Building Contractors Handicap",
  "raceUrl": "https://www.sportinglife.com/racing/results/2026-08-24/brighton/934627/blackmore-building-contractors-handicap",
  "raceDate": "2026-08-24",
  "raceTime": "13:30",
  "offTime": "13:30:12",
  "raceType": "FLAT",
  "raceClass": "5",
  "ageBand": "4YO plus",
  "distance": "5f 60y",
  "distanceYards": 1160,
  "surface": "TURF",
  "going": "Good to Firm (Good in places)",
  "isHandicap": true,
  "raceStage": "WEIGHEDIN",
  "declaredRunners": 6,
  "winningTime": "1m 0.75s",
  "winningTimeSeconds": 60.75,
  "verdict": "SOUTH SHORE has made a positive start for his present stable...",
  "firstPrize": 4187,
  "prizeCurrency": "GBP",
  "totalPrize": 7870,
  "placesPaid": 2,
  "bookPercentage": 111.12,
  "toteWin": "5.0 GBP",
  "toteExacta": "14.2 GBP",
  "placepot": "136.8 GBP",
  "rideId": 251626285,
  "clothNumber": 1,
  "drawNumber": 5,
  "finishPosition": 1,
  "finishDistance": null,
  "isWinner": true,
  "isPlaced": true,
  "horseId": 1165390,
  "horseName": "Em Four",
  "horseUrl": "https://www.sportinglife.com/racing/profiles/horse/1165390",
  "horseAge": 4,
  "horseSexLabel": "Gelding",
  "foaledDate": "2022-03-28",
  "daysSinceLastRun": 35,
  "formSummary": "135785",
  "weight": "9-9",
  "weightPounds": 135,
  "officialRating": 74,
  "headgear": [],
  "ownerName": "Mr J A Osborne",
  "trainerId": 197,
  "trainerName": "J A Osborne",
  "jockeyId": 29850,
  "jockeyName": "Saffie Osborne",
  "odds": "4/1",
  "oddsDecimal": 5,
  "impliedProbability": 20,
  "openingOdds": "7/2",
  "oddsHistory": ["4/1", "7/2", "10/3", "7/2"],
  "betMovement": "tchd 10/3",
  "isFavourite": false,
  "marketRank": 3,
  "lifetimeRuns": 33,
  "lifetimeWins": 7,
  "lifetimeWinPercent": 21.2,
  "commentary": "Won 3 times on all-weather earlier in the year and arrives in good heart...",
  "runningComment": "Mounted in chute, wore hood and went early to post, midfield, progress over 2f out...",
  "silkUrl": "https://www.sportinglife.com/images/silks/20260824bgh143001.png",
  "fieldSize": 6,
  "scrapedAt": "2026-08-25T16:44:43.346Z"
}
```

Upcoming races have no `finishPosition`, `winningTime`, or tote returns yet, and settled races no longer carry live bookmaker prices. `raceType` is stated by the feed only once a race has run, so it is `null` on tomorrow's card. Those are the data's real state, not gaps in the parser.

### Configure the run

Drive the Actor from four source types, alone or together: a date range, Sporting Life URLs, race IDs, and horse, jockey, or trainer IDs. Filters run as each race and runner is read, so only matches reach your dataset. With nothing set it scrapes today's racecards. The Input tab lists every parameter.

Today's card for two courses:

```json
{ "dateFrom": "2026-08-26", "courses": ["Ascot", "Newmarket"], "maxItems": 300 }
```

A week of results, with each horse's form history attached:

```json
{ "dateFrom": "2026-08-01", "dateTo": "2026-08-07", "raceStages": ["WEIGHEDIN"], "includeHorseForm": true, "maxItems": 5000 }
```

Tomorrow's Irish card with every bookmaker's price:

```json
{ "dateFrom": "2026-08-27", "countries": ["Eire"], "includeBookmakerOdds": true, "maxItems": 400 }
```

One trainer's runners over a season, winners only:

```json
{ "dateFrom": "2026-04-01", "dateTo": "2026-09-30", "trainerNameContains": ["Appleby"], "finishPositions": ["winner"], "maxItems": 2000 }
```

A single race by URL, with replay and last year's winners:

```json
{ "startUrls": ["https://www.sportinglife.com/racing/racecards/2026-08-26/catterick/racecard/934971/berber-leather-maiden-stakes"], "includeVideos": true, "includeLastYearsWinners": true }
```

### Pricing

Pay-per-event: **$0.007 per runner**, plus a $0.01 fee per race day scanned and a $0.03 run-start fee. You pay only for rows written to your dataset. Every optional block is a separate event that is charged only when you tick its checkbox.

| Runners collected | Approximate cost |
|---|---|
| 100 | $0.74 |
| 1,000 | $7.04 |
| 10,000 | $70.13 |

Choosing `outputMode: races` bills **$0.05 per race** instead, with the whole field nested in one row. On an average nine-runner card that is cheaper than per-runner billing; on a five-runner field it is dearer. `outputMode: meetings` bills $0.02 per meeting.

Optional blocks: bookmaker odds $0.003 per runner, form history $0.003 per runner, horse profile and pedigree $0.008 per horse, race replay $0.003 per race with a direct MP4, tipster nap $0.003 per row, article $0.004 per row. Standalone jockey and trainer profile rows are $0.008 each.

New Apify accounts start with $5 in free credit.

### Free users

Free-plan runs return up to 10 rows as a preview. [Upgrade your Apify plan](https://console.apify.com/sign-up?fpr=vmoqkp) to collect up to 1,000,000 rows per run.

### Run it

1. [Create a free Apify account with $5 in credit](https://console.apify.com/sign-up?fpr=vmoqkp).
2. Open the [Sporting Life Racing Scraper](https://apify.com/parseforge/sporting-life-racing-scraper?fpr=vmoqkp).
3. Set `dateFrom` and `dateTo`, or paste Sporting Life URLs, add any filters, and click **Start**.
4. Export the results as CSV, Excel, JSON, or XML from the **Dataset** tab.

Run it programmatically through the [Apify API](https://docs.apify.com/api/v2) or the [ApifyClient](https://docs.apify.com/api/client/js) for JavaScript and Python.

### Use with AI agents (MCP)

Give an AI agent live access to racing data through the Model Context Protocol. Add the Actor to Claude, Cursor, or any MCP client:

```bash
claude mcp add --transport http apify "https://mcp.apify.com?tools=parseforge/sporting-life-racing-scraper"
```

Then prompt it in plain language:

- *"Pull today's Ascot card and list every runner with its price and official rating."*
- *"Get last Saturday's British results and tell me which favourites won."*
- *"Compare bookmaker prices for tomorrow's 15:30 at Newmarket."*

Copy this into ChatGPT, Claude, or Cursor to start:

```
Use the Apify Actor "parseforge/sporting-life-racing-scraper" to collect horse racing data from Sporting Life. Input: { "dateFrom": "<YYYY-MM-DD>", "dateTo": "<YYYY-MM-DD>", "courses": ["<course>"], "countries": ["<country>"], "includeBookmakerOdds": <true|false>, "maxItems": <n> }. It returns one row per runner with horse, age, weight, official rating, trainer, jockey, odds, Timeform commentary, finishing position, and race and meeting context. Call it with the ApifyClient and my APIFY_TOKEN.
```

### Troubleshooting

**Why am I getting no results?**

Check the date. There is no racing on some days, and racecards are only published about five days ahead — a date further out returns nothing but the odd early entry for a big autumn race. Filters stack, so a course plus a class plus a going term can leave zero races; drop them one at a time.

**Why are the bookmaker odds empty?**

Prices are live markets with a narrow window. Firms price up on the morning of the race, so a card pulled the night before returns `SP` from every firm and no usable price — that costs you nothing, because the block only bills when a real price is delivered. Once a race is settled the market is gone. Use the starting price in `odds` and `oddsDecimal` for past races.

**Why is a replay URL missing?**

Sporting Life carries two video providers. Racing TV courses ship a direct MP4, which lands in `replayUrl`. At The Races courses ship only a host-less provider path, which lands in `replayStreamPath` and is never billed. About 45% of replays are direct MP4s.

**Why is `raceType` null?**

Sporting Life states flat, hurdle, or chase only in a horse's own form lines, which means it resolves once a race has been run. Tomorrow's card does not have it yet.

**Why fewer rows than I asked for?**

`maxItems` is a ceiling, not a target. The day may hold fewer runners than that, or your filters removed them. Widen the date range or relax the filters.

**Why is the run slow?**

`includePedigree` and `includeFutureEntries` fetch one profile per horse, which multiplies requests on a big card. Turn them off for bulk runs, or lower `racesPerDay`.

**A field stopped filling.**

Sporting Life changed its public response shape. Email us with your run ID so we can update the parser.

### FAQ

| Question | Answer |
|---|---|
| Do I need a Sporting Life account or API key? | No. It reads the public racing feed, so there is no login, cookie, or token to manage. |
| Which countries are covered? | Britain, Ireland, France, and a United States selection, as published on Sporting Life's own card listing. |
| How far back do results go? | To early 2005, solid from that April. Racecards run about five days into the future. |
| Can I get odds from more than one bookmaker? | Yes. Tick `includeBookmakerOdds` and each runner returns every firm Sporting Life carries, plus the best price and who offers it. |
| Can I download race replays? | Partly. Tick `includeVideos`: Racing TV courses return a direct MP4 URL, At The Races courses return only a provider path with no host. You are billed only for the usable MP4s. |
| Does it return the full form history? | Yes, with `includeHorseForm`: each previous run's date, course, distance, going, weight, rating, starting price, and the in-running comment. |
| Can I filter by trainer, jockey, or owner? | Yes, by partial name. Filters run before rows are written, so only matches are billed. |
| Is a proxy needed? | No. The feed answers anonymous datacenter requests, so the proxy field can stay off. |
| How many rows per run? | Free plan: 10. Paid: up to 1,000,000, bounded by what the cards and filters return. |
| What is `marketRank`? | The runner's price position in its own race, 1 being the shortest. Computed here, not published by Sporting Life. |
| How is the favourite decided? | Sporting Life flags it only once a race has run. On an upcoming card `isFavourite` falls back to the shortest price, which agreed with the flag on every settled race tested. Joint favourites all get the flag. |
| Is this an official Sporting Life product? | No. It is unofficial and reads only publicly available Sporting Life data. |

### Related actors

- [Equibase Scraper](https://apify.com/parseforge/equibase-scraper?fpr=vmoqkp): US horse racing entries, results, and charts.
- [FanDuel Sportsbook Odds Scraper](https://apify.com/parseforge/fanduel-scraper?fpr=vmoqkp): live sportsbook markets and prices.
- [TheSportsDB Scraper](https://apify.com/parseforge/thesportsdb-scraper?fpr=vmoqkp): teams, players, and fixtures across sports.
- [Reddit Posts Scraper](https://apify.com/parseforge/reddit-posts-scraper?fpr=vmoqkp): posts, scores, and comments from any subreddit.
- [X.com (Twitter) Post Scraper](https://apify.com/parseforge/x-com-scraper?fpr=vmoqkp): public X posts by profile, URL, or list.

Browse the full [ParseForge collection](https://apify.com/parseforge?fpr=vmoqkp) for more scrapers.

🆘 **Need help?** Email parseforge@protonmail.com with your run ID, your input, and what you expected.

⚠️ **Disclaimer.** This Actor is unofficial and is not affiliated with, endorsed by, or sponsored by Sporting Life, Sky Betting & Gaming, or Timeform. It collects only publicly available Sporting Life data. You are responsible for using the data in compliance with Sporting Life's terms and applicable laws, including GDPR, CCPA, and PIPL. Gambling carries risk; nothing here is betting advice.

# Actor input Schema

## `dateFrom` (type: `string`):

First race day to collect, as YYYY-MM-DD. Racecards are published about five days ahead and results go back to early 2005. Leave both dates empty to scrape today.

Example: 2026-08-24

## `dateTo` (type: `string`):

Last race day to collect, as YYYY-MM-DD, inclusive. Leave empty to use the same day as Date from.

Example: 2026-08-26

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

Any sportinglife.com racing URL: a racecard, a result, a race-day listing, or a horse, jockey, or trainer profile. Each one is recognised automatically.

Examples:

- https://www.sportinglife.com/racing/racecards/2026-08-26/catterick/racecard/934971/berber-leather-maiden-stakes
- https://www.sportinglife.com/racing/results/2026-08-24
- https://www.sportinglife.com/racing/profiles/horse/em-four/1165390

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

Numeric Sporting Life race IDs to fetch in full, without going through a race-day listing.

Example: 934971

## `horseIds` (type: `array`):

Numeric horse IDs. Each one returns a profile row with pedigree, career record, full form, and upcoming entries.

Example: 1165390

## `jockeyIds` (type: `array`):

Numeric jockey IDs. Each one returns a profile row with recent rides, strike rate, and upcoming bookings.

Example: 29850

## `trainerIds` (type: `array`):

Numeric trainer IDs. Each one returns a profile row with recent runners, strike rate, and upcoming entries.

Example: 197

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

What one dataset row represents. Runner is the flat, spreadsheet-friendly shape and the default.

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

Total rows to write in this run. Free Apify plans return a 10-row preview.

## `racesPerDay` (type: `integer`):

Cap the races taken from each day's card so one busy Saturday cannot use up the whole run. Leave empty to take every race that passes the filters.

## `countries` (type: `array`):

Keep only meetings in these countries. Matches the country name or its short code, case-insensitive.

Available: England, Scotland, Wales, Eire, Northern Ireland, France, United States, plus other international cards the feed carries.

## `courses` (type: `array`):

Keep only these racecourses. Full or partial name, case-insensitive.

Examples:

- Ascot
- Newmarket
- Cheltenham

## `surfaces` (type: `array`):

Keep only races run on these surfaces.

## `raceClasses` (type: `array`):

Keep only these British race classes. Class 1 is the highest. Irish, French, and US races usually carry no class.

## `raceStages` (type: `array`):

Keep only races at these stages. DORMANT is an upcoming race, OFF is running, WEIGHEDIN and RESULT are settled.

## `handicapFilter` (type: `string`):

Keep handicaps only, non-handicaps only, or both.

## `raceNameContains` (type: `array`):

Keep only races whose name contains at least one of these terms. Case-insensitive.

Examples:

- Hurdle
- Chase
- Group 1
- Maiden

## `goingContains` (type: `array`):

Keep only races whose going description contains at least one of these terms. Case-insensitive.

Examples:

- Good to Firm
- Soft
- Standard

## `minRunners` (type: `integer`):

Drop races with fewer declared runners than this.

## `maxRunners` (type: `integer`):

Drop races with more declared runners than this.

## `minPrize` (type: `number`):

Drop races whose first-place prize is below this. The number is in the race's own currency (GBP, EUR, or USD), which is reported as prizeCurrency.

## `timeFrom` (type: `string`):

Keep only races off at or after this local course time, as HH:MM.

Example: 14:00

## `timeTo` (type: `string`):

Keep only races off at or before this local course time, as HH:MM.

Example: 18:30

## `horseNameContains` (type: `array`):

Keep only runners whose horse name contains at least one of these terms. Case-insensitive.

## `trainerNameContains` (type: `array`):

Keep only runners from trainers whose name contains at least one of these terms. Case-insensitive.

Example: Appleby

## `jockeyNameContains` (type: `array`):

Keep only runners ridden by jockeys whose name contains at least one of these terms. Case-insensitive.

Example: Moore

## `ownerNameContains` (type: `array`):

Keep only runners whose owner name contains at least one of these terms. Case-insensitive.

Example: Godolphin

## `minOfficialRating` (type: `integer`):

Drop runners rated below this by the handicapper. Unrated horses are dropped when this is set.

## `maxOfficialRating` (type: `integer`):

Drop runners rated above this by the handicapper.

## `minAge` (type: `integer`):

Drop runners younger than this, in years.

## `maxAge` (type: `integer`):

Drop runners older than this, in years.

## `minOddsDecimal` (type: `number`):

Drop runners priced shorter than this, in decimal odds including the stake. Accepts decimals: 3.5 means 5/2 or bigger.

## `maxOddsDecimal` (type: `number`):

Drop runners priced longer than this, in decimal odds including the stake. Accepts decimals: 6.5 means 11/2 or shorter.

## `favouritesOnly` (type: `boolean`):

Keep only the favourite in each race. Sporting Life flags the favourite only once a race has run, so on an upcoming card the shortest price in the race is used instead. Joint favourites all match. Verified to agree with the flag on every settled race tested.

## `finishPositions` (type: `array`):

For settled races, keep only runners with these outcomes. Leave empty to keep every runner.

## `includeNonRunners` (type: `boolean`):

Keep withdrawn horses as rows, flagged with isNonRunner. Off by default so the dataset holds only horses that actually take part.

## `includeBookmakerOdds` (type: `boolean`):

Add live prices from every bookmaker Sporting Life carries, plus the best available price and its bookmaker, to each runner. One extra request per race. Firms price up on the morning of the race: before that they answer SP and no price is returned or billed, and once a race is settled the market is gone.

## `includeHorseForm` (type: `boolean`):

Add each horse's previous runs as a nested form array: date, course, distance, going, position, weight, official rating, starting price, and the in-running comment.

## `includePedigree` (type: `boolean`):

Add sire, dam, damsire, and coat colour to each runner. Costs one profile request per horse, so it makes big runs noticeably slower.

## `includeFutureEntries` (type: `boolean`):

Add the races each horse is already entered for, with date, course, distance, and race name. Reads the horse profile, so it costs one request per horse and shares that request with Pedigree.

## `includeVideos` (type: `boolean`):

Add the race replay and its caption. Racing TV courses return a direct MP4 in replayUrl; At The Races courses return only a host-less provider path in replayStreamPath, which is reported but never billed.

## `includeLastYearsWinners` (type: `boolean`):

Add the previous runnings' winners of the same race, with trainer, jockey, weight carried, and starting price.

## `includeTipsterNaps` (type: `boolean`):

Also write the naps table: every national tipster's nap of the day with their running wins, losses, and profit to level stakes.

## `includeArticles` (type: `boolean`):

Also write Sporting Life's racing tips and news articles with title, author, snippet, and publish date.

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

How many race cards to fetch at once. The default suits every run; lower it only if you are routing through a slow proxy.

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

Optional. The site does not block datacenter traffic, so leaving this off costs you nothing and saves the proxy line on your bill.

## Actor input object example

```json
{
  "outputMode": "runners",
  "maxItems": 100,
  "handicapFilter": "any",
  "favouritesOnly": false,
  "includeNonRunners": false,
  "includeBookmakerOdds": false,
  "includeHorseForm": false,
  "includePedigree": false,
  "includeFutureEntries": false,
  "includeVideos": false,
  "includeLastYearsWinners": false,
  "includeTipsterNaps": false,
  "includeArticles": false,
  "maxConcurrency": 12,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Every collected runner, race, or meeting with its meeting, race, horse, trainer, jockey, market and result fields

# 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 = {
    "dateFrom": "",
    "dateTo": "",
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("parseforge/sporting-life-racing-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 = {
    "dateFrom": "",
    "dateTo": "",
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("parseforge/sporting-life-racing-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 '{
  "dateFrom": "",
  "dateTo": "",
  "maxItems": 100
}' |
apify call parseforge/sporting-life-racing-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parseforge/sporting-life-racing-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/jq7bccncrXyuEbkOW/builds/ZdYWLNVGOavi9hrcy/openapi.json
