> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sportrix.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Sportrix Data WebSocket Stream: Real-Time Live Scores

> Connect to the Sportrix Data WebSocket endpoint to receive real-time live scores and statistics. Requires the live_scores_statistics scope.

The Sportrix Data WebSocket stream gives you a persistent, low-latency connection for real-time live scores and statistics. Rather than polling the REST API, you subscribe to one or more matches and receive an immediate snapshot followed by pushed updates whenever the match state changes.

## Endpoint

```
wss://scores.sportrixdata.com/v1/stream
```

**Required scope:** `live_scores_statistics`

## Authentication

Pass your API key as a `?key=` query parameter or an `X-API-Key` header. The query parameter is the most convenient option for WebSocket clients that cannot set custom headers:

```
wss://scores.sportrixdata.com/v1/stream?key=sk_your_api_key_here
```

The connection is rejected with **HTTP 401** if the key is invalid, disabled, expired, or does not have the `live_scores_statistics` scope.

## Keepalive (ping/pong)

The server sends a WebSocket **ping** control frame every **30 seconds** to keep idle connections alive — for example between matches, or when nothing is changing on a quiet match. This prevents proxies and clients from closing the connection on a read/idle timeout.

* **No client action is required.** Most WebSocket libraries (browser `WebSocket`, Python `websockets`, `websocket-client`, Go `gorilla/websocket`, etc.) reply with a pong automatically. You do not need to send anything yourself.
* **Set your read/idle timeout above 30 seconds.** 60 seconds is a safe value. Because the ping is a received frame, it resets your read deadline and prevents premature disconnects.
* **Do not set a read timeout below 30 seconds**, or you'll close the connection between pings. There is no application-level `ping` message to send from the client — the protocol-level ping/pong is handled by your WebSocket library.

### Library examples

<CodeGroup>
  ```python Python (websockets) theme={null}
  import asyncio, websockets

  async def run():
      # Defaults already keep the connection healthy. You can also rely
      # purely on the server's 30s ping by raising the timeouts.
      async with websockets.connect(
          "wss://scores.sportrixdata.com/v1/stream?key=sk_your_api_key_here",
          ping_interval=20,
          ping_timeout=60,
      ) as ws:
          async for msg in ws:
              print(msg)

  asyncio.run(run())
  ```

  ```python Python (websocket-client) theme={null}
  import websocket  # websocket-client

  ws = websocket.WebSocketApp(
      "wss://scores.sportrixdata.com/v1/stream?key=sk_your_api_key_here",
      on_message=lambda _ws, msg: print(msg),
  )
  # ping_interval lets the library answer server pings promptly;
  # leave reads blocking so the 30s server ping resets your read deadline.
  ws.run_forever(ping_interval=30, ping_timeout=None)
  ```

  ```javascript Browser (WebSocket) theme={null}
  // Nothing to do — the browser answers server pings automatically
  // and the WebSocket API has no read timeout to configure.
  const ws = new WebSocket(
    "wss://scores.sportrixdata.com/v1/stream?key=sk_your_api_key_here"
  );
  ws.onmessage = (event) => console.log(event.data);
  ```
</CodeGroup>

## How it works

1. **Connect** to the endpoint with your API key.
2. **Send a subscribe message** with the `match_id` of the match you want to follow (the same id returned by the REST `/matches` endpoints).
3. **Receive a snapshot** immediately after subscribing, then **receive update frames** whenever the match state changes.
4. **Send an unsubscribe message** when you no longer need updates for a match.

A single connection can subscribe to **multiple matches simultaneously**. Every data frame includes a `match_id` field so you can demultiplex frames from different matches on the same connection.

## Subscribe and unsubscribe

Send JSON control messages to the server:

```json theme={null}
{"action": "subscribe", "match_id": 41282}
```

```json theme={null}
{"action": "unsubscribe", "match_id": 41282}
```

<Note>
  Only matches in your enabled sports can be subscribed. Attempting to subscribe to a match outside your sport allowlist returns an `error` frame instead of a snapshot.
</Note>

## Python example

```python theme={null}
import json, websocket  # websocket-client

ws = websocket.create_connection(
    "wss://scores.sportrixdata.com/v1/stream?key=sk_your_api_key_here"
)
ws.send(json.dumps({"action": "subscribe", "match_id": 41282}))
while True:
    msg = json.loads(ws.recv())
    if msg["op"] in ("snapshot", "update"):
        d = msg["data"]
        if d["sport"] == "cricket":  # cricket has its own shape (no clock/phase)
            s = d["score"]
            print(f'{d["batting"]} {s["runs"]}/{s["wickets"]} ({s["overs"]}) '
                  f'- {d["last_event"]["label"]}')
        else:  # soccer
            clock = d["clock"]
            print(f'{d["home"]} {d["score"]["home"]}-{d["score"]["away"]} {d["away"]} '
                  f'[{clock["minute"]}:{clock["second"]:02d} {clock["period"]}] {d["phase"]["label"]}')
    elif msg["op"] == "error":
        print("error:", msg["error"])
```

<Note>
  Always branch on `data["sport"]` — the snapshot schema is sport-specific (soccer carries `clock`/`phase`/`stats`/`events`; cricket carries `score`/`over`/`batsmen`/`bowler`/`scorecard`). See the [live snapshot reference](/api/live-snapshot) for both shapes.
</Note>

<Tip>
  If you only need scores without full match statistics, the REST `GET /matches/{id}/live` endpoint with the `live_scores` scope may be simpler than maintaining a WebSocket connection.
</Tip>

## Next steps

See the [WebSocket Message Reference](/api/websocket-messages) for the complete specification of every client message and server frame.
