DEV Community

Joey Umanito
Joey Umanito

Posted on

How to Build a Real-Time Chat App with Python and WebSockets

Real-time features are everywhere: live chat, notifications, collaborative editing. WebSockets make this possible, and Python makes it easy. Let's build a real-time chat application from scratch.

What We're Building

A simple chat room where multiple users can send and receive messages instantly — no page refresh needed.

Setup

pip install websockets asyncio
Enter fullscreen mode Exit fullscreen mode

The Server (server.py)

import asyncio
import websockets
import json
from datetime import datetime

# Store connected clients
connected_clients = set()

async def handle_client(websocket, path):
    # Register new client
    connected_clients.add(websocket)
    print(f"New client connected. Total: {len(connected_clients)}")

    try:
        async for message in websocket:
            data = json.loads(message)

            # Broadcast to all connected clients
            broadcast_message = json.dumps({
                "user": data.get("user", "Anonymous"),
                "message": data.get("message", ""),
                "timestamp": datetime.now().strftime("%H:%M:%S")
            })

            # Send to all clients except sender
            await asyncio.gather(
                *[client.send(broadcast_message) 
                  for client in connected_clients 
                  if client != websocket]
            )
    except websockets.exceptions.ConnectionClosed:
        pass
    finally:
        connected_clients.remove(websocket)
        print(f"Client disconnected. Total: {len(connected_clients)}")

async def main():
    async with websockets.serve(handle_client, "localhost", 8765):
        print("WebSocket server running on ws://localhost:8765")
        await asyncio.Future()  # Run forever

if __name__ == "__main__":
    asyncio.run(main())
Enter fullscreen mode Exit fullscreen mode

The Client (client.html)

<!DOCTYPE html>
<html>
<head>
    <title>Real-Time Chat</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; }
        #messages { height: 400px; overflow-y: scroll; border: 1px solid #ccc; padding: 10px; }
        .message { margin: 5px 0; padding: 8px; background: #f0f0f0; border-radius: 4px; }
        input { width: 70%; padding: 10px; }
        button { padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; }
    </style>
</head>
<body>
    <h2>Real-Time Chat Room</h2>
    <div id="messages"></div>
    <br>
    <input type="text" id="username" placeholder="Your name" value="User1">
    <input type="text" id="messageInput" placeholder="Type a message...">
    <button onclick="sendMessage()">Send</button>

    <script>
        const ws = new WebSocket('ws://localhost:8765');
        const messagesDiv = document.getElementById('messages');

        ws.onmessage = function(event) {
            const data = JSON.parse(event.data);
            const msgDiv = document.createElement('div');
            msgDiv.className = 'message';
            msgDiv.textContent = `[${data.timestamp}] ${data.user}: ${data.message}`;
            messagesDiv.appendChild(msgDiv);
            messagesDiv.scrollTop = messagesDiv.scrollHeight;
        };

        function sendMessage() {
            const username = document.getElementById('username').value;
            const message = document.getElementById('messageInput').value;

            ws.send(JSON.stringify({ user: username, message: message }));
            document.getElementById('messageInput').value = '';
        }

        document.getElementById('messageInput').addEventListener('keypress', function(e) {
            if (e.key === 'Enter') sendMessage();
        });
    </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Adding Features

User Join/Leave Notifications

async def handle_client(websocket, path):
    # Send welcome message
    await websocket.send(json.dumps({
        "user": "System",
        "message": "Welcome to the chat!",
        "timestamp": datetime.now().strftime("%H:%M:%S")
    }))

    # Notify others
    connected_clients.add(websocket)
    join_message = json.dumps({
        "user": "System",
        "message": "A new user joined the chat",
        "timestamp": datetime.now().strftime("%H:%M:%S")
    })
    await asyncio.gather(
        *[client.send(join_message) for client in connected_clients if client != websocket]
    )
Enter fullscreen mode Exit fullscreen mode

Message History

message_history = []

async def handle_client(websocket, path):
    # Send last 50 messages to new client
    for msg in message_history[-50:]:
        await websocket.send(msg)
Enter fullscreen mode Exit fullscreen mode

Deploying to Production

  1. Railway.app (free tier): Deploy your WebSocket server
  2. Nginx: Proxy WebSocket connections
  3. SSL: Use wss:// for secure connections
location /ws {
    proxy_pass http://localhost:8765;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}
Enter fullscreen mode Exit fullscreen mode

Real-World Applications

This same architecture powers:

  • Live customer support chat
  • Collaborative document editing
  • Real-time dashboards
  • Multiplayer game state sync
  • Live auction bidding systems

Need a Custom Real-Time Application?

Building a chat system, live dashboard, or real-time notification system for your business?


What real-time features are you building? Share in the comments!

Top comments (0)