Real-Time with WebSockets (Flask-SocketIO)
A WebSocket keeps a single connection open in both directions, so the server can push live updates to the browser the instant they happen instead of waiting to be asked.
Learn Real-Time with WebSockets (Flask-SocketIO) in our free Flask course — a beginner-friendly interactive lesson with worked examples, a practice exercise…
Part of the free Flask course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll build an event dispatcher and a rooms-and-broadcast model in plain Python, then see the real Flask-SocketIO server and client code.
Plain HTTP is request-response : the client asks, the server answers, the connection closes. To get fresh data the client must ask again (polling). A WebSocket instead opens one long-lived, two-way channel, so the server can push data the moment something changes — perfect for chat, live scores, and dashboards.
Socket.IO models this as named events : you register a handler with @socketio.on("event") and the framework calls it whenever that event arrives. The runnable EventBus below is exactly that idea in miniature — register handlers, then emit events to fire them.
Emitting connect then message runs each registered handler in turn — the same flow Flask-SocketIO drives when a real client connects and sends a message.
Often you don't want to message every client — just those watching one game or chatting in one channel. A room is a named group of clients. The server can emit to a single room, or broadcast to everyone by leaving the room out.
The runnable model below gives each client an outbox. alice and bob join the sports room; carol does not. A score event sent to sports reaches only alice and bob, while a global ping reaches all three.
alice's outbox holds both the score and the ping ; carol's holds only the ping because she never joined sports . That is room-scoped delivery.
A WebSocket has two sides. The browser uses the Socket.IO client library: it connect s, emit s events to the server, and listens with socket.on("event", handler) to receive pushes. The mental model is symmetric with the server's on/emit.
The runnable example simulates that client side — a small object that registers listeners and reacts when the "server" delivers an event — so you can see how a received push updates the UI.
Complete the bus below. Replace each ___ so handlers register and events dispatch.
❌ Running socketio.run but events never arrive
You started the app with app.run() or a plain WSGI server. Flask-SocketIO needs socketio.run(app) (dev) or an async server like eventlet/gevent so it can hold the WebSocket open.
By default emit goes only to the current client. Add broadcast=True for all clients, or room="name" to target a room they've joined.
Build a chat server that echoes each message to everyone except the sender.
Lesson complete — your app can talk back in real time!
You modeled the on/emit event pattern, scoped delivery with rooms, broadcast to everyone, simulated the browser client, and read the real Flask-SocketIO server and JavaScript client.
🚀 Up next: Sending Email — notify users from your app with Flask-Mail.
Practice quiz
How does a WebSocket differ from a normal HTTP request?
- It is slower than HTTP
- It keeps one long-lived two-way connection open
- It only works for images
- It cannot send data to the client
Answer: It keeps one long-lived two-way connection open. A WebSocket opens a single persistent, bidirectional channel so the server can push data anytime.
Which extension adds Socket.IO to a Flask app?
- Flask-WS
- Flask-Realtime
- Flask-Push
- Flask-SocketIO
Answer: Flask-SocketIO. Flask-SocketIO integrates the Socket.IO real-time protocol with Flask.
How do you register a server-side event handler?
- @socketio.on('event')
- @app.route('event')
- @socketio.handle('event')
- @socketio.listen('event')
Answer: @socketio.on('event'). @socketio.on('event') registers a handler that fires when that named event arrives.
Which function sends an event to a client?
- send()
- push()
- emit()
- dispatch()
Answer: emit(). emit('event', data) sends an event; by default in a handler it goes back to the sender.
How do you send an event to every connected client?
- emit(..., broadcast=True)
- emit(..., all=True)
- emit(..., everyone=True)
- broadcast_all(...)
Answer: emit(..., broadcast=True). Passing broadcast=True to emit sends the event to all connected clients.
What is a room in Socket.IO?
- A separate server process
- A database table
- A named group of connected clients
- A type of event
Answer: A named group of connected clients. A room is a named group of clients; you emit to a room to target just that subset.
How does a client join a room inside a handler?
- add_room('name')
- join_room('name')
- room.join('name')
- socketio.join('name')
Answer: join_room('name'). join_room('name') adds the current client to a room so it can receive room-targeted events.
How do you emit an event only to clients in a room?
- emit(..., only='name')
- emit(..., group='name')
- emit(..., room='name')
- emit(..., to_room='name')
Answer: emit(..., room='name'). emit('event', data, room='name') delivers the event only to clients that joined that room.
How does the browser client listen for a pushed event?
- socket.listen('event', fn)
- socket.receive('event', fn)
- socket.handle('event', fn)
- socket.on('event', fn)
Answer: socket.on('event', fn). On the client, socket.on('event', handler) reacts to events the server pushes.
Why can't a plain WSGI server run Flask-SocketIO well?
- It can't hold many long-lived connections efficiently
- It rejects JSON
- It blocks emit()
- It has no routing
Answer: It can't hold many long-lived connections efficiently. Flask-SocketIO needs an async server (eventlet, gevent, or socketio.run) to keep many connections open.