Quick start - websockets 10.1 documentation
Description: Here are a few examples to get you started quickly with websockets. Hello world!: Here’s a WebSocket server. It receives a name from the client, sends a greeting, and closes the connection. serve()...

Hide navigation sidebar
Hide table of contents sidebar
Toggle table of contents sidebar

# Quick start

Here are a few examples to get you started quickly with websockets.

## Hello world!

Here’s a WebSocket server.

It receives a name from the client, sends a greeting, and closes the connection.

    #!/usr/bin/env python

    import asyncio
    import websockets

    async def hello(websocket):
        name = await websocket.recv()
        print(f"<<< {name}")

        greeting = f"Hello {name}!"

        await websocket.send(greeting)
        print(f">>> {greeting}")

    async def main():
        async with websockets.serve(hello, "localhost", 8765):
            await asyncio.Future()  # run forever

    if __name__ == "__main__":
        asyncio.run(main())

`serve()` executes the connection handler coroutine `hello()` once for each WebSocket connection. It closes the WebSocket connection when the handler returns.

Here’s a corresponding WebSocket client.

It sends a name to the server, receives a greeting, and closes the connection.

    #!/usr/bin/env python

    import asyncio
    import websockets

    async def hello():
        uri = "ws://localhost:8765"
        async with websockets.connect(uri) as websocket:
            name = input("What's your name? ")

            await websocket.send(name)
            print(f">>> {name}")

            greeting = await websocket.recv()
            print(f"<<< {greeting}")

    if __name__ == "__main__":
        asyncio.run(hello())

Using `connect()` as an asynchronous context manager ensures the WebSocket connection is closed.

## Encryption

Secure WebSocket connections improve confidentiality and also reliability because they reduce the risk of interference by bad proxies.

The `wss` protocol is to `ws` what `https` is to `http`. The connection is encrypted with TLS (Transport Layer Security). `wss` requires certificates like `https`.

TLS vs. SSL

TLS is sometimes referred to as SSL (Secure Sockets Layer). SSL was an earlier encryption protocol; the name stuck.

Here’s how to adapt the server to encrypt connections. See the documentation of the `ssl` module for configuring the context securely.

    #!/usr/bin/env python

    import asyncio
    import pathlib
    import ssl
    import websockets

    async def hello(websocket):
        name = await websocket.recv()
        print(f"<<< {name}")

        greeting = f"Hello {name}!"

        await websocket.send(greeting)
        print(f">>> {greeting}")

    ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    localhost_pem = pathlib.Path(__file__).with_name("localhost.pem")
    ssl_context.load_cert_chain(localhost_pem)

    async def main():
        async with websockets.serve(hello, "localhost", 8765, ssl=ssl_context):
            await asyncio.Future()  # run forever

    if __name__ == "__main__":
        asyncio.run(main())

Here’s how to adapt the client similarly.

    #!/usr/bin/env python

    import asyncio
    import pathlib
    import ssl
    import websockets

    ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    localhost_pem = pathlib.Path(__file__).with_name("localhost.pem")
    ssl_context.load_verify_locations(localhost_pem)

    async def hello():
        uri = "wss://localhost:8765"
        async with websockets.connect(uri, ssl=ssl_context) as websocket:
            name = input("What's your name? ")

            await websocket.send(name)
            print(f">>> {name}")

            greeting = await websocket.recv()
            print(f"<<< {greeting}")

    if __name__ == "__main__":
        asyncio.run(hello())

This client needs a context because the server uses a self-signed certificate.

When connecting to a secure WebSocket server with a valid certificate — any certificate signed by a CA that your Python installation trusts — you can simply pass `ssl=True` to `connect()`.

## In a browser

The WebSocket protocol was invented for the web — as the name says!

Here’s how to connect to a WebSocket server in a browser.

Run this script in a console:

    #!/usr/bin/env python

    import asyncio
    import datetime
    import random
    import websockets

    async def show_time(websocket):
        while websocket.open:
            await websocket.send(datetime.datetime.utcnow().isoformat() + "Z")
            await asyncio.sleep(random.random() * 2 + 1)

    async def main():
        async with websockets.serve(show_time, "localhost", 5678):
            await asyncio.Future()  # run forever

    if __name__ == "__main__":
        asyncio.run(main())

