> For the complete documentation index, see [llms.txt](https://info.soccerfootball.info/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://info.soccerfootball.info/websocket/channels/odds-realtime.md).

# ODDS REALTIME

## ODDS\_REALTIME Channel

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

### Availability

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

### Update Frequency

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

### Events

| Event                  | Description       |
| ---------------------- | ----------------- |
| odds\_update\_realtime | Changed odds only |

***

### odds\_update\_realtime

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

#### Message

```json
{
  "type": "odds_update_realtime",
  "channel": "ODDS_REALTIME",
  "matchId": "12345",
  "leagueId": "67890",
  "ts": 1705314600000,
  "data": {
    "changedOdds": [
      {
        "market": "live1x2",
        "value": "1.75;3.80;4.50"
      },
      {
        "market": "liveOU",
        "value": "2.20;1.65|2.5"
      }
    ]
  }
}
```

#### Data Fields

| Field                  | Type   | Description           |
| ---------------------- | ------ | --------------------- |
| `changedOdds`          | array  | Array of changed odds |
| `changedOdds[].market` | string | Market name           |
| `changedOdds[].value`  | string | New odds value        |

#### Available Markets

| Market Name             | Format                  | Description                 |
| ----------------------- | ----------------------- | --------------------------- |
| `kickoff1x2`            | `"home;draw;away"`      | 1X2 at kickoff              |
| `live1x2`               | `"home;draw;away"`      | Live 1X2                    |
| `starting1x2`           | `"home;draw;away"`      | Opening 1X2                 |
| `kickoffOU`             | `"over;under\|line"`    | O/U at kickoff              |
| `liveOU`                | `"over;under\|line"`    | Live O/U                    |
| `startingOU`            | `"over;under\|line"`    | Opening O/U                 |
| `kickoffAH`             | `"home;away\|handicap"` | AH at kickoff               |
| `liveAH`                | `"home;away\|handicap"` | Live AH                     |
| `startingAH`            | `"home;away\|handicap"` | Opening AH                  |
| `kickoffAsianCorners`   | `"over;under\|line"`    | Asian Corners at kickoff    |
| `liveAsianCorners`      | `"over;under\|line"`    | Live Asian Corners          |
| `kickoff1hAH`           | `"home;away\|handicap"` | 1H AH at kickoff            |
| `live1hAH`              | `"home;away\|handicap"` | Live 1H AH                  |
| `kickoff1hGoals`        | `"over;under\|line"`    | 1H O/U at kickoff           |
| `live1hGoals`           | `"over;under\|line"`    | Live 1H O/U                 |
| `kickoff1hAsianCorners` | `"over;under\|line"`    | 1H Asian Corners at kickoff |
| `live1hAsianCorners`    | `"over;under\|line"`    | Live 1H Asian Corners       |
| `kickoff1hResult`       | `"home;draw;away"`      | 1H Result at kickoff        |
| `live1hResult`          | `"home;draw;away"`      | Live 1H Result              |
| `dropping1x2`           | `"home;draw;away"`      | 1X2 odds change             |

***

### Subscription Examples

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

NO scope "all" allowed

#### Subscribe to a specific match

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

#### Subscribe to a league

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

***

### Example: Maintaining Local State

```javascript
// Local state for match odds
const matchOdds = {};

function initializeOdds(matchId) {
  matchOdds[matchId] = {
    live1x2: null,
    liveOU: null,
    liveAH: null,
    liveAsianCorners: null,
    live1hAH: null,
    live1hGoals: null
    // ... other markets initialized to null
  };
}

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

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

  const matchId = msg.matchId;

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

  // Apply delta updates
  msg.data.changedOdds.forEach(change => {
    const oldValue = matchOdds[matchId][change.market];
    matchOdds[matchId][change.market] = change.value;

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

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

### Example: Tracking 1X2 Movement

```javascript
const oddsHistory = {};

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

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

  msg.data.changedOdds.forEach(change => {
    if (change.market === 'live1x2') {
      const matchId = msg.matchId;
      const [home, draw, away] = change.value.split(';').map(parseFloat);

      // Initialize history
      if (!oddsHistory[matchId]) {
        oddsHistory[matchId] = [];
      }

      // Record change with timestamp
      const lastEntry = oddsHistory[matchId][oddsHistory[matchId].length - 1];
      oddsHistory[matchId].push({
        ts: msg.ts,
        home,
        draw,
        away,
        homeChange: lastEntry ? (home - lastEntry.home).toFixed(2) : 0,
        awayChange: lastEntry ? (away - lastEntry.away).toFixed(2) : 0
      });

      // Detect significant movement
      if (lastEntry) {
        const homeMove = home - lastEntry.home;
        const awayMove = away - lastEntry.away;

        if (homeMove < -0.10) {
          console.log(`ALERT: Home odds dropping significantly (${homeMove.toFixed(2)})`);
        }
        if (awayMove < -0.10) {
          console.log(`ALERT: Away odds dropping significantly (${awayMove.toFixed(2)})`);
        }
      }
    }
  });
};
```

### Example: Real-time Odds Display

```javascript
function parse1x2(value) {
  if (!value) return { home: '-', draw: '-', away: '-' };
  const [home, draw, away] = value.split(';');
  return { home, draw, away };
}

function parseOU(value) {
  if (!value) return { over: '-', under: '-', line: '-' };
  const [odds, line] = value.split('|');
  const [over, under] = odds.split(';');
  return { over, under, line };
}

function parseAH(value) {
  if (!value) return { home: '-', away: '-', handicap: '-' };
  const [odds, handicap] = value.split('|');
  const [home, away] = odds.split(';');
  return { home, away, handicap };
}

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

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

  msg.data.changedOdds.forEach(change => {
    switch (change.market) {
      case 'live1x2':
        const m1x2 = parse1x2(change.value);
        console.log(`1X2: ${m1x2.home} | ${m1x2.draw} | ${m1x2.away}`);
        break;

      case 'liveOU':
        const ou = parseOU(change.value);
        console.log(`O/U ${ou.line}: Over ${ou.over} | Under ${ou.under}`);
        break;

      case 'liveAH':
        const ah = parseAH(change.value);
        console.log(`AH (${ah.handicap}): ${ah.home} | ${ah.away}`);
        break;
    }
  });
};
```

***

### Comparison: ODDS vs ODDS\_REALTIME

| Feature           | ODDS          | ODDS\_REALTIME |
| ----------------- | ------------- | -------------- |
| Update frequency  | 15-30 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 odds and apply deltas
2. **Handle reconnections**: On reconnect, subscribe to ODDS first for a full snapshot, then switch to ODDS\_REALTIME
3. **Combine channels**: Use ODDS for initial state and ODDS\_REALTIME for updates
4. **Track history**: Store odds history if you need to analyze movement patterns
5. **Handle null values**: Some markets may not be available for all matches

### Notes

* Only changed markets are included in each message
* An empty `changedOdds` array means no changes (rare, but possible)
* For a complete snapshot, use the ODDS channel
* This channel requires client-side state management
* Odds changes can be frequent during live matches, especially near key events
