Skip to main content

Overview

Contract and salary data includes current player salaries, contract options (player/team options), team cap holds, dead money, and historical salary information. Data is scraped from Spotrac and RealGM, covering current contracts and multi-year projections.

Data Files

Current Salaries

Active player contracts and future years
  • salary.csv

Contract Options

Player/team options and deadlines
  • option.csv

Salary Cap Info

League salary cap, luxury tax, aprons
  • cap.csv

Historical Salaries

Historical player salaries (1991-present)
  • nba_salaries_master.csv

Cap Holds

Team cap holds
  • nba_cap_holds.csv

Dead Money

Released player cap hits
  • nba_dead_money.csv

Schema: Current Salaries

File: salary.csv
Generated by: contract_data.py
Records: ~500 active players
Source: Spotrac team pages
Updated: Current season + 5-6 year projections

Fields

Player
string
required
Player name (cleaned, no suffixes)
Team
string
required
Team abbreviation (ATL, BOS, BKN, etc.)

Sample Data

Player,Team,2024-25,2025-26,2026-27,2027-28,2028-29,Guaranteed
Stephen Curry,GSW,55761216.0,59606816.0,62840802.0,0,0,178208834.0
Joel Embiid,PHI,51415938.0,55012210.0,59013270.0,63014330.0,0,228455748.0
LeBron James,LAL,48728845.0,52627150.0,0,0,0,101356095.0
A value of 0 indicates no contract for that season (free agent, option declined, or contract expired)

Schema: Contract Options

File: option.csv
Generated by: contract_data.py
Source: Spotrac “Upcoming Deadlines” tables

Fields

Player
string
required
Player name
Team
string
required
Team abbreviation
2024-25
string
Option type for 2024-25 season
2025-26
string
Option type for 2025-26 season
2026-27
string
Option type for 2026-27 season
2027-28
string
Option type for 2027-28 season
2028-29
string
Option type for 2028-29 season

Option Types

CodeMeaning
PPlayer option (player decides to opt in/out)
TTeam option (team decides to exercise or decline)
NGNon-guaranteed (team can release without penalty)
EEExtension eligible
RFARestricted free agent
UFAUnrestricted free agent
0Fully guaranteed, no option

Sample Data

Player,Team,2024-25,2025-26,2026-27,2027-28,2028-29
LeBron James,LAL,P,0,0,0,0
James Harden,LAC,P,0,0,0,0
Paul George,PHI,0,P,0,0,0
Kawhi Leonard,LAC,0,P,0,0,0

Schema: Salary Cap Information

File: cap.csv
Source: RealGM salary cap info
Records: Annual cap levels from 1990-present
Season
string
Season format: “2024-25”
year
integer
Ending year (2025 for 2024-25)
Salary Cap
float
Team salary cap (in dollars)
Luxury Tax
float
Luxury tax threshold
1st Apron
float
First apron threshold (new CBA)
2nd Apron
float
Second apron threshold (new CBA)
BAE
float
Bi-annual exception amount
Standard / Non-Taxpayer
float
Non-taxpayer mid-level exception (MLE)
Taxpayer
float
Taxpayer mid-level exception
Team Room / Under Cap
float
Room exception for teams under cap

Schema: Historical Salaries

File: nba_salaries_master.csv
Records: ~35,000+ player-season-team records
Coverage: 1991-present
player
string
Player name
salary
float
Salary for that season (in dollars)
team
string
Team abbreviation
year
integer
Season year
nba_id
float
NBA player ID (when available)

Sample Data

player,salary,team,year,nba_id
Moses Malone,2406000.0,ATL,1991,77449.0
Dominique Wilkins,2065000.0,ATL,1991,1122.0

Usage Examples

Current Top Salaries

import pandas as pd

df = pd.read_csv('salary.csv')

# Top 2024-25 salaries
top_salaries = df.nlargest(30, '2024-25')[['Player', 'Team', '2024-25']]
top_salaries['2024-25'] = top_salaries['2024-25'].apply(lambda x: f"${x:,.0f}")

print("Highest Paid Players 2024-25:")
print(top_salaries)

Players with Options

import pandas as pd

options = pd.read_csv('option.csv')

# Find all player options for 2025-26
player_options_2526 = options[options['2025-26'] == 'P']