Save this file as `show_time.html`:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>WebSocket demo</title>
        </head>
        <body>
            <script src="show_time.js"></script>
        </body>
    </html>

Save this file as `show_time.js`:

    window.addEventListener("DOMContentLoaded", () => {
      const messages = document.createElement("ul");
      document.body.appendChild(messages);

      const websocket = new WebSocket("ws://localhost:5678/");
      websocket.onmessage = ({ data }) => {
        const message = document.createElement("li");
        const content = document.createTextNode(data);
        message.appendChild(content);
        messages.appendChild(message);
      };
    });

Then open `show_time.html` in a browser and see the clock tick irregularly.

## Broadcast

A WebSocket server can receive events from clients, process them to update the application state, and broadcast the updated state to all connected clients.

Here’s an example where any client can increment or decrement a counter. The concurrency model of `asyncio` guarantees that updates are serialized.

Run this script in a console:

    #!/usr/bin/env python

    import asyncio
    import json
    import logging
    import websockets

    logging.basicConfig()

    USERS = set()

    VALUE = 0

    def users_event():
        return json.dumps({"type": "users", "count": len(USERS)})

    def value_event():
        return json.dumps({"type": "value", "value": VALUE})

    async def counter(websocket):
        global USERS, VALUE
        try:
            # Register user
            USERS.add(websocket)
            websockets.broadcast(USERS, users_event())
            # Send current state to user
            await websocket.send(value_event())
            # Manage state changes
            async for message in websocket:
                event = json.loads(message)
                if event["action"] == "minus":
                    VALUE -= 1
                    websockets.broadcast(USERS, value_event())
                elif event["action"] == "plus":
                    VALUE += 1
                    websockets.broadcast(USERS, value_event())
                else:
                    logging.error("unsupported event: %s", event)
        finally:
            # Unregister user
            USERS.remove(websocket)
            websockets.broadcast(USERS, users_event())

    async def main():
        async with websockets.serve(counter, "localhost", 6789):
            await asyncio.Future()  # run forever

    if __name__ == "__main__":
        asyncio.run(main())

Save this file as `counter.html`:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>WebSocket demo</title>
            <link href="counter.css" rel="stylesheet">
        </head>
        <body>
            <div class="buttons">
                <div class="minus button">-</div>
                <div class="value">?</div>
                <div class="plus button">+</div>
            </div>
            <div class="state">
                <span class="users">?</span> online
            </div>
            <script src="counter.js"></script>
        </body>
    </html>

Save this file as `counter.css`:

    body {
        font-family: "Courier New", sans-serif;
        text-align: center;
    }
    .buttons {
        font-size: 4em;
        display: flex;
        justify-content: center;
    }
    .button, .value {
        line-height: 1;
        padding: 2rem;
        margin: 2rem;
        border: medium solid;
        min-height: 1em;
        min-width: 1em;
    }
    .button {
        cursor: pointer;
        user-select: none;
    }
    .minus {
        color: red;
    }
    .plus {
        color: green;
    }
    .value {
        min-width: 2em;
    }
    .state {
        font-size: 2em;
    }

Save this file as `counter.js`:

    window.addEventListener("DOMContentLoaded", () => {
      const websocket = new WebSocket("ws://localhost:6789/");

      document.querySelector(".minus").addEventListener("click", () => {
        websocket.send(JSON.stringify({ action: "minus" }));
      });

      document.querySelector(".plus").addEventListener("click", () => {
        websocket.send(JSON.stringify({ action: "plus" }));
      });

      websocket.onmessage = ({ data }) => {
        const event = JSON.parse(data);
        switch (event.type) {
          case "value":
            document.querySelector(".value").textContent = event.value;
            break;
          case "users":
            const users = `${event.count} user${event.count == 1 ? "" : "s"}`;
            document.querySelector(".users").textContent = users;
            break;
          default:
            console.error("unsupported event", event);
        }
      };
    });

Then open `counter.html` file in several browsers and play with [+] and [-].