How the numbers are built

Capster prefers working software over a complete CBA encyclopedia. Every calculator on the site uses the same pure functions, and those functions have unit tests. Read this page before you treat a dollar as gospel.

Data

  • Contracts: historical_contracts.parquet from the nflverse-data contracts release (OTC-sourced). CSV is a flat companion and omits nested year rows — ingest uses parquet.
  • Timestamp: timestamp.json on that same release. Currently 2026-09-05 07:13:51 EDT.
  • Rosters: nflverse roster_2026.csv for GSIS IDs, current club, and active/inactive status. Contract year-team is only the fallback when there is no roster row.
  • Player stats: nflverse stats_player_week_{season}.parquet from the stats_player release (same table as nflreadr::load_player_stats). Regular season only. As-of comes from that release's timestamp.json. Snapshot: data/player_stats.json. Web Stats lists the full Capster roster (no volume cutoff). O-line and D-line snaps come from PFR load_snap_counts (joined on pfr_id). DL QB pressures / hurries / hits come from PFR advanced defense. OL "pressures allowed" is the team's QB times_pressured total (unit-level, not per lineman). Pancakes and per-lineman pressures allowed are not in nflverse — those columns stay empty. An optional "Qualified only" toggle restores the old volume gates.
  • Refresh with npm run ingest. Daily snap / line-stat refresh is npm run ingest:stats (or ingest:snaps) without CAPSTER_SKIP_DOWNLOAD. Snapshot meta records each nflverse feed name and as-of timestamp. Capster does not scrape PFF, SIS, ESPN, or NFL.com. Pancakes and per-lineman pressures allowed stay empty until a licensed dump or official API exists.

Cap math assumptions

  1. Year-by-year figures come from nflverse historical_contracts (OTC-sourced). Amounts are converted from millions of dollars to whole dollars.
  2. Current club is the nflverse roster_{season} team when a GSIS row exists. Contract season_history / OTC year-team is the fallback — it lags cutdown, waiver, and trade windows.
  3. Current-year cap hit is that season's cap_number. Empty years[] or a missing season row is N/A — not a fake $0 — and those contracts are excluded from roster-cap sums and top-contract lists.
  4. Remaining bonus = leftover prorated_bonus + option_bonus for this season and later. Remaining guaranteed salary is the sum of guaranteed_salary on those same rows.
  5. Standard cut: dead cap this year ≈ remaining bonus + remaining guaranteed salary. Savings = current cap hit − dead cap (can be negative).
  6. June 1 designation: this year takes this year's bonus + this year's guaranteed salary; leftover bonus and future guaranteed salary are booked next year.
  7. 1-for-1 / sandbox trade: the sending club keeps remaining bonus as dead money. The receiving club takes this year's cap hit minus this year's bonus (salary, roster, workout, other).
  8. Room vs league cap = published league cap − summed season cap_number for contracts that have a year row. Dead money is not modeled (estimatedDeadMoney stays 0). This is an active-cap load gap, not OTC-accurate space. LTBE, top-51, and carryover are also missing.
  9. season_history on each nflverse row is career-long, so inactive contract rows are not used as dead-money sources (they would double-count stars).
  10. Yrs Left (and the fairness yearsLeft term) counts playing seasons through the last year with cash_paid > 0. Void / poison-pill rows stay on the year table and in cut / dead-cap math.
  11. Option / void / injury guarantees, restructures, and splits are incomplete. Treat every dollar as a best-effort estimate pending an OTC API enrichment.

Fairness score

The fairness score is a toy heuristic — not a front office model. It blends remaining APY, years left, leftover guaranteed salary, and a position weight (quarterbacks count more; specialists less). A score of 100 is perfectly even; the lean says which locker room is asking more.

Per player: APY × yearsLeft^0.65 × positionWeight × (1 + 0.2 × guaranteedShare). Score is 100 × min(A,B) / max(A,B). Lean flips if one side is more than 8% higher.

PositionWeight
QB1.85
LT1.25
EDGE1.22
T1.20
OT1.20
RT1.15
DE1.15
WR1.15
CB1.12
OLB1.10
DT1.05
IDL1.05
TE1.05
S1.00
FS1.00
SS1.00
NT1.00
G1.00
OG1.00
C1.00
LB1.00
ILB1.00
MLB1.00
RB0.72
FB0.55
K0.35
P0.30
LS0.25

OTC enrichment TODOs

  • Replace nflverse parquet ingest with an official Over The Cap API when a key is available (same CapsterDataProvider interface).
  • Pull true dead-money tables, June 1 flags, void-year schedules, and option-exercise triggers.
  • Add team-level carryover, top-51 offseason math, and LTBE/NLTBE incentives.
  • Join more stable IDs (PFR / OTC / GSIS) and weekly roster status.