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.