Sports Reference Stats Scraper - NBA & NHL avatar

Sports Reference Stats Scraper - NBA & NHL

Pricing

from $21.00 / 1,000 player season records

Go to Apify Store
Sports Reference Stats Scraper - NBA & NHL

Sports Reference Stats Scraper - NBA & NHL

Scrape NBA player and team stats from Basketball-Reference and NHL stats from Hockey-Reference: per-season stats, advanced metrics (PER, win shares, BPM), team rosters and salaries. One row per season, 23 seasons for LeBron James in one page. Export CSV, Excel, JSON. No login or API key.

Pricing

from $21.00 / 1,000 player season records

Rating

0.0

(0)

Developer

RecordsData

RecordsData

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

10 days ago

Last modified

Share

RecordsData

Sports Reference Stats Scraper scrapes Basketball-Reference (NBA) and Hockey-Reference (NHL). Paste player, team or league-season URLs, or pick a whole season or a last-name letter with no URL at all. Get one row per season with every stat column the page publishes, plus playoffs, career totals, bio and draft, advanced metrics, hockey goalies, Corsi and Fenwick, rosters and salaries. Export CSV, Excel, JSON or API. No login, no API key. Last updated 2026-10-11. From $25 per 1,000 season rows.

Sports Reference Stats Scraper turns Basketball-Reference and Hockey-Reference pages into structured data. A single LeBron James page with every option on returned 115 rows in a cloud run. It is built for sports analysts, fantasy players, journalists and data scientists who need historical NBA and NHL numbers.

๐Ÿ€ What does Sports Reference Stats Scraper do?

It has three modes, set with the Mode input:

  • Start URLs (urls): player pages, team-season pages, league-season tables or letter indexes from either site.
  • Whole league season (season): every player of one NBA or NHL season, no URL needed. Pick sport, season and statType; hockey adds playerType.
  • Player index (index): the players-by-last-name-letter list of one sport, with player id, first and last season, position and active flag.

On player, team and league pages you can switch on extra rows:

  • Playoff stats, Career totals and Advanced stats (PER, win shares, BPM and VORP for basketball, rate stats for hockey).
  • Corsi and Fenwick: hockey possession rows with PDO and zone starts.
  • Team roster and Salaries (basketball), including tables hidden in HTML comments.
  • Bio and draft details: full name, height, weight, birth date and place, college, draft round, pick and year, and Hall of Fame flag on every row of the player.
  • Numbers as numbers (numericValues): stat values as numbers instead of text.

Hockey goalie pages work, with goalie columns such as goalie_wins and save_pct_goalie. Every row carries sport, pageType and recordType, and the column names are the ones the source site uses, so numbers match the page.

โš–๏ธ Basketball-Reference scraper vs other Apify actors

Read on 2026-10-10 from the public Store pages of each actor. A cell says "not shown" when the page does not mention the feature.

Uslulzasaur (basketball and hockey)parseforge (basketball and hockey)
SportsNBA and NHL in one actorOne actor per sportOne actor per sport
Start without a URLSeason mode and letter indexLetter index or detailed modeSeason and stat type
Playoffs, career, bio, draftAll four as switchesPlayoffs, career, bio, draftNot shown
Hockey goalies, CorsiGoalies, Corsi, Fenwick, PDOGoalies yes, Corsi not shownGoalies, Corsi "where available"
Roster, salariesBoth, as switchesNot shownNot shown
Price per 1,000$25 Free plan, $21 top tierFrom $10$19 header, $21 README

lulzasaur is the cheapest, about 2.5 times below our season row, and also returns playoffs, bio and draft; it gives 11 fields in its basketball views while we publish 220 data columns, plus rosters and salaries. parseforge is level on price and starts from a season, but its page shows neither playoffs nor bio. If you only need a cheap flat list of one sport, lulzasaur may fit better.

๐Ÿ“Š What data can you extract from Basketball-Reference and Hockey-Reference?

FieldDescription
sport, pageType, recordTypeBasketball or hockey; player, team, league or index; season, playoffs, career, career-playoffs, advanced, playoffs-advanced, possession, playoffs-possession, roster, salary or index
name, team, url, playerId, playerUrlPlayer or team name, source page, site player id (for example jamesle01) and player page
year_id, age, team_name_abbr, comp_name_abbr, posSeason (Career on career rows), age, team, league and position
pts_per_g, trb_per_g, ast_per_g, per, ws, bpm, vorpBasketball per-game and advanced metrics
goals, assists, corsi_pct, pdo, goalie_wins, save_pct_goalieHockey skater, possession and goalie stats
salary, salaryUsdSalary rows as printed and as a number in US dollars
fullName, birthPlace, draftYear, draftPick, hallOfFameBio and draft fields (Bio on)

The dataset schema declares 223 fields (220 data columns plus error, errorType and hint) and five output views. Cells the source leaves empty are left out of the row.

