Inspect WebSocket Frames with websocat
Connect to a live WebSocket endpoint with websocat, send handcrafted frames, watch server pushes arrive, and diagnose protocol issues the browser hides.
Task
Attach to a WebSocket endpoint from the terminal, exchange frames by hand, and diagnose message ordering or handshake problems.
When to use this
The dashboard stops updating a few minutes after load. The browser tool shows a connection but no frames, and nobody can tell whether the server stopped sending or the client stopped handling.
Prerequisites
- websocat installed on PATH
- The WebSocket URL including any required token
- A quiet period on the endpoint so test frames are identifiable
Steps
1. Connect and verify the handshake completes.
websocat "wss://stream.example.com/ws?token=$TOKEN" --json-logs 2>&1 | head -5Expected output: Connection logs print an established session; if the URL or subprotocol is wrong the close code appears immediately.
2. Watch inbound frames without sending anything.
timeout 30 websocat "wss://stream.example.com/ws?token=$TOKEN" | head -20Expected output: Server frames stream to stdout in raw form; their arrival pattern (or silence) shows whether the server is still pushing.
3. Send a subscription frame by hand and read the reply.
echo '{"op":"subscribe","channel":"orders"}' | websocat "wss://stream.example.com/ws?token=$TOKEN"Expected output: An acknowledgment frame and then channel data arrive, proving the server logic works and the bug is client-side handling.
4. Check whether the server relies on client pings to keep intermediaries alive.
timeout 120 websocat --ping-interval 25 "wss://stream.example.com/ws?token=$TOKEN" | wc -lExpected output: With 25-second pings the line count keeps growing; without them the connection dies around second 60, indicting an idle-timeout proxy.
Troubleshooting
Problem
Handshake fails with 401 or 403
Solution
The token is expired or not passed the way the server expects; check whether auth rides in the query string, a header, or the first frame after connect.
Problem
Connection drops after exactly one minute
Solution
An intermediary load balancer enforces an idle timeout; send application-level or protocol pings more frequently than the timeout.
Problem
Frames arrive as binary garbage
Solution
The server uses msgpack or protobuf framing; pass --binary and decode with the matching tool, or request a JSON mode if the server offers one.
Limitations
- Handcrafted frames bypass client serialization, so bugs in the client encoder are invisible to this method.
- Authentication schemes that require full browser context, such as cookie-bound sessions, are awkward to reproduce in a terminal.
A terminal is a better WebSocket client than a guess
Browser tooling shows WebSocket frames but will not let you type your own, and it hides failures behind a single red icon. websocat turns the terminal into a raw client: you see the handshake, you send any frame you like, and you watch exactly what the server pushes and when. When a stream stops updating, this answers in one run whether the server went quiet or the client stopped processing.
# Send one subscription frame, watch what comes back
echo '{"op":"subscribe","channel":"orders"}' | \
websocat "wss://stream.example.com/ws?token=$TOKEN"
# Keep the link warm through a proxy idle timeout
websocat --ping-interval 25 "wss://stream.example.com/ws?token=$TOKEN"
Separate transport from behavior
The first question for a silent stream is whether bytes are arriving at all. Watch inbound traffic without sending anything: growing output means transport is fine and the client dropped the ball; total silence means the server or an intermediary stopped the flow. This single observation halves the search space before you read any application code.
Reproduce the idle timeout precisely
Drops at suspiciously round intervals, like 60 seconds, are almost always intermediary idle timeouts rather than server logic. Sending a ping every 25 seconds keeps the link warm and proves the diagnosis; if that fixes the terminal session, the same fix belongs in the client library configuration.