Growing Discord community — direct access to the developer, live coverage & picks. Join the Discord Join now →
Leagues Matches Predictions Stats Coverage
Docs / Guides addon

Connect to live WebSockets#

Polling tells you the score every few seconds; the WebSocket pushes it the moment it changes. This guide gets you from zero to a working connection. Channel-level frame references: Football · Tennis.

What you need#

  1. An API token (Authentication).
  2. The WebSocket addon ($3/mo) from /addons/. Without it the server accepts the connection, sends an error frame and closes with code 4402.

Pick a channel#

URL Use for
wss://sports.bzzoiro.com/live/football/ Football — recommended. Score, stats, ball position, odds; on covered matches also per-action events with pitch coordinates
wss://sports.bzzoiro.com/ws/live/ Multi-sport legacy channel — football and tennis on one socket ("sport": "tennis" on subscribe)

Authenticate#

Two transports for the same token:

// Option A — query string (simplest)
const ws = new WebSocket("wss://sports.bzzoiro.com/live/football/?token=YOUR_API_KEY");

// Option B — WebSocket subprotocol (keeps the token out of URL logs; preferred)
const ws = new WebSocket("wss://sports.bzzoiro.com/live/football/", ["token", "YOUR_API_KEY"]);

Authentication failures close the socket after an explanatory error frame:

Close code Meaning
4401 Missing or invalid token
4402 Token OK but no active WebSocket subscription
4404 Unknown WebSocket path

Subscribe#

Send JSON frames. Up to 10 concurrent subscriptions per socket.

{"action": "subscribe",   "event_id": 223510}
{"action": "subscribe",   "event_id": 223510, "bookmaker_slug": "pinnacle"}
{"action": "unsubscribe", "event_id": 223510}
{"action": "ping"}

Which matches are live-trackable? The REST live list flags them: GET /api/v2/events/live/live_websocket: true (and websocket_plus: true for full per-action coverage). Bookmaker slugs come from GET /api/v2/bookmakers/.

The server confirms with a subscribed frame containing a full snapshot (event state, recent positional data, current odds), then streams updates.

Minimal working client#

const ws = new WebSocket("wss://sports.bzzoiro.com/live/football/", ["token", "YOUR_API_KEY"]);

ws.onopen = () => ws.send(JSON.stringify({ action: "subscribe", event_id: 223510 }));

ws.onmessage = (msg) => {
  const frame = JSON.parse(msg.data);
  switch (frame.type) {
    case "subscribed": console.log("snapshot", frame.event, frame.odds); break;
    case "event":      console.log("score", frame.score, frame.time.display); break;
    case "livedata":   console.log("ball", frame.situation, frame.coordinates); break;
    case "action":     console.log("action", frame.action_type, frame.x, frame.y); break;
    case "odds":       console.log("odds", frame.odds); break;
    case "error":      console.warn(frame.code, frame.message);
  }
};

ws.onclose = (e) => {
  if (e.code === 4401) console.error("bad token");
  else if (e.code === 4402) console.error("subscription required — /addons/");
  else setTimeout(connect, 3000);   // transient — reconnect with backoff
};
import asyncio, json, websockets

async def main():
    url = "wss://sports.bzzoiro.com/live/football/?token=YOUR_API_KEY"
    async with websockets.connect(url) as ws:
        await ws.send(json.dumps({"action": "subscribe", "event_id": 223510}))
        async for raw in ws:
            frame = json.loads(raw)
            if frame["type"] == "event":
                print(frame["score"], frame["time"]["display"])

asyncio.run(main())

Staying connected#

  • The server pings every 25 s; browsers and standard libraries answer automatically. If you implement your own client, reply to pings or you'll be dropped after ~20 s.
  • On unexpected close (not 4401/4402), reconnect with exponential backoff and re-send your subscriptions — subscriptions do not survive a reconnect.
  • {"action":"ping"}{"type":"pong"} works as an application-level liveness check.
  • Malformed JSON gets an error frame (bad_json) but the socket stays open.

Try it without code#

The live debug console connects with a demo token and shows raw frames for any currently-covered match — the fastest way to see real payloads before writing a client.

View this page as Markdown · Found a mistake? Tell us