๐Ÿงพ Sample output of the Sports Reference Stats Scraper

Trimmed row from a cloud run on a LeBron James player page (season 2012-13). Bio and draft columns appear only when their switch is on:

{
"sport": "basketball",
"pageType": "player",
"recordType": "season",
"name": "LeBron James",
"url": "https://www.basketball-reference.com/players/j/jamesle01.html",
"year_id": "2012-13",
"age": "28",
"team_name_abbr": "MIA",
"comp_name_abbr": "NBA",
"pos": "PF",
"games": "76",
"fg_pct": ".565",
"trb_per_g": "8.0",
"ast_per_g": "7.3",
"pts_per_g": "26.8",
"awards": "MVP-1,DPOY-2,AS,NBA1,DEF1",
"scrapedAt": "2026-10-04T04:50:40.409Z"
}

Values are strings exactly as the site prints them (for example .565) unless Numbers as numbers is on.

๐Ÿ’ฐ How much does it cost to scrape Basketball-Reference and Hockey-Reference?

The Actor uses pay-per-event pricing. You pay only for rows saved to the dataset. Prices are the live Free-plan prices; paid Apify plans pay less (down to $21 per 1,000 season rows).

EventWhat you are charged forPrice per 1,000
player-season-recordOne season row, including league-season table rows$25.00
player-advanced-recordOne advanced row, including Corsi and Fenwick possession rows$12.00
team-roster-recordOne roster row on a team page$10.00
salary-recordOne salary row, basketball only$12.00
player-playoff-recordOne playoff season row of a player or a whole league season$12.00
player-career-recordOne career total row of a player page$10.00
player-index-recordOne line of the players-by-letter list$10.00

Playoff, career and player-index events are the same on every plan. Bio and draft details cost nothing extra. Error rows, 404 pages and empty tables are never charged.

Worked examples at the Free-plan price: 1,000 season rows cost 1,000 x $0.025 = $25.00, and adding 1,000 advanced rows brings it to $25.00 + 1,000 x $0.012 = $37.00.

  • One team-season page with Advanced stats and Team roster on: 3 + 19 + 19 events, about $0.49.
  • One player page, salaries only (1 season row + 23 salary rows): about $0.30.
  • One letter of the player index, 500 index rows: 500 x $0.010 = about $5.00.

Set a maximum cost per run in the Apify run options and the Actor stops cleanly when it is reached. Free Apify users are limited to 10 rows per run.

๐Ÿš€ How to scrape Basketball-Reference and Hockey-Reference (3 steps)

  1. Open the Actor in Apify Console. Keep Mode on Start URLs and paste player or team URLs, or switch Mode to Whole league season and pick sport and season.
  2. Set Max Items and switch on only the extras you need: playoffs, career, advanced, Corsi and Fenwick, roster, salaries, bio.
  3. Click Start, then download the dataset as JSON, CSV, Excel or XML from the Output tab.

โš™๏ธ Input of the Sports Reference Stats Scraper

FieldTypeDescription
modestringurls (default), season or index.
startUrlsarrayPlayer, team, league-season or letter pages. Used in urls mode. Default: LeBron James.
sportstringbasketball or hockey. Used in season and index modes.
seasonintegerEnding year, 2025 means 2024-25. Season mode. Default 2025.
statTypestringstandard, totals (basketball only) or advanced. Season mode.
playerTypestringskaters or goalies. Hockey season mode and team pages.
letterstringOne letter a to z. Index mode.
maxItemsintegerMaximum main rows. Free users: 10. Paid users: up to 1,000,000. Extra rows are not counted.
includePlayoffs, includeCareer, includeAdvanced, includeCorsiFenwick, includeRoster, includeSalariesbooleanExtra row types, all off by default.
includeBio, numericValuesbooleanBio and draft details on every player row; numeric stat values. Off by default.
{
"mode": "season",
"sport": "hockey",
"season": 2024,
"statType": "standard",
"playerType": "goalies",
"maxItems": 50,
"includePlayoffs": true
}

๐Ÿ“ฆ Output of the Sports Reference Stats Scraper

Results go to the default dataset with five views. Error rows (for example an unsupported URL) carry error, errorType and hint and are never billed. If a page does not exist (404), the run ends as succeeded with zero rows and zero charge. A run that is rate limited by the site (HTTP 429) ends as succeeded, keeps the rows already delivered and writes one free error row.

๐Ÿ’ก Use cases for Basketball-Reference and Hockey-Reference data

  • Model building and fantasy or betting research: pull every season of a career, with playoffs, PER, win shares, goalie save percentage and Corsi.
  • Payroll and draft analysis: combine rosters, salary history and draft fields.
  • Media and content: get verified season-by-season numbers for articles.

๐Ÿ”Œ Run Sports Reference Stats Scraper via API, schedule and integrations

