Basketball Reference Scraper — NBA Stats Tables
Pricing
from $16.00 / 1,000 basketball statistics rows
Basketball Reference Scraper — NBA Stats Tables
Extract Basketball Reference stats tables (per game, totals, advanced, rosters, box scores) as JSON rows for NBA analysis. USD 20 per 1,000 rows.
Pricing
from $16.00 / 1,000 basketball statistics rows
Rating
0.0
(0)
Developer
Muhammad Afzal
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
10 hours ago
Last modified
Categories
Share
Basketball Reference Scraper turns public Basketball Reference player, team, league, season and box-score pages into one clean JSON row per table row, with every stat keyed by the site's own column name. It is built for NBA analysts, fantasy players, journalists and data pipelines that need per-game, totals, advanced or roster tables without copy-pasting, and it costs USD 20 per 1,000 rows on the FREE tier (USD 0.02 per row, USD 16 per 1,000 on GOLD).
You give it the page URLs and the table IDs you want. It reads each page once, including the tables Basketball Reference hides inside HTML comments, and writes the rows to an Apify dataset you can export as JSON, CSV or Excel or read through the API.
What does the Basketball Reference scraper return?
Each dataset item is one row of one stats table. The envelope stays the same for every table, and the stats themselves sit in data.
| Field | What it contains |
|---|---|
sourceUrl | The Basketball Reference page the row came from |
pageType | player, team, league, boxscore or other, from the URL path |
pageTitle, entityName | Page title and main heading, for example Stephen Curry |
tableId, tableTitle | HTML table ID and caption, for example per_game_stats / Per Game Table |
rowNumber, rowKey | Position in the table and a stable key used to remove duplicates |
rowLabel | First non-empty cell, usually the season, player or team |
data | Every cell keyed by its data-stat name, such as games, pts_per_g, fg3_pct, ast_per_g |
links | Absolute links from linked cells (game logs, team seasons, award pages) |
scrapedAt | UTC time the page was parsed |
Numbers become JSON numbers, blank or dash cells become null, and labels such as 2024-25 stay strings. Repeated header rows inside a table are dropped. The run also writes a SUMMARY record with the outcome (DATA, EMPTY, BLOCKED, REJECTED or FAILED), page and table counts, rows delivered and per-page warnings.
How do I scrape NBA stats tables from Basketball Reference?
Paste up to 20 public https://www.basketball-reference.com/ URLs into startUrls and list the table IDs in tableIds. The default reads Stephen Curry's per-game table.
| Input | Default | Notes |
|---|---|---|
startUrls | Curry player page | 1–20 public Basketball Reference URLs; other hosts and Stathead pages are rejected |
tableIds | ["per_game_stats"] | Exact HTML table IDs, up to 50 |
extractAllTables | false | Take every table on each page instead of tableIds |
includeSummaryRows | false | Also keep career, total and partial-team rows |
maxResults | 100 | Row cap for the whole run, 1–5,000 |
requestDelayMillis | 3200 | Gap between page requests, 3,200–15,000 ms |
requestTimeoutSeconds | 30 | Timeout for one page, 10–60 s |
A player's career per-game and advanced tables plus one team season:
{"startUrls": [{ "url": "https://www.basketball-reference.com/players/c/curryst01.html" },{ "url": "https://www.basketball-reference.com/teams/GSW/2025.html" }],"tableIds": ["per_game_stats", "advanced"],"maxResults": 250}
Which Basketball Reference table IDs can I use?
Use the ID of the HTML table on the page. Common ones are per_game_stats, totals_stats, advanced and roster; league and box-score pages have their own IDs. If you are unsure, run once with extractAllTables: true on one page, or run with a guess: when no requested ID matches, the run ends EMPTY, charges no rows, and SUMMARY lists up to 30 table IDs that page actually has.
Is there a Basketball Reference API for this data?
This Actor gives you API access to the public tables. Call it from apify-client, the Apify REST API, a schedule or an AI agent, and you get the same JSON rows every time, so you do not maintain your own HTML parser.
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('muhammadafzal/basketball-reference-scraper').call({startUrls: [{ url: 'https://www.basketball-reference.com/leagues/NBA_2025_per_game.html' }],tableIds: ['per_game_stats'],maxResults: 50,});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const row of items) console.log(row.rowLabel, row.data.pts_per_g);
Python:
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("muhammadafzal/basketball-reference-scraper").call(run_input={"startUrls": [{"url": "https://www.basketball-reference.com/players/c/curryst01.html"}],"tableIds": ["per_game_stats"],"maxResults": 25,})for row in client.dataset(run.default_dataset_id).iterate_items():print(row["rowLabel"], row["data"].get("pts_per_g"))
Use it from an AI assistant
Basketball Reference Scraper works from Claude, ChatGPT, Cursor or any MCP client through Apify's MCP server. Add https://mcp.apify.com/?tools=muhammadafzal/basketball-reference-scraper to your client and ask, for example: "Get Stephen Curry's per-game stats by season from Basketball Reference and tell me his three best three-point percentage seasons." Each row is charged at the prices below, so ask for a row limit.
What does the output look like?
Two rows from a cloud run of the default input on 2026-10-26 (18 rows, 5 seconds), shortened (the second row shows only some fields):
[{"sourceUrl": "https://www.basketball-reference.com/players/c/curryst01.html","pageType": "player","pageTitle": "Stephen Curry Stats, Height, Weight, Position, Draft Status and more","entityName": "Stephen Curry","tableId": "per_game_stats","tableTitle": "Per Game Table","rowNumber": 1,"rowKey": "49f6ad0b18ea10b23e14","rowLabel": "2009-10","data": { "year_id": "2009-10", "age": 21, "team_name_abbr": "GSW", "pos": "PG", "games": 80, "fg3_pct": 0.437, "ast_per_g": 5.9, "pts_per_g": 17.5, "awards": "ROY-2" },"links": { "year_id": "https://www.basketball-reference.com/players/c/curryst01/gamelog/2010/", "team_name_abbr": "https://www.basketball-reference.com/teams/GSW/2010.html" },"scrapedAt": "2026-10-26T06:55:45.453Z"},{"sourceUrl": "https://www.basketball-reference.com/players/c/curryst01.html","pageType": "player","tableId": "per_game_stats","rowNumber": 2,"rowLabel": "2010-11","data": { "year_id": "2010-11", "age": 22, "games": 74, "fg3_pct": 0.442, "ft_pct": 0.934, "pts_per_g": 18.6, "awards": null },"scrapedAt": "2026-10-26T06:55:45.453Z"}]
Pricing: how much does Basketball Reference data cost?
The Actor uses pay-per-event pricing with platform usage included. You pay for rows written to the dataset, plus one start event per run at the default 256 MB memory.
| Event | FREE | BRONZE | SILVER | GOLD | PLATINUM | DIAMOND |
|---|---|---|---|---|---|---|
| Statistics row (one dataset item) | USD 0.02 | USD 0.02 | USD 0.02 | USD 0.016 | USD 0.016 | USD 0.016 |
| Actor start (per started GB of allocated memory) | USD 0.005 | USD 0.005 | USD 0.005 | USD 0.005 | USD 0.005 | USD 0.005 |
Worked totals on the FREE tier:
- Curry's per-game table (18 rows): 18 × USD 0.02 + USD 0.005 = USD 0.365
- 100 rows: 100 × USD 0.02 + USD 0.005 = USD 2.005
maxResults caps the row charge, and if you set a run-level maximum charge, the Actor checks the remaining budget before every row and stops cleanly. Wrong table IDs, blocked pages and timeouts produce no row charges.
When should I use it, and when not?
Use it when you know the Basketball Reference pages you need and want specific tables as rows: a player's career splits, a team's roster and advanced stats, a season's league-wide per-game table, or the box scores of a few games.
Use something else when:
- You need baseball, hockey or WNBA stats: Baseball Reference Stats Scraper, Hockey-Reference NHL Stats Scraper or WNBA Stats Scraper.
- You want Stathead queries, college basketball (a different Sports Reference site) or logged-in pages. They are rejected.
- You want to mirror the whole site, train an AI model or build a competing stats database. The Actor does not crawl links, and Sports Reference's terms restrict those uses.
Limits and responsible access
- Speed: one page took about 5 seconds in the 2026-10-26 cloud run. Pages are fetched one at a time at least 3.2 seconds apart, which keeps traffic under the 20-requests-per-minute limit Sports Reference publishes, so 20 pages take a little over a minute.
- Scope: 20 pages and 5,000 rows per run, no link following, no retry storms. HTTP 403, 429, challenge pages and timeouts are recorded in
SUMMARY, and a blocked run returns zero rows. - Freshness: pages are read live at run time, so in-season tables reflect the site at that moment.
FAQ
Does it crawl the whole Basketball Reference site?
No. It reads only the URLs you supply, up to 20 per run, and never follows links.
Can I get every table on a page?
Yes. Set extractAllTables: true. It includes tables stored inside HTML comments, which many Basketball Reference pages use for their secondary stats tables.
What happens if my table ID is wrong?
The run ends EMPTY, no rows are charged, and SUMMARY lists the table IDs found on that page so you can retry.
Are career totals and team subtotal rows included?
Not by default. Set includeSummaryRows: true to keep footer, total and partial-team rows such as a traded player's per-team lines.
Do I need a Stathead subscription?
No. The Actor reads only free public pages, and it rejects Stathead URLs.
Can I export the stats to CSV or Google Sheets?
Yes. Apify exports any dataset to CSV, JSON, Excel or XML, and integrations can push it to Google Sheets. The nested data object becomes one column per stat in CSV.
Can I publish the data?
Credit Basketball Reference and keep the sourceUrl. Sports Reference's data-use policy limits bulk redistribution and AI training, so check its terms for your use.
Related Actors
- Baseball Reference Stats Scraper: MLB tables from Baseball Reference
- Hockey-Reference NHL Stats Scraper: NHL tables from Hockey-Reference
- WNBA Stats Scraper: WNBA player and team stats
- Cars and Bids Scraper and Canada Open Data Scraper: other public-data tools from the same developer
Legal and compliance
The Actor reads public Basketball Reference pages without logging in, solving CAPTCHAs or bypassing access controls, and it stays under the site's published request limit. Follow Sports Reference's terms of use, data-use policy and bot-traffic policy, and credit Basketball Reference when you publish results. This tool is not affiliated with Sports Reference, and this is not legal advice.
Last verified: 2026-10-27