Войти Получить API-ключ
Tutorials

How to Get Live Set-by-Set Scores and Player Stats in Volleyball

Illustration of a live volleyball scoreboard showing set-by-set scores and player stats
Кратко

Learn how to fetch live set-by-set scores and per-player match statistics using Live Volleyball API's live_match_details endpoint.

На этой странице

Volleyball scoring works differently from most sports — matches are won by sets, and each set has its own point tally. Building a proper live match view means showing both the overall set count and the point-by-point score of the set in progress, plus per-player stats once they're available. This guide covers exactly that using /live_match_details.

Two Endpoints, Two Jobs

It's worth being clear about the split between the two main live endpoints:

  • /matches — the quick live board: current set count, and current_set_points for the set in progress
  • /live_match_details — the full picture: complete set-by-set score history, venue, broadcast info, bracket position, and per-player statistics

Use /matches for a scrolling live scores list, and /live_match_details once a user taps into a specific match.

Fetching the Full Set-by-Set Score

The score object breaks down every set played so far, not just the current tally:

import requests

response = requests.get(
    'https://live-volleyball-api.com/api/v1/live_match_details',
    params={'api_key': 'YOUR_KEY', 'match_id': match_id, 'lang': 'en'}
).json()

data = response['data']
score = data['score']

print(f"Sets: {score['home']} - {score['away']}")
for i, set_score in enumerate(score['sets'], 1):
    print(f"  Set {i}: {set_score['home']}-{set_score['away']}")

The same call in JavaScript:

const res = await fetch(
  'https://live-volleyball-api.com/api/v1/live_match_details' +
  `?api_key=YOUR_KEY&match_id=${matchId}&lang=en`
);
const result = await res.json();
const score = result.data.score;

score.sets.forEach((set, i) => {
  console.log(`Set ${i + 1}: ${set.home}-${set.away}`);
});

Identifying the Live In-Progress Set

While a match is live, the last entry in the sets array is the set currently being played — its point values update as the match progresses, so it's the one worth highlighting differently in your UI:

function renderSets(sets, isLive) {
  return sets.map((set, i) => {
    const isCurrent = isLive && i === sets.length - 1;
    return (
      <span key={i} className={isCurrent ? 'set-live' : 'set-final'}>
        {set.home}-{set.away}
      </span>
    );
  });
}

Handling a Match That Hasn't Started

score is null before kickoff — always check before accessing its fields:

if (data.score === null) {
  showKickoffCountdown(data.date_time);
} else {
  renderScoreboard(data.score);
}

Fetching Per-Player Match Statistics

The statistics object returns a dynamic set of columns (points, attack%, block, serve%, ace, reception%) per player, plus a team total row. Since the exact columns vary by competition, read them from statistics.columns rather than hardcoding field names:

const stats = data.statistics;

if (stats) {
  console.log('Columns:', stats.columns);

  stats.home.forEach(player => {
    const row = stats.columns.map(col => `${col}: ${player.stats[col]}`).join(', ');
    console.log(row);
  });

  console.log('Team total:', stats.home_total);
}

Building a Player Stats Table

function PlayerStatsTable({ statistics, side }) {
  if (!statistics || statistics[side].length === 0) {
    return <p>Stats not available for this match</p>;
  }

  return (
    <table>
      <thead>
        <tr>
          {statistics.columns.map(col => <th key={col}>{col}</th>)}
        </tr>
      </thead>
      <tbody>
        {statistics[side].map(player => (
          <tr key={player.player_id}>
            {statistics.columns.map(col => (
              <td key={col}>{player.stats[col] || '—'}</td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  );
}

Why Statistics Can Be Missing for One Side

Statistics availability isn't always symmetric — one team's row can be populated while the other's away array is empty and away_total is null, depending on what the upstream feed provides for that specific competition. Always render each side independently rather than assuming both are present together:

function hasStats(statsSide) {
  return Array.isArray(statsSide) && statsSide.length > 0;
}

Combining Score and Stats in One View

function MatchLiveView({ data }) {
  return (
    <div>
      {data.score ? (
        <SetScoreboard score={data.score} isLive={data.status?.is_live} />
      ) : (
        <KickoffCountdown dateTime={data.date_time} />
      )}

      {data.statistics && (
        <>
          <PlayerStatsTable statistics={data.statistics} side="home" />
          <PlayerStatsTable statistics={data.statistics} side="away" />
        </>
      )}
    </div>
  );
}

Frequently Asked Questions

Is the score field the same as current_set_points from /matches?

No, current_set_points in /matches is just the live point score of the in-progress set — score.sets in /live_match_details gives the full history of every completed and in-progress set together.

Are player statistics available for every league?

No, statistics is only available for some leagues and matches — always check for null before rendering a stats table, and show a fallback message otherwise.

Do I need to poll live_match_details for score updates, or is matches enough?

For a match list view, /matches alone is enough. Poll /live_match_details only for the specific match a user has open, since it's a heavier response with more fields to update.

What does an empty reception (Rec) value mean for a player?

An empty string for a stat like Rec or Rec% typically means that player didn't register any actions in that category during the match — treat it as "no data" rather than zero.

Поделиться статьёй:
← Назад в блог