Equibase Horse Racing Scraper
Pricing
from $0.69 / 1,000 records
Equibase Horse Racing Scraper
Scrape Equibase horse racing data: race entries, results, finish order, win/place/show and exotic payouts, scratches and race-day changes for every US and Canadian track, plus horse histories. Export JSON, CSV or Excel.
Pricing
from $0.69 / 1,000 records
Rating
0.0
(0)
Developer
ParseBird
Maintained by CommunityActor stats
1
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Equibase Horse Racing Scraper
Equibase Horse Racing Scraper extracts race entries, results and payouts from Equibase, the official database of North American Thoroughbred racing. It covers every US, Canadian and Puerto Rico track Equibase lists for a date and returns runners, jockeys, trainers, morning line odds, finish order, win/place/show and exotic payouts, scratches and race-day changes.
| Pick a date and get one clean record per race: the card with pedigree, owner, breeder, weight, medication and morning line for every runner, plus the official finish order, $2 win/place/show prices and every exotic payout (exacta, trifecta, superfecta, daily double, Pick 3 to Pick 6). Add horse histories with every career start, its Equibase Speed Figure and the last 60 days of workouts. |
Copy to your AI assistant
Copy this block into ChatGPT, Claude, Cursor or any other LLM to start using this Actor.
Use the Apify Actor "parsebird/equibase-horse-racing-scraper" (Equibase Horse Racing Scraper) to get horse racing entries, results, payouts and race-day changes from equibase.com for US, Canadian and Puerto Rico tracks. Call it with the apify-client package: Python `ApifyClient("<APIFY_TOKEN>").actor("parsebird/equibase-horse-racing-scraper").call(run_input={...})`, or JavaScript `new ApifyClient({ token }).actor('parsebird/equibase-horse-racing-scraper').call({...})`, then read items from the run's default dataset. Inputs (all optional): raceDate (string "MM/DD/YYYY" or "YYYY-MM-DD", default today in US Eastern time; results exist for about the last 30 days, entries for the coming days), dataMode ("both" default, "entries", "results", "late_changes" = today's scratches and changes), trackCodes (array of Equibase track codes, e.g. ["SA","GP","KEE","CD","BEL","SAR","WO"]; default all tracks), maxItems (int, default 50, max records saved), raceTypes (array of words matched against race type and name, e.g. ["claiming"], ["maiden"], ["stakes"], ["grade"]), filliesMaresOnly (bool, default false), includeHorseHistory (bool, default false: adds one horse_history record per runner), maxHorseProfiles (int, default 100), proxyConfiguration (object, default no proxy). Race records (record_type "race") have race_id (e.g. "KEE-2026-10-31-R12"), race_date, track_code, track_name, country, race_number, race_name, race_type, race_category, grade, breed, distance, distance_furlongs, surface, track_condition, purse, purse_currency, post_time, off_time, age_sex_restriction, conditions, wagers, entries_count, starters_count, scratched_count, entries (pipe string "program|horse|jockey|trainer|weight|morning line" joined by " | "), entries_detail (array: program_number, post_position, horse_name, horse_refno, sire, dam, dam_sire, age, sex, medication, claim_price, jockey, trainer, owner, breeder, weight, morning_line, is_scratched, scratch_reason, finish_position, win/place/show payouts), results_available, winner_horse, winner_jockey, winner_trainer, winner_owner, winner_breeder, winning_time, finish_order, finish_order_detail, win_payout, place_payout, show_payout, payouts_by_horse, exotic_payouts (JSON string {bet_type: payoff}), exotic_payouts_by_type (object with raw_label, wager_amount, winning_numbers, payoff), race_cancelled, cancellation_reason, entry_url, result_url. Race-day change records (record_type "late_change") have change_id, track_code, race_date, race_id, race_number, program_number, horse_name, change_type (scratch, scratch_reason, jockey, weight, overweight, apprentice_type, course_change, distance, owner, rail, first_start_as_gelding, coupled_entry, wagering, race_cancelled, track_conditions, announcement, note), old_value, new_value, reason, time_posted, time_posted_at. Horse history records (record_type "horse_history") have horse_refno, horse_name, sire, dam, dam_sire, foaled, sex, color, breeder, last_owner, last_trainer, last_jockey, career_starts, career_wins, career_seconds, career_thirds, career_earnings_usd, past_starts (race_date, track_name, race_number, race_type, finish_position, speed_figure) and workouts (date, track_name, distance, time, note, rank) from the last 60 days. Pricing: pay per record; horse histories are premium records. API docs: https://apify.com/parsebird/equibase-horse-racing-scraper/api. Get a token at https://console.apify.com/settings/integrations.
What is Equibase Horse Racing Scraper?
Equibase Horse Racing Scraper turns Equibase race cards and result charts into structured JSON, CSV or Excel. Pick a date, and the Actor finds every track racing that day in the United States, Canada and Puerto Rico, reads each race card and results summary, and saves one record per race with the full field of runners, the official order of finish and all payouts.
It works as an Equibase API alternative. Equibase sells its data feeds to businesses but has no free public API, so Equibase Horse Racing Scraper collects the entries, results and race-day changes that Equibase publishes on its free website pages and hands them to you as a dataset.
To try it, open the Input tab and click Start. The prefill returns 20 races from today's cards. If no track races today, the Actor uses the next race day.
What can Equibase Horse Racing Scraper do?
- π Race entries: every runner with program number, post position, horse, pedigree (sire, dam, dam sire), age, sex, state or country bred, medication, weight, claiming price, jockey, trainer, owner, breeder and morning line odds.
- π Results and payouts: official order of finish, winning time, winner's jockey, trainer, owner and breeder, $2 win/place/show prices for the top three and every exotic payout on the chart, including exacta, trifecta, superfecta, Super High Five, daily double, Pick 3, Pick 4, Pick 5 and Pick 6 with the winning numbers.
- β οΈ Race-day changes: scratches with reasons, jockey changes, weight and overweight changes, surface and distance switches, rail settings, track conditions and track announcements, one record per change with the time Equibase posted it.
- π Race details: race type, stakes name and grade, distance as text and in furlongs, surface, track condition, purse with currency (USD or CAD), post time, age and sex restrictions, full race conditions and the wagers offered.
- π Horse histories: profile, career record and earnings, every career start with its finish and Equibase Speed Figure, and workouts from the last 60 days for each horse in the races you saved.
- π Filters: keep only certain tracks, race types (claiming, maiden, allowance, stakes, graded stakes) or races for fillies and mares.
- β Cancellations: races Equibase lists as cancelled are flagged with
race_cancelledand the reason. - βοΈ Built for automation: schedule runs every morning for the day's cards or every evening for the results, call the Actor through the Apify API, send results to Make, Zapier, n8n, Google Sheets, Slack and more, and export as JSON, CSV, Excel or HTML.
What data can you extract from Equibase?
Race records (record_type: race):
| Field | Description |
|---|---|
race_id | Track, date and race number, for example KEE-2026-10-31-R12 |
race_date, track_code, track_name, country | Race date, Equibase track code, track name and USA, CAN or PR |
race_number, race_name, race_type, race_category, grade | Race number, stakes name (or race type), race type such as Maiden Claiming, a broad category and the stakes grade (1, 2, 3) |
breed | Thoroughbred, or the breed Equibase shows for other races, such as Quarter Horse |
distance, distance_furlongs, surface, track_condition | Distance as text (1 1/16 Miles) and in furlongs, Dirt, Turf or All Weather, and condition such as Fast or Firm |
purse, purse_currency | Purse amount, in CAD for Canadian tracks and USD elsewhere |
post_time, off_time | Scheduled post time (ET) and the time the race went off |
age_sex_restriction, conditions, wagers | Short restriction such as 3yo+ F&M, full race conditions and the wagers offered |
entries_count, starters_count, scratched_count | Horses entered, horses that started and scratches |
entries | Compact pipe string: `post |
entries_detail | One object per horse: program number, post position, horse, Equibase ID, sire, dam, dam sire, age, sex, medication, claiming price, jockey, trainer, owner, breeder, weight, morning line, scratch and reason, finish position and payouts |
winner_horse, winner_jockey, winner_trainer, winner_owner, winner_breeder, winning_time | Winner details from the results chart |
finish_order, finish_order_detail | Order of finish as text and as a list with program numbers, Equibase IDs and dead-heat flags |
win_payout, place_payout, show_payout, payouts_by_horse | The winner's $2 win/place/show prices, and the place and show prices of the second and third horses |
exotic_payouts, exotic_payouts_by_type | Exotic payoffs as a JSON string ({"exacta": 31.3, ...}) and as an object with the bet label, base amount and winning numbers |
race_cancelled, cancellation_reason | Cancellation flag and reason from Equibase's cancellations list |
entry_url, result_url, scraped_at | Source pages on Equibase and collection time |
Race-day change records (record_type: late_change) have change_type, old_value, new_value, reason, race_number, program_number, horse_name, time_posted and time_posted_at (UTC). Horse history records (record_type: horse_history) have the horse's profile, career totals, past_starts and workouts.
Fields that a record doesn't have are null. A race card for a future date has no results yet, and a results-only record has no morning line or race conditions.
How to scrape Equibase
- Open Equibase Horse Racing Scraper on Apify Store and go to the Input tab.
- Set Race date, or leave it empty for today.
- Choose Data: entries and results, entries only, results only, or today's race-day changes.
- Optionally add Track codes such as
SA,GPorKEE, and Race types such asclaimingorstakes. - Set Max records. A full day across all tracks is often more than 100 races, so use 500 to get the whole day.
- Turn on Add horse histories if you also want each runner's career and workouts.
- Click Start. When the run finishes, download the dataset as JSON, CSV, Excel or HTML, or read it with the dataset API.
To get results for a whole day, run it in the evening after the last race or for a past date. Results appear on Equibase as races are run.
Input parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
raceDate | string | today (ET) | Date as MM/DD/YYYY or YYYY-MM-DD |
dataMode | string | both | both, entries, results or late_changes |
trackCodes | array | all tracks | Equibase track codes, for example SA, GP, KEE, CD, BEL, SAR, WO |
maxItems | integer | 50 | Maximum race records (or race-day changes) to save |
raceTypes | array | β | Words to match in the race type or name: claiming, maiden, allowance, stakes, grade |
filliesMaresOnly | boolean | false | Keep only races where every runner is a filly or mare |
includeHorseHistory | boolean | false | Add one horse_history record per runner in the saved races |
maxHorseProfiles | integer | 100 | Maximum horse histories per run |
proxyConfiguration | object | no proxy | Optional proxy. The Actor works without one |
Example input for the Breeders' Cup graded stakes at Keeneland, with horse histories:
{"raceDate": "10/31/2026","trackCodes": ["KEE"],"dataMode": "both","raceTypes": ["grade"],"maxItems": 20,"includeHorseHistory": true,"maxHorseProfiles": 30}
Output example
A race record for the 2026 Breeders' Cup Classic. Lists are cut to the first items here to keep the example short.
{"record_type": "race","race_id": "KEE-2026-10-31-R12","race_date": "2026-10-31","track_code": "KEE","track_name": "Keeneland","country": "USA","race_number": 12,"race_name": "Longines Breeders' Cup Classic","race_type": "Stakes","race_category": "Stakes","grade": "1","breed": "Thoroughbred","distance": "1 1/4 Miles","distance_furlongs": 10.0,"surface": "Dirt","track_condition": "Fast","purse": 7000000,"purse_currency": "USD","post_time": "6:16 PM ET","off_time": "6:19","age_sex_restriction": "3yo+","wagers": "Exacta / Trifecta / Superfecta Super High Five","entries_count": 8,"starters_count": 7,"scratched_count": 1,"entries": "1|T O Password|K Kimura|D Takayanagi|126|30/1 | 2|Sovereignty|J Alvarado|W I Mott|126|5/2 | 3|Golden Tempo|J L Ortiz|C DeVaux|122|5/1 | ...","entries_detail": [{"program_number": "1","post_position": 1,"horse_name": "T O Password","state_bred": "JPN","horse_refno": "11442038","sire": "Copano Rickey (JPN)","dam": "T O Rachel (JPN)","dam_sire": "King Kamehameha (JPN)","age": 5,"sex": "H","jockey": "K Kimura","trainer": "D Takayanagi","owner": "Tomoya Ozasa","breeder": "Yanagawa Bokujo","weight": 126,"morning_line": "30/1","is_scratched": false,"finish_position": 4}],"results_available": true,"winner_horse": "Sovereignty","winner_program_number": "2","winner_jockey": "Junior Alvarado","winner_trainer": "William I. Mott","winner_owner": "Godolphin, LLC","winner_breeder": "Godolphin","winning_time": "2:00.36","finish_order": "1. Sovereignty, 2. The Puma, 3. Knightsbridge, 4. T O Password (JPN), 5. Forever Young (JPN), 6. Golden Tempo, 7. Napoleon Solo","win_payout": 5.94,"place_payout": 4.16,"show_payout": 2.94,"payouts_by_horse": [{"program_number": "2", "horse_name": "Sovereignty", "jockey": "Junior Alvarado", "win": 5.94, "place": 4.16, "show": 2.94, "finish_position": 1},{"program_number": "4", "horse_name": "The Puma", "jockey": "Javier Castellano", "win": null, "place": 11.22, "show": 6.1, "finish_position": 2}],"exotic_payouts": "{\"pick_3\": 110.46, \"pick_4\": 158.45, \"pick_5\": 452.61, \"pick_6\": 5058.59, \"daily_double\": 7.05, \"exacta\": 31.3, \"superfecta\": 131.71, \"super_high_five\": 3485.57, \"trifecta\": 72.65}","exotic_payouts_by_type": {"pick_3": {"raw_label": "$3 Pick 3", "wager_amount": 3.0, "payoff": 110.46, "winning_numbers": "2-2-2 (3 correct)"}},"race_cancelled": false,"stakes_id": "4198","entry_url": "https://www.equibase.com/static/entry/KEE103126USA-EQB.html","result_url": "https://www.equibase.com/static/chart/summary/KEE103126USA-EQB.html"}
A race-day change record:
{"record_type": "late_change","change_id": "BEL-2026-10-31-16","track_code": "BEL","track_name": "Belmont Park","race_date": "2026-10-31","race_id": "BEL-2026-10-31-R7","race_number": 7,"program_number": "8","horse_name": "Cuando","change_type": "scratch_reason","old_value": "Reason Unavailable","new_value": "PrivVet-Illness","reason": "PrivVet-Illness","time_posted": "9:30 AM ET","time_posted_at": "2026-10-31T13:30:00Z"}
A horse history record (premium record), with one past start and one workout shown:
{"record_type": "horse_history","horse_refno": "11442038","horse_name": "T O Password","state_bred": "JPN","sex": "H","color": "B","foaled": "2021-05-20","sire": "Copano Rickey (JPN)","dam": "T O Rachel (JPN)","dam_sire": "King Kamehameha (JPN)","breeder": "Yanagawa Bokujo","last_jockey": "Kazushi Kimura","last_trainer": "Daisuke Takayanagi","last_owner": "Tomoya Ozasa","career_starts": 13,"career_wins": 5,"career_seconds": 1,"career_thirds": 1,"career_earnings_usd": 1208627,"past_starts": [{"race_id": "KEE-2026-10-31-R12", "track_name": "Keeneland", "race_date": "2026-10-31", "race_number": 12, "race_type": "Longines Breeders' Cup Classic (Gr. 1)", "finish_position": 4, "speed_figure": 114}],"workouts": [{"track_code": "KEE", "track_name": "Keeneland", "date": "2026-10-27", "surface": "Dirt", "distance": "5F", "time": "1:03.80", "note": "Breezing", "rank": "3/5"}],"profile_url": "https://www.equibase.com/profiles/Results.cfm?type=Horse&refno=11442038®istry=T"}
Use Equibase Horse Racing Scraper from Python or JavaScript
Install the client with pip install apify-client or npm install apify-client, and get your API token from Apify Console.
Python
from apify_client import ApifyClientclient = ApifyClient("<APIFY_TOKEN>")run = client.actor("parsebird/equibase-horse-racing-scraper").call(run_input={"raceDate": "10/30/2026","dataMode": "results","maxItems": 500,})for race in client.dataset(run["defaultDatasetId"]).iterate_items():print(race["race_id"], race["winner_horse"], race["win_payout"], race["exotic_payouts"])
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<APIFY_TOKEN>' });const run = await client.actor('parsebird/equibase-horse-racing-scraper').call({dataMode: 'late_changes',trackCodes: ['GP', 'SA'],maxItems: 200,});const { items } = await client.dataset(run.defaultDatasetId).listItems();items.filter((c) => c.change_type === 'scratch').forEach((c) => console.log(c.track_code, c.race_number, c.program_number, c.horse_name, c.reason));
Use cases
- Handicapping and betting models: build datasets of fields, morning lines, results and payouts to test angles by track, surface, distance, trainer or jockey.
- Payout research: compare exotic payoffs (exacta, trifecta, superfecta, Pick 4, Pick 5) across tracks and race types.
- Scratch and change alerts: schedule the race-day changes mode every few minutes on race days and push new scratches, jockey switches and surface changes to Slack or email through integrations.
- Owner, trainer and breeder tracking: follow which connections are entering and winning, and at what claiming levels.
- Horse research: pull each runner's career, Speed Figures and recent workouts before a race.
- Racing media and apps: feed race cards and results into websites, newsletters, dashboards or spreadsheets.
How it works
- The Actor reads Equibase's entries and results index pages to find every track racing on your date.
- For each track it reads the race card and the results summary chart and joins them race by race.
- For today's date, it also reads the track's race-day changes page for track conditions, and the cancellations list for every date.
- With Add horse histories on, it reads each runner's Equibase profile and workout pages.
- Records are saved as they are built. If Apify moves the run to another server, it continues without saving the same record twice.
In our tests, all 137 races run on October 30, 2026 across 15 tracks came back in under 20 seconds.
How much does it cost to scrape Equibase?
Equibase Horse Racing Scraper uses pay-per-event pricing. Compute and proxy costs are included in the event price, so they aren't billed separately.
| Event | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
| Record (one race or one race-day change) | $0.99 / 1,000 | $0.89 / 1,000 | $0.79 / 1,000 | $0.69 / 1,000 |
| Premium record (one horse history) | $1.69 / 1,000 | $1.49 / 1,000 | $1.29 / 1,000 | $1.09 / 1,000 |
At Free plan prices, a full day of about 140 races costs about $0.14. Adding horse histories for 1,000 runners adds $1.69. To control spending, set Max records and Max horse histories. The run also stops when it reaches the maximum cost per run you set in Apify Console.
Is it legal to scrape Equibase?
Equibase Horse Racing Scraper only collects race information that Equibase publishes on its free, public pages: entries, results summary charts, race-day changes and horse profiles. It doesn't log in and doesn't access Equibase's paid products, such as full PDF charts or past performances. Equibase's data is copyrighted and its terms of use limit how it may be used, especially commercially. Check that your use complies with those terms and consult a lawyer if you're unsure. For more background, read Apify's article Is web scraping legal?
Other sports and betting scrapers from ParseBird
| Actor | What it does |
|---|---|
| Sports Betting Odds Scraper | Moneyline, spread and totals from sportsbooks for NFL, NBA, MLB, NHL, soccer and UFC |
| Action Network Scraper & API | Sportsbook odds, public betting splits, expert picks and line movement from Action Network |
| Sports Injury Reports API | NFL, NBA, WNBA, MLB and NHL injury reports with status and expected return |
| FlashScore Scraper & API | Live and scheduled scores for football, basketball, tennis and more from FlashScore |
| SofaScore Scraper | Live scores, fixtures, lineups, statistics and standings from SofaScore |
| MLB Stats Scraper | Teams, rosters, schedules, standings and player stats from MLB's Stats API |
| UFC Scraper | Fighter profiles, event fight cards and division rankings from UFC.com |
| Kalshi Scraper | Prediction market events, prices and volume from Kalshi |
FAQ
Do I need an Equibase account or API key? No. The Actor reads the same free pages Equibase shows to every visitor.
Which dates can I scrape? Equibase's free pages keep results for about the last 30 days and race cards for the coming days as they are drawn, usually up to a week ahead. Older pages are removed by Equibase. When you ask for a date outside that range, the run log and status message tell you which dates are available.
Why are the results empty for today?
Results appear on Equibase as each race is run. Run the Actor after the last race, or use entries mode for today's cards.
Which tracks are covered?
Every track on Equibase's entries and results pages for your date, which covers Thoroughbred racing in the United States, Canada and Puerto Rico, plus the Quarter Horse races that run on those cards (breed tells them apart). Track codes follow Equibase, such as SA Santa Anita, GP Gulfstream Park, KEE Keeneland, CD Churchill Downs, BEL Belmont Park, SAR Saratoga and WO Woodbine.
How do I get race-day changes for a past date? You can't. Equibase only publishes the changes page for the current race day, and early in the morning it can still show the previous day's changes until the new day's page is posted. To keep a history of changes, schedule runs during race days.
Are beaten lengths, fractional times and comments included? No. Those are only in Equibase's full PDF charts, which aren't part of the free results pages. The Actor returns the order of finish, winning time and payouts from the results summary.
Why is show_payout sometimes null?
Small fields often have no show betting. In four-horse races, for example, Equibase posts win and place prices only. A few exotic payoffs, such as some Super High Five pools, are published as $0.00, and the Actor keeps them as published.
How does the "Fillies and mares only" filter work? It keeps a race only if every runner on the card is a filly or mare. The sex comes from the race card, so it works for dates whose entries are still on Equibase, which is roughly the last 10 days and the coming week.
Do I need a proxy? No. The Actor runs without a proxy by default. If Equibase keeps refusing access from your runs, add an Apify proxy in the Advanced section.
Can I run it on a schedule or from my own code? Yes. Use Apify schedules for daily runs, the Apify API or the Python and JavaScript clients shown above, and integrations to send results to Google Sheets, Slack, Make, Zapier or n8n.
Something doesn't work or a field is missing. What should I do? Open an issue on the Actor's Issues tab with your input and run ID, and we'll look into it.