Login Get API Key
Tutorials

How to Build an NBA Roster Page with Injuries and Depth Chart

Illustration of an NBA roster page showing depth chart and injury status

Learn how to build a full team roster page โ€” injury status, contract details, and depth chart position โ€” using Live Basketball API's team/players endpoint.

On this page

An NBA roster page is about more than a player list โ€” fans and fantasy managers want to know who's actually available to play, where each player sits on the depth chart, and contract context. The /team/players endpoint returns all of this in a single call, covering all 30 NBA teams.

What's in a Roster Response

Beyond basic bio data (name, position, height, weight), each player entry includes fields most roster APIs don't offer:

  • Injury status โ€” whether a player is currently injured and why
  • Depth chart position โ€” starter vs second-string vs bench at each position
  • Contract and salary data โ€” annual salary and contract expiry
  • Previous club history โ€” most recent prior team and transfer date

Fetching a Team's Full Roster

import requests

response = requests.get(
    'https://live-basketball-api.com/api/v1/team/players',
    params={'api_key': 'YOUR_KEY', 'team_id': '4kjso6vrhugyaktbc7751ijm1', 'lang': 'en'}
).json()

for player in response['players']:
    status = 'INJURED' if player['injured'] else 'Active'
    print(f"#{player['jersey_number']} {player['name']} ({player['position']}) โ€” {status}")

Building an Injury-Aware Roster List

Surface injury information prominently rather than burying it โ€” this is what most visitors to a roster page actually want to check first before a game:

function RosterRow({ player }) {
  return (
    <tr className={player.injured ? 'row-injured' : ''}>
      <td><img src={player.photo} alt="" /></td>
      <td>{player.name}</td>
      <td>{player.position_name}</td>
      <td>
        {player.injured ? (
          <span className="injury-badge" title={player.injury_reason}>
            ๐Ÿš‘ {player.injury_status || 'Injured'}
          </span>
        ) : (
          <span className="status-active">Active</span>
        )}
      </td>
    </tr>
  );
}

Note that injury_status (a short designation like "day-to-day") can be null even when injured is true โ€” fall back to the generic "Injured" label and rely on injury_reason for the tooltip detail in that case.

Rendering a Depth Chart

The depth field (1 = starter, 2 = second string, etc.) combined with depth_position lets you group players by position and rank without building your own depth-chart logic:

function buildDepthChart(players) {
  const chart = {};

  players.forEach(player => {
    if (player.depth_position === null) return;
    if (!chart[player.depth_position]) chart[player.depth_position] = [];
    chart[player.depth_position].push(player);
  });

  Object.keys(chart).forEach(pos => {
    chart[pos].sort((a, b) => (a.depth || 99) - (b.depth || 99));
  });

  return chart;
}

// { PG: [starter, backup1, backup2], C: [starter, backup1], ... }
function DepthChart({ players }) {
  const chart = buildDepthChart(players);

  return (
    <div className="depth-chart">
      {Object.entries(chart).map(([position, roster]) => (
        <div key={position} className="depth-column">
          <h4>{position}</h4>
          {roster.map(p => (
            <div key={p.id} className={`depth-slot depth-${p.depth}`}>
              {p.name}
            </div>
          ))}
        </div>
      ))}
    </div>
  );
}

Displaying Contract Information

Salary and contract fields are useful for a "front office" style page, but require careful null-handling since not every player's salary is publicly disclosed:

function ContractInfo({ player }) {
  if (player.salary === null) {
    return <span>Salary not disclosed</span>;
  }

  const formatted = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: player.salary_currency || 'USD',
    maximumFractionDigits: 0
  }).format(player.salary);

  return (
    <span>
      {formatted}/yr โ€” under contract until {player.contract_until || 'unknown'}
    </span>
  );
}

Showing Where a Player Came From

previous_clubs gives you the most recent prior team, useful for a "recently joined" badge on new acquisitions:

function ArrivalNote({ player }) {
  if (!player.previous_clubs || player.previous_clubs.length === 0) return null;

  const [latest] = player.previous_clubs;
  return (
    <p className="arrival-note">
      Joined from {latest.team} ({latest.date})
    </p>
  );
}

Putting the Full Page Together

function TeamRosterPage({ teamId }) {
  const [roster, setRoster] = useState(null);

  useEffect(() => {
    fetchTeamPlayers(teamId).then(setRoster);
  }, [teamId]);

  if (!roster) return <Loading />;

  return (
    <div>
      <h1>{roster.team_name} Roster</h1>
      <p>{roster.player_count} players โ€” {roster.league}</p>

      <DepthChart players={roster.players} />

      <table>
        <tbody>
          {roster.players.map(p => <RosterRow key={p.id} player={p} />)}
        </tbody>
      </table>
    </div>
  );
}

Frequently Asked Questions

Does this endpoint work for non-NBA teams?

The endpoint documentation specifically notes coverage of all 30 NBA teams โ€” depth of data (salary, contract, injury detail) for non-NBA leagues may vary or be less complete, since this level of detail is most consistently available for NBA rosters.

Is salary data updated in real time as contracts change?

Treat salary and contract fields as a snapshot rather than guaranteed real-time โ€” for time-sensitive contract news, cross-reference with official league sources rather than relying solely on this field for breaking news accuracy.

What does a null depth value mean?

It typically means the player isn't assigned a specific depth chart slot (e.g. a two-way contract player or someone not in the regular rotation) โ€” filter these out of a depth chart view rather than trying to render them at an arbitrary position.

Can I filter the roster to only injured players?

Yes, since the full roster is returned in one call, filter client-side: roster.players.filter(p => p.injured) โ€” no separate endpoint or parameter is needed for this.

Share this article:
โ† Back to blog