Master OpenClaw Gateway Architecture: WebSocket API Guide
Ever tried to build a bot or a custom UI that needs to talk to several different messaging apps at once? It usually turns into a mess of conflicting libraries and connection drops. You need a way to centralize that logic so your apps stay light and your connections stay stable.
The Gateway architecture is designed to be that central brain for your messaging setup. It handles the heavy lifting of protocol management while providing a clean, unified interface for your clients and nodes.
Overview
Section titled “Overview”A single long‑lived Gateway owns all your messaging surfaces, including WhatsApp via Baileys, Telegram via grammY, Slack, Discord, Signal, iMessage, and WebChat.
Your control-plane clients, such as the macOS app, CLI, web UI, or automations, connect to this Gateway over WebSocket. By default, it binds to 127.0.0.1:18789.
Nodes on macOS, iOS, Android, or headless setups also connect over WebSocket, but they declare a role: node with specific capabilities and commands.
You only run one Gateway per host. This is the specific place where your WhatsApp session stays open. The Gateway also runs an HTTP server to serve the canvas host at these locations:
/__openclaw__/canvas/(agent-editable HTML/CSS/JS)/__openclaw__/a2ui/(A2UI host)
This server uses the same port as the Gateway (default 18789).
Components and flows
Section titled “Components and flows”Gateway (daemon)
Section titled “Gateway (daemon)”The Gateway maintains your provider connections and exposes a typed WS API for requests, responses, and server‑push events. It validates every inbound frame against a JSON Schema. You can expect it to emit events like agent, chat, presence, health, heartbeat, and cron.
Clients (mac app / CLI / web admin)
Section titled “Clients (mac app / CLI / web admin)”Each client uses one WS connection. You can use these to send requests like health, status, send, agent, or system-presence. Clients also subscribe to events such as tick, agent, presence, and shutdown.
Nodes (macOS / iOS / Android / headless)
Section titled “Nodes (macOS / iOS / Android / headless)”Nodes connect to the same WS server but use role: node. When you connect a node, you provide a device identity. Pairing is device‑based, and the approval is stored in the device pairing store. Nodes allow you to use commands like canvas.*, camera.*, screen.record, and location.get.
Protocol details:
WebChat
Section titled “WebChat”This is a static UI that uses the Gateway WS API to handle chat history and sending messages. If you are running a remote setup, it connects through the same SSH or Tailscale tunnel as your other clients.
Connection lifecycle (single client)
Section titled “Connection lifecycle (single client)”sequenceDiagram participant Client participant Gateway
Client->>Gateway: req:connect Gateway-->>Client: res (ok) Note right of Gateway: or res error + close Note left of Client: payload=hello-ok<br>snapshot: presence + health
Gateway-->>Client: event:presence Gateway-->>Client: event:tick
Client->>Gateway: req:agent Gateway-->>Client: res:agent<br>ack {runId, status:"accepted"} Gateway-->>Client: event:agent<br>(streaming) Gateway-->>Client: res:agent<br>final {runId, status, summary}Wire protocol (summary)
Section titled “Wire protocol (summary)”The transport uses WebSocket text frames with JSON payloads. Your first frame must be a connect frame.
After the handshake, the communication follows these patterns:
- Requests:
{type:"req", id, method, params}→{type:"res", id, ok, payload|error} - Events:
{type:"event", event, payload, seq?, stateVersion?}
If you set OPENCLAW_GATEWAY_TOKEN or use the --token flag, you must provide a matching token in connect.params.auth.token or the socket will close.
You need to use idempotency keys for methods that cause side effects, like send or agent. This allows you to retry safely because the server maintains a short-lived cache to deduplicate requests. Nodes are required to include role: "node" along with their specific caps, commands, and permissions during the connect phase.
Pairing + local trust
Section titled “Pairing + local trust”Every WS client, whether it is an operator or a node, must include a device identity when calling connect. New device IDs need pairing approval. Once approved, the Gateway gives you a device token for your next connections.
To make things easier, local connects (using loopback or the host’s own tailnet address) can be auto‑approved. This keeps the experience smooth when you are working on the same host.
All connections must sign the connect.challenge nonce. The v3 signature payload also binds the platform and deviceFamily. The gateway pins this metadata when you reconnect and will require a repair pairing if your metadata changes. Non‑local connects always require explicit approval, and gateway authentication (gateway.auth.*) applies to every connection regardless of whether it is local or remote.
Details: Gateway protocol, Pairing, Security.
Protocol typing and codegen
Section titled “Protocol typing and codegen”The protocol is defined using TypeBox schemas. From these, a JSON Schema is generated, which is then used to generate Swift models. This ensures the types stay consistent across different parts of the system.
Remote access
Section titled “Remote access”If you need to access the Gateway remotely, using Tailscale or a VPN is the best way to go. If those aren’t options, you can use an SSH tunnel:
ssh -N -L 18789:127.0.0.1:18789 user@hostThe same handshake and auth token rules apply when you are using a tunnel. You can also enable TLS and optional pinning for WebSockets in remote environments.
Operations snapshot
Section titled “Operations snapshot”You can start the Gateway in the foreground by running openclaw gateway, which will send logs to stdout. You can check the system status by sending a health request over WS, which is also included in the hello-ok message. For production setups, you should use launchd or systemd to handle auto‑restarts and supervision.
Invariants
Section titled “Invariants”The architecture relies on a few strict rules:
- Exactly one Gateway controls a single Baileys session per host.
- The handshake is mandatory; the connection closes if the first frame isn’t a valid JSON
connectframe. - The Gateway only accepts JSON frames.
- Events are not replayed, so you must refresh your state if you detect a gap.
Related
Section titled “Related”- Agent Loop — detailed agent execution cycle
- Gateway Protocol — WebSocket protocol contract
- Queue — command queue and concurrency
- Security — trust model and hardening
Next steps
Section titled “Next steps”- Check out the Agent Loop to see how tasks are executed.
- Read the Gateway Protocol for the full API spec.
- Learn about Security to harden your setup.
- Explore Pairing to manage your devices.
Need help getting started? Try the AI Setup Assistant.
OpenClaw Expert
Still stuck?
If this page didn't answer your case, ask OpenClaw Expert for step-by-step guidance.