MoviOdds Docs
API docs Sports Markets Bet Builder Python moviodds.com

bet365 odds WebSocket feed

Live bet365 prices pushed to you as JSON when they change, instead of polling. One connection covers every match and sport. Free, no key.

Connect and subscribe

wss://moviodds.com/ws

Once connected, send a subscribe message. Leave out both lists to get every match and market:

{"op": "subscribe"}

Or narrow it down by match ids, market groups, or both:

{"op": "subscribe", "groups": ["1777", "67"]}
{"op": "subscribe", "fixtures": ["202138001"]}

Group 1777 is the in-play soccer Full Time Result and 67 the in-play tennis match winner. The sports page lists the winner groups for every sport.

Messages

First you get a snapshot per match with all its current prices. After that, a delta arrives whenever a price changes, carrying only the changed quotes. A real delta:

{
  "type": "delta",
  "fixture": "202138001",
  "quotes": [{
    "fixture_id": "202138001",
    "group_id": "1777",
    "group_name": "Fulltime Result",
    "sel_id": "128575935",
    "label": "Draw",
    "n2": "X",
    "odds_dec": 2.05,
    "odds_frac": "21/20",
    "ts": "2026-10-05T02:39:10.528360129Z"
  }],
  "server_time": "2026-10-05T02:39:10.528647673Z"
}

Python example

import asyncio, json, websockets

async def main():
    async with websockets.connect("wss://moviodds.com/ws", max_size=None) as ws:
        await ws.send(json.dumps({"op": "subscribe", "groups": ["1777"]}))
        async for raw in ws:
            msg = json.loads(raw)
            if msg.get("type") in ("snapshot", "delta"):
                for q in msg["quotes"]:
                    print(msg["type"], msg["fixture"], q.get("label"), q["odds_dec"],
                          "SUSP" if q.get("suspended") else "")

asyncio.run(main())

JavaScript example

const ws = new WebSocket("wss://moviodds.com/ws");
ws.onopen = () => ws.send(JSON.stringify({ op: "subscribe", groups: ["1777"] }));
ws.onmessage = (ev) => {
  const msg = JSON.parse(ev.data);
  if (msg.type === "snapshot" || msg.type === "delta") {
    for (const q of msg.quotes) console.log(msg.type, msg.fixture, q.label, q.odds_dec);
  } else if (msg.type === "remove") {
    // No quotes: the whole match is gone. Otherwise drop just the listed selections.
    console.log("remove", msg.fixture, (msg.quotes || []).length || "whole match");
  }
};

It runs in the browser too: the moviodds.com live board is built on this socket.

Changing a subscription

Live match stats

When match stats are on, add "stats": true to your subscribe to also get the live stats of in-play matches:

{"op": "subscribe", "stats": true}
{"type": "stats", "fixture": "202138001", "stats": {"sport": "soccer", "home": {"attacks": 41, "possession": 55}, "away": {"attacks": 37, "possession": 45}}, "server_time": "2026-10-17T20:01:02Z"}

Snapshots are complete

Every subscribe sends one snapshot per subscribed match we currently carry, with every current selection, suspended ones included. Replace the match's prices with it. A selection missing from the snapshot is gone. A match we no longer carry gets no snapshot, so drop it. There is no "snapshot finished" message, so don't wait for one. You don't need a REST reload after reconnecting; the snapshot is enough.

Heartbeats, closes and reconnects

Up to 25 connections per IP. Each connection's first 3 subscribe/unsubscribe messages apply at once, then one every 2 seconds; extra ones are merged and the latest wins. Full details are in the API docs.

FAQ

Is the bet365 odds WebSocket free?

Yes. No sign-up and no key. Up to 25 connections per IP.

How fast are the updates?

In-play changes arrive within about a second of bet365 making them. Pre-match changes arrive when we next read the match: every few seconds near kickoff, up to every 30 minutes for matches days away.

Which sports stream live?

All 24 we cover, including soccer, tennis, basketball, American football, ice hockey, baseball, cricket, table tennis and esports.

Do I need to poll as well?

No. Every subscribe sends a complete snapshot of each match you subscribe to, so you can run from the WebSocket alone. /odds is there if you prefer to load the board over REST.

Are these really bet365 odds?

Yes, only bet365's own prices. MoviOdds is an independent project and is not affiliated with bet365.

More: closing lines · historical odds · all 24 sports · Python client · API docs