Call it from your own code with the Apify API client:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('RecordsData/sports-reference-stats-scraper').call({
mode: 'season',
sport: 'basketball',
season: 2024,
statType: 'advanced',
maxItems: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length);

Schedule runs and send results to Google Sheets, Zapier, Make or n8n.

๐Ÿค– Sports Reference Stats Scraper MCP server for AI agents

AI agents can call this Actor through the Apify MCP server at https://mcp.apify.com?tools=RecordsData/sports-reference-stats-scraper. Add this to your MCP client configuration (Claude Desktop, Cursor, VS Code or any remote MCP client):

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com?tools=RecordsData/sports-reference-stats-scraper"
}
}
}

Example agent prompt:

Use the Sports Reference Stats Scraper on https://www.basketball-reference.com/players/j/jamesle01.html with advanced stats and playoffs on and 10 rows max, then tell me which season had the highest PER.

An agent should choose this Actor when it needs season-by-season NBA or NHL stats, playoffs, career totals, advanced metrics, hockey goalies or Corsi, team rosters, NBA salaries, or a whole league season.

The Actor reads publicly available statistics pages and does not log in or bypass any protection. It requests pages one at a time with a 3.3 second delay and stops when the site answers HTTP 429. You are responsible for using the data in line with the target site's terms of use and the laws that apply to you. This is an independent tool and is not affiliated with Sports Reference LLC.

โ“ Frequently asked questions about the Sports Reference Stats Scraper

Which Sports Reference sites does Sports Reference Stats Scraper support?

Sports Reference Stats Scraper supports Basketball-Reference.com for the NBA and Hockey-Reference.com for the NHL. Baseball-Reference, Pro-Football-Reference and FBref sat behind a Cloudflare challenge when we checked on 2026-09-15, so they are not supported. You can mix NBA and NHL URLs in a single Start URLs list.

Which URLs can I use with Sports Reference Stats Scraper?

Sports Reference Stats Scraper accepts player pages such as /players/j/jamesle01.html, team-season pages such as /teams/BOS/2024.html, league-season tables such as /leagues/NBA_2025_per_game.html, and letter indexes such as /players/a/. Any other URL type returns an error row with a hint, and that error row is never billed, so a wrong link costs nothing.

Why did my Sports Reference Stats Scraper run return 0 results?

If the page does not exist (404), Sports Reference Stats Scraper ends as succeeded with zero rows and you are not charged. Check the error rows too, since the URL may be unsupported and a wrong link returns a free error row with a hint. A run that delivers nothing also stops after 10 pages instead of walking a long URL list.

Why do basketball and hockey rows have different fields in Sports Reference Stats Scraper?

Each sport tracks different statistics, so Sports Reference Stats Scraper keeps each site's own column names instead of forcing a shared schema. Basketball rows have fields such as pts_per_g, while hockey rows have goals and goalie rows have save_pct_goalie. Every row is tagged with sport, pageType and recordType.

Why are some salary or advanced rows missing for older seasons?

The source site does not publish every number for every season, especially salaries from before the 1990s. Sports Reference Stats Scraper returns what is on the page and does not invent values. Cells the source leaves empty are left out of the row instead of being filled with a placeholder, so a missing column simply means the page has no number there.

Can I scrape a whole team roster with Sports Reference Stats Scraper?

Yes. Paste a team-season URL such as /teams/BOS/2024.html, switch on Team roster, and optionally Advanced stats or Playoff stats. You get one roster row per player with number, position, height, weight, birth date and college. Roster rows cost $0.010 each on the Free plan and the option works for team URLs only.

Do I need a proxy to run Sports Reference Stats Scraper?

No. Both Basketball-Reference and Hockey-Reference responded normally in our tests without a proxy, so Sports Reference Stats Scraper has no proxy setting to configure. It requests pages one at a time with a delay, uses no login, and needs no API key, only an Apify account.

How do I limit my spend on Sports Reference Stats Scraper?

Set the Max Items input and the maximum cost per run in the Apify run options. Sports Reference Stats Scraper stops cleanly when either limit is reached, with the status message "Stopped at your max charge limit". Note that Max Items counts main rows only, while advanced, roster, salary and other extra rows are not counted there, and the billed ones are extra events.

What happens if I send an empty or invalid input to Sports Reference Stats Scraper?

Start URLs is no longer required, and its default is the LeBron James page; season and index modes ignore it. Mistakes such as a URL that is not a Basketball-Reference or Hockey-Reference page end the run as succeeded with one free error row that has errorType invalid-input, an error and a hint.

๐Ÿ”— Want more sports data? Other RecordsData scrapers

๐Ÿ†˜ Support

Found a bug or need another field? Open an issue in the Issues tab of this Actor or write to contact.punkrecordsdata@gmail.com.

Last updated: 2026-10-11