Sports Reference Stats Scraper - NBA & NHL
Pricing
from $21.00 / 1,000 player season records
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
18 hours ago
Last modified
Categories
Share
Sports Reference Stats Scraper scrapes player and team pages from Basketball-Reference (NBA) and Hockey-Reference (NHL). Paste a player or team URL, get one row per season with every stat column the page publishes, plus optional advanced metrics, rosters and salaries. Export CSV, Excel, JSON or API. No login, no API key. Verified 2026-10-03. From $25 per 1,000 season rows.
Sports Reference Stats Scraper turns any Basketball-Reference or Hockey-Reference player or team-season page into structured data. A single LeBron James page returned 23 season rows with 36 columns per row in our test run, and a single Boston Celtics 2024 team page returned 19 roster rows, 19 advanced-stats rows and 19 per-game rows. It is built for sports analysts, fantasy players, bettors, journalists and data scientists who need historical NBA and NHL numbers without copy-pasting tables.
๐ What does Sports Reference Stats Scraper do?
- Scrapes NBA player career stats from Basketball-Reference, one row per season.
- Scrapes NHL player career stats from Hockey-Reference, one row per season.
- Scrapes team-season pages (for example the 2024 Boston Celtics) with per-game stats for every player.
- Adds advanced metrics on request: PER, win shares, BPM and VORP for basketball, possession and rate stats for hockey.
- Adds the full team roster on request: number, position, height, weight, birth date, college.
- Adds NBA salary history per season on request, including the tables the sites hide inside HTML comments.
Every row is tagged with sport and pageType, and the column names are the ones the source site uses (pts_per_g, ws_per_48, goals, and so on), so numbers match what you see on the page.
๐ What data can you extract from Basketball-Reference and Hockey-Reference?
| Field | Description |
|---|---|
sport | basketball or hockey |
pageType | player or team |
name | Player or team name |
url | Source page URL |
year_id | Season, for example 2012-13 (player pages) |
age, team_name_abbr, comp_name_abbr, pos | Age, team, league and position for that season |
games, games_started, mp_per_g | Games played, started and minutes per game |
pts_per_g, trb_per_g, ast_per_g, stl_per_g, blk_per_g | Basketball per-game production |
fg_pct, fg3_pct, ft_pct, efg_pct | Shooting percentages (basketball) |
goals, assists, and other hockey columns | Hockey season stats, as published by Hockey-Reference |
awards | Season awards and honors when the player has any, for example MVP-1,AS,NBA1 |
per, ws, bpm, vorp | Advanced metrics (basketball, with Advanced stats on) |
player, height, weight, birth_date, college | Roster fields (team pages, with Team roster on) |
season, team_name, salary | Salary rows (basketball, with Salaries on) |
scrapedAt | ISO timestamp of the scrape (UTC) |
Cells the source leaves empty are left out of the row instead of being filled with a placeholder, so rows never contain empty columns. In our 10-row LeBron James test there were 36 columns and none of them was empty across all rows.
๐งพ Sample output of the Sports Reference Stats Scraper
Real row from a cloud run on basketball-reference.com/players/j/jamesle01.html (LeBron James, season 2012-13):
{"sport": "basketball","pageType": "player","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","games_started": "76","mp_per_g": "37.9","fg_per_g": "10.1","fga_per_g": "17.8","fg_pct": ".565","fg3_per_g": "1.4","fg3a_per_g": "3.3","fg3_pct": ".406","fg2_per_g": "8.7","fg2a_per_g": "14.5","fg2_pct": ".602","efg_pct": ".603","ft_per_g": "5.3","fta_per_g": "7.0","ft_pct": ".753","orb_per_g": "1.3","drb_per_g": "6.8","trb_per_g": "8.0","ast_per_g": "7.3","stl_per_g": "1.7","blk_per_g": "0.9","tov_per_g": "3.0","pf_per_g": "1.4","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), so you can cast them in your own pipeline.
๐ฐ How much does it cost to scrape Basketball-Reference and Hockey-Reference?
The Actor uses pay-per-event pricing. You pay only for rows that are saved to the dataset. Prices below are the live Free-plan prices; paid Apify plans get lower per-event prices (down to $21 per 1,000 season rows on the highest plan).
| Event | What you are charged for | Price per 1,000 |
|---|---|---|
player-season-record | One season row of per-game stats (the base event) | $25.00 |
player-advanced-record | One advanced-metrics row (optional) | $12.00 |
team-roster-record | One roster row on a team page (optional) | $10.00 |
salary-record | One salary row, basketball only (optional) | $12.00 |
You are not charged for error rows, pages that return 404, empty tables or duplicate rows. A run that cannot deliver any data fails with a clear message and charges nothing.
Real examples from our test runs, at the Free-plan price:
- 10 season rows of one player: 10 events, about $0.25.
- One team-season page with Advanced stats and Team roster on, 3 season rows: 3 + 19 + 19 events, about $0.49.
- One player page, salaries only (1 season row + 23 salary rows): about $0.30.
Set a maximum cost per run in the Apify run options and the Actor stops cleanly when it is reached, with the status message "Stopped at your max charge limit". Free Apify users are limited to 10 season rows per run.
๐ How to scrape Basketball-Reference and Hockey-Reference (3 steps)
- Open the Actor in Apify Console and paste one or more player or team URLs into Start URLs, for example
https://www.basketball-reference.com/players/j/jamesle01.htmlorhttps://www.hockey-reference.com/players/o/ovechal01.html. - Set Max Items (season rows to return) and switch on Advanced stats, Team roster or Salaries only if you need them.
- Click Start, then download the dataset as JSON, CSV, Excel or XML from the Output tab.
โ๏ธ Input of the Sports Reference Stats Scraper
| Field | Type | Description |
|---|---|---|
startUrls | array | Player or team-season pages on basketball-reference.com or hockey-reference.com. Default: LeBron James. |
maxItems | integer | Maximum season rows to return. Free users: 10. Paid users: up to 1,000,000. Extra rows from the options below are not counted here. |
includeAdvanced | boolean | Add advanced metrics rows (default false). |
includeRoster | boolean | Add the team roster, team URLs only (default false). |
includeSalaries | boolean | Add salary rows, basketball only (default false). |
{"startUrls": [{ "url": "https://www.basketball-reference.com/players/j/jamesle01.html" },{ "url": "https://www.basketball-reference.com/teams/BOS/2024.html" }],"maxItems": 50,"includeAdvanced": true,"includeRoster": true,"includeSalaries": false}
๐ฆ Output of the Sports Reference Stats Scraper
Results go to the default dataset. The Player Seasons view shows the key columns, and the full dataset has every column the source table publishes. Error rows (for example an unsupported URL) carry only an error field and are never billed. If a page genuinely has no data, the run ends as succeeded with the status message "No rows found" and zero charge. If every URL fails because of a block, a bad URL or a layout change, the run fails with a clear message.
โ๏ธ Basketball-Reference scraper vs other Apify actors
Prices below are the public Free-plan prices read from the Apify API on 2026-10-03.
| Actor | Sports | Events | Price per 1,000 rows |
|---|---|---|---|
| Sports Reference Stats Scraper (this one) | NBA and NHL in one Actor | 4 (season, advanced, roster, salary) | $25 season row, $10 to $12 for extras |
| parseforge basketball-reference-scraper and hockey-reference-scraper | One sport each | 1 flat event | $21 |
| lulzasaur basketball-reference-scraper and hockey-reference-scraper | One sport each | 1 flat event | $10 |
We are more expensive on the base row than both alternatives. What the extra buys: NBA and NHL in a single input list, optional advanced metrics, roster and salary rows as separate switches (you pay for them only when you turn them on), and the salary and advanced tables that the sites ship inside HTML comments. If you only need a flat table of one sport and price is the main factor, a cheaper single-sport actor may fit you better.
๐ก Use cases for Basketball-Reference and Hockey-Reference data
- Model building: pull every season of a player career to train valuation or projection models.
- Fantasy and betting research: compare per-game production, PER, win shares and BPM across seasons.
- Payroll and cap analysis: combine a team roster with salary history for value-per-dollar studies.
- Media and content: get verified season-by-season numbers for articles and graphics.
๐ 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({startUrls: [{ url: 'https://www.hockey-reference.com/players/o/ovechal01.html' }],maxItems: 25,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.length);
Use the Apify Scheduler to refresh data after each season, send results to Google Sheets, Zapier, Make or n8n, or connect the Actor to AI agents through the Apify MCP server.
โ๏ธ Is it legal to scrape Basketball-Reference and Hockey-Reference?
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 delay between them. You are responsible for using the data in line with the target site's terms of use and the laws that apply to you. Sports statistics are not personal data in the sense of GDPR for most use cases, but check your own situation. 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 it support?
Basketball-Reference.com (NBA) and Hockey-Reference.com (NHL). Baseball-Reference, Pro-Football-Reference and FBref sit behind a Cloudflare challenge when we checked on 2026-09-15, so they are not supported.
Which URLs can I use?
Player pages such as /players/j/jamesle01.html and team-season pages such as /teams/BOS/2024.html. Other URL types return an error row that is not billed.
Why did I get 0 results?
Either the page does not exist (404) or it has no stats table, for example a player who has not played yet. In that case the run ends as succeeded with a "No rows found" message and you are not charged. If the run fails instead, check the error rows in the dataset: the URL may be unsupported or the site may have changed its layout.
Why do basketball and hockey rows have different fields?
Each sport tracks different stats, and the Actor keeps each site's own column names instead of forcing a shared schema.
Why are some salary or advanced rows missing for older seasons?
The source site does not publish every number for every season, especially salaries before the 1990s. The Actor returns what is on the page.
Can I scrape a whole team roster?
Yes. Use a team-season URL, switch on Team roster, and optionally Advanced stats.
Do I need a proxy?
No. Both sites responded normally in our tests without a proxy, so there is no proxy setting to configure.
How do I limit my spend?
Set Max Items and the maximum cost per run. The Actor stops cleanly when either limit is reached.
๐ Want more sports data? Other PunkRecordsData scrapers
- Basketball Match Stats Scraper: live box scores, play-by-play and odds.
- Sofascore Match Stats Scraper: live scores, odds and lineups across sports.
- Tennis Match Stats Scraper: ATP and WTA match statistics.
๐ 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-03