# STATS REALTIME

The STATS\_REALTIME channel delivers only the statistics that have changed, in real-time.

### Availability

| Plan  | Available |
| ----- | --------- |
| BASIC | No        |
| PRO   | No        |
| ULTRA | No        |
| MEGA  | Yes       |

### Update Frequency

Updates are sent **immediately** when statistics change (real-time).

### Events

| Event                   | Description             |
| ----------------------- | ----------------------- |
| stats\_update\_realtime | Changed statistics only |

***

### stats\_update\_realtime

Delivers only the statistics that have changed since the last update.

#### Message

```json
{
  "type": "stats_update_realtime",
  "channel": "STATS_REALTIME",
  "matchId": "12345",
  "leagueId": "67890",
  "ts": 1705314600000,
  "data": {
    "changedStats": [
      {
        "stat": "possession",
        "value": "56;44"
      },
      {
        "stat": "corners",
        "value": "5;2"
      },
      {
        "stat": "shotsOnTarget",
        "value": "5;2"
      }
    ]
  }
}
```

#### Data Fields

| Field                  | Type   | Description                       |
| ---------------------- | ------ | --------------------------------- |
| `changedStats`         | array  | Array of changed statistics       |
| `changedStats[].stat`  | string | Statistic name                    |
| `changedStats[].value` | string | New value in "teamA;teamB" format |

#### Available Statistics

| Stat Name          | Description          |
| ------------------ | -------------------- |
| `timer`            | Current match minute |
| `extraTimer`       | Extra time minutes   |
| `status`           | Match status         |
| `score`            | Current score        |
| `score1h`          | First half score     |
| `score2h`          | Second half score    |
| `possession`       | Ball possession %    |
| `attacks`          | Total attacks        |
| `dangerousAttacks` | Dangerous attacks    |
| `shotsOnTarget`    | Shots on target      |
| `shotsOffTarget`   | Shots off target     |
| `totalShots`       | Total shots          |
| `shotsBlocked`     | Blocked shots        |
| `corners`          | Total corners        |
| `corners1h`        | First half corners   |
| `fouls`            | Fouls committed      |
| `yellowCards`      | Yellow cards         |
| `redCards`         | Red cards            |
| `yellowToRed`      | Second yellow cards  |
| `substitutions`    | Substitutions        |
| `throwIns`         | Throw-ins            |
| `injuries`         | Injuries             |
| `penalties`        | Penalties awarded    |
| `offsides`         | Offsides             |
| `xg`               | Expected goals       |

***

### Subscription Examples

#### Subscribe to all real-time stats updates

NO scope "all" allowed

#### Subscribe to a specific match

```json
{"action": "subscribe", "channel": "STATS_REALTIME", "scope": "match", "id": "b01d28ac92221034"}
```

#### Subscribe to a league

```json
{"action": "subscribe", "channel": "STATS_REALTIME", "scope": "league", "id": "f2b16fa54cb525d"}
```

***

### Example: Maintaining Local State

```javascript
// Local state for match statistics
const matchStats = {};

function initializeStats(matchId) {
  matchStats[matchId] = {
    timer: '0',
    possession: '50;50',
    corners: '0;0',
    shotsOnTarget: '0;0',
    shotsOffTarget: '0;0',
    fouls: '0;0',
    yellowCards: '0;0',
    redCards: '0;0'
    // ... other stats initialized to defaults
  };
}

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  if (msg.type !== 'stats_update_realtime') return;

  const matchId = msg.matchId;

  // Initialize if first update for this match
  if (!matchStats[matchId]) {
    initializeStats(matchId);
  }

  // Apply delta updates
  msg.data.changedStats.forEach(change => {
    const oldValue = matchStats[matchId][change.stat];
    matchStats[matchId][change.stat] = change.value;

    console.log(`[${matchId}] ${change.stat}: ${oldValue} → ${change.value}`);
  });

  // Now matchStats[matchId] contains the current state
  console.log('Current stats:', matchStats[matchId]);
};
```

### Example: Detecting Specific Changes

```javascript
ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  if (msg.type !== 'stats_update_realtime') return;

  msg.data.changedStats.forEach(change => {
    switch (change.stat) {
      case 'corners':
        const [homeCorners, awayCorners] = change.value.split(';').map(Number);
        console.log(`Corner! Home: ${homeCorners}, Away: ${awayCorners}`);
        break;

      case 'yellowCards':
        const [homeYellow, awayYellow] = change.value.split(';').map(Number);
        console.log(`Yellow card! Home: ${homeYellow}, Away: ${awayYellow}`);
        break;

      case 'redCards':
        const [homeRed, awayRed] = change.value.split(';').map(Number);
        if (homeRed > 0 || awayRed > 0) {
          console.log(`RED CARD! Home: ${homeRed}, Away: ${awayRed}`);
        }
        break;

      case 'possession':
        const [homePoss, awayPoss] = change.value.split(';').map(Number);
        console.log(`Possession update: ${homePoss}% - ${awayPoss}%`);
        break;
    }
  });
};
```

***

### Comparison: STATS vs STATS\_REALTIME

| Feature           | STATS         | STATS\_REALTIME |
| ----------------- | ------------- | --------------- |
| Update frequency  | 30-60 seconds | Real-time       |
| Data sent         | Full snapshot | Delta only      |
| Bandwidth usage   | Higher        | Lower           |
| State management  | Not required  | Required        |
| Plan availability | ULTRA, MEGA   | MEGA only       |

### Best Practices

1. **Maintain local state**: Keep a local copy of statistics and apply deltas
2. **Handle reconnections**: On reconnect, subscribe to STATS first for a full snapshot, then switch to STATS\_REALTIME
3. **Combine channels**: Use STATS for initial state and STATS\_REALTIME for updates
4. **Handle missing matches**: Initialize stats when you receive the first update for a match

### Notes

* Only changed statistics are included in each message
* An empty `changedStats` array means no changes (rare, but possible)
* For a complete snapshot, use the STATS channel
* This channel requires client-side state management


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://info.soccerfootball.info/websocket/channels/stats-realtime.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
