THE COURTSIDE VIEW2025–26 SEASON
COURTSIDE VIEW · PROPRIETARY

CR
METHODOLOGY

A full breakdown of how the Courtside Rating is calculated — inputs, normalisation, weighting, and scaling. Component weights are proprietary and not disclosed.

OVERVIEW

CR is built from 5 components made up of 10 underlying metrics. Each metric is normalised to a percentile within its season's player pool, weighted by a proprietary scheme, and scaled to a 0–100 output anchored against historical reference seasons.

ORAPM
DRAPM
BPM
PER
eFG%
RIM FREQ
3PT FREQ
MID FREQ ↓
AST%
POTENTIAL AST
i
The precise weight of each metric is proprietary and not publicly disclosed. This is consistent with industry practice — ESPN's Real Plus-Minus, FiveThirtyEight's RAPTOR, and similar metrics protect their weighting methodology. All inputs and their individual calculations are documented in full below and on the CR Deep Dive page.

STEP 1 — NORMALISE EACH METRIC

Each of the 10 raw metrics is converted to a 0–100 percentile relative to all qualifying players in that season. This puts every metric on the same scale so they can be fairly combined.

percentile(player, metric) = (players with lower value ÷ total players) × 100

For metrics where lower is better (midrange frequency), the ranking is inverted — fewer midrange attempts equals a higher percentile. Qualifying players must average 20+ minutes per game over 50+ games.

STEP 2 — WEIGHT AND SUM

Each normalised percentile is multiplied by its proprietary weight, then all 10 weighted scores are summed. The weights reflect how much each metric contributes to predicting true player impact. All weights sum to 1.0.

raw_score = w₁·p(ORAPM) + w₂·p(DRAPM) + w₃·p(BPM) + w₄·p(PER) + w₅·p(eFG%) + w₆·p(RimFreq) + w₇·p(3PTFreq) + w₈·p(MidFreq) + w₉·p(AST%) + w₁₀·p(PotentialAST) where p(x) = percentile of metric x · weights w₁–w₁₀ are proprietary · Σw = 1

STEP 3 — SCALE USING HISTORICAL ANCHORS

The raw score is scaled using two fixed historical anchor points drawn from our full dataset (2017–18 season onward). Anchors are fixed permanently so that a CR of 90 means the same thing across all seasons.

CR = (raw_score − floor_score) ÷ (ceiling_score − floor_score) × (99 − 30) + 30 floor_score = raw score of a historical replacement-level season → CR ≈ 30 ceiling_score = raw score of the best historical season in the dataset → CR ≈ 99

The floor is set at the 5th percentile of raw scores across all historical player-seasons. The ceiling is set at the 99th percentile. Both are calculated once across all seasons combined and never recalibrated.

CR TIERS

95–99
MVP TIER
Historically elite season
88–94
ALL-NBA
Top 10–15 player
78–87
ALL-STAR
Clear starter, impact player
65–77
SOLID STARTER
Positive contributor
30–64
BENCH / FRINGE
Below average to replacement

DATA SOURCES

All metrics are sourced from the NBA Stats API via the swar/nba_api Python library. Specific endpoints used:

LeagueDashPlayerStats
Per game stats, eFG%, AST%, usage, BPM proxy
LeagueDashPlayerStats (ShotAreaShooting)
Rim frequency, 3PT frequency, midrange frequency
LeagueDashLineups
On/off splits for ORAPM and DRAPM calculation
LeagueDashPtStats (PtAssist)
Potential assists
LeagueDashPtDefend
Defensive FG% by zone, rim deterrence
PlayByPlayV2
Play-by-play for lineup stint calculations
CR is calculated seasonally and updated nightly during the active season. Historical values are available from the 2017–18 season onward. BPM methodology developed by Daniel Myers. PER methodology developed by John Hollinger. Both are applied to NBA Stats API data.