print("Players with 2025-26 Player Options:")
print(player_options_2526[['Player', 'Team', '2025-26']])

Team Salary Cap Analysis

import pandas as pd

salaries = pd.read_csv('salary.csv')
cap = pd.read_csv('cap.csv')

# Get 2024-25 cap info
cap_2025 = cap[cap['year'] == 2025].iloc[0]
salary_cap = cap_2025['Salary Cap']
lux_tax = cap_2025['Luxury Tax']
apron1 = cap_2025['1st Apron']
apron2 = cap_2025['2nd Apron']

# Calculate team payrolls
team_payroll = salaries.groupby('Team')['2024-25'].sum().sort_values(ascending=False)

team_payroll_df = pd.DataFrame({
    'Team': team_payroll.index,
    'Total_Salary': team_payroll.values,
    'Over_Cap': team_payroll.values - salary_cap,
    'Lux_Tax_Status': team_payroll.values > lux_tax,
    'Over_Apron1': team_payroll.values > apron1,
    'Over_Apron2': team_payroll.values > apron2
})

print("Team Salary Analysis 2024-25:")
print(team_payroll_df.head(30))

Contract Flexibility

import pandas as pd

salaries = pd.read_csv('salary.csv')
options = pd.read_csv('option.csv')

# Merge salary and options
merged = salaries.merge(options, on=['Player', 'Team'])

# Find players with expiring contracts or options
expiring_2025 = merged[
    (merged['2025-26'] == 0) | 
    (merged['2025-26'].isin(['P', 'T', 'UFA', 'RFA']))
]

expiring_2025['Status_2026'] = expiring_2025['2025-26']
print("Contract Flexibility - 2025-26 Free Agents/Options:")
print(expiring_2025[['Player', 'Team', '2024-25', 'Status_2026']].sort_values('2024-25', ascending=False))

Historical Salary Inflation

import pandas as pd

df = pd.read_csv('nba_salaries_master.csv')

# Average salary by year
avg_by_year = df.groupby('year')['salary'].mean().reset_index()
avg_by_year.columns = ['Year', 'Avg_Salary']

print("Average NBA Salary by Year:")
print(avg_by_year.tail(20))

# Compare to salary cap growth
cap = pd.read_csv('cap.csv')
cap_growth = cap[['year', 'Salary Cap']].merge(avg_by_year, left_on='year', right_on='Year')
cap_growth['Cap_vs_AvgSalary_Ratio'] = cap_growth['Salary Cap'] / cap_growth['Avg_Salary']

print("\nSalary Cap vs Average Salary:")
print(cap_growth.tail(10))

Guaranteed Money Leaders

import pandas as pd

df = pd.read_csv('salary.csv')

# Top guaranteed money
top_guaranteed = df.nlargest(30, 'Guaranteed')[['Player', 'Team', 'Guaranteed']]
top_guaranteed['Guaranteed'] = top_guaranteed['Guaranteed'].apply(lambda x: f"${x:,.0f}")

print("Most Guaranteed Money Remaining:")
print(top_guaranteed)

Data Collection Scripts

contract_data.py

Scrapes Spotrac for current contracts and options

salary_scrape.py

Historical salary data collection

price.py

Salary cap information scraper

Important Notes

  • Salary values are in US dollars (not scaled)
  • Guaranteed column accounts for player/team options and non-guaranteed years
  • Some contracts include trade kickers, incentives not reflected in base salary
  • Dead cap is included in team salary totals
Contract data is current as of the last scrape. Mid-season trades, signings, or releases may not be reflected immediately. Re-run contract_data.py to refresh.
Use the Guaranteed column to assess true contract commitments, not just current year salary. This accounts for options and non-guaranteed years.

CBA Rules Reference

  • Salary Cap: Soft cap, teams can exceed via exceptions
  • Luxury Tax: Tax penalty for exceeding threshold
  • First Apron: Restricts some team-building options (no BAE, limited TPE)
  • Second Apron: Severe restrictions (no MLE, can’t aggregate salaries in trades, frozen draft picks)
  • Mid-Level Exception (MLE): Allows over-cap teams to sign players
    • Non-taxpayer MLE: ~$12-13M
    • Taxpayer MLE: ~$5M
  • Bi-Annual Exception (BAE): ~$4-5M, can’t use if over first apron

Build docs developers (and LLMs) love