WebSocket · Testing · Realtime
How to test a WebSocket API online, step by step
A practical guide to testing a WebSocket API from the browser: connecting, sending frames, saving messages, headers and auth, and fixing common handshake errors.

To test a WebSocket API online, you need a client that can open a ws:// or wss:// connection, send frames you write, and show every frame the server sends back with timestamps. In Swastik Codes that takes about a minute: open the app, create a WebSocket request, paste the URL, press Connect, type a message and press Send. The rest of this guide walks through that flow in detail, explains what happens during the handshake, and covers the problems you are most likely to hit.
What you need
- A WebSocket endpoint that is reachable from the public internet, for example
wss://api.example.com/socket. If you only want to try the client first,wss://echo.websocket.orgis a public echo server: it sends one greeting line when you connect and then returns every message you send. - A free Swastik Codes account. The web app needs one, because traffic goes through the server (see below for why).
- Whatever credentials your API expects during the handshake: a bearer token, an API key, a cookie or a query parameter.
Why the endpoint must be public
A browser page cannot open arbitrary WebSocket connections with custom headers, and it cannot reach servers that block cross-origin requests. So the Swastik Codes web app does not connect to your endpoint directly. It opens one WebSocket to the swastik.codes server, and the server opens the real connection to your endpoint and relays frames in both directions.
That relay protects itself and everybody else: it refuses private, loopback, link-local and other reserved addresses. ws://localhost:8080 or ws://192.168.1.20 will not work from the web app. Deploy your server somewhere public (a staging environment, a small VM, a platform such as Fly.io or Render), or use a tunnelling tool that gives you a public HTTPS hostname. The desktop app for Windows and Linux runs connections from your own machine, so it reaches local servers.
Step 1: create a WebSocket request
- Open the app and sign in.
- Click the + button at the end of the tab bar. The New request menu lists every request type: HTTP, GraphQL, WebSocket, Socket.IO, Server-Sent Events, gRPC, MQTT and MCP. Choose WebSocket.
- Paste your URL into the address bar, for example
wss://echo.websocket.org.
If you already have an HTTP request pointing at the same host, you can change its type in place with the request type picker. The URL scheme is converted for you (https:// becomes wss://), and the name, headers, query parameters and authorization carry over.
Step 2: add headers, query parameters and auth
Most production WebSocket APIs authenticate during the opening handshake, because after that the connection is just a stream of frames. The request editor has the same tabs you know from HTTP requests:
- Params: query parameters appended to the URL, such as
?token=…or?room=lobby. - Authorization: Bearer token, Basic auth, API key (as a header or a query parameter) or OAuth 2.0. The choice is turned into handshake headers or query parameters. You can also inherit auth from the collection the request is saved in.
- Headers: any extra handshake headers, for example
Origin, a customX-Client-Versionor aCookie. - Settings: subprotocols (sent as
Sec-WebSocket-Protocol), ping interval, handshake request timeout, maximum message size, automatic reconnection with attempts and interval, and whether to verify the server's TLS certificate.
Values can use variables like {{baseUrl}} and {{token}} from your environments, so the same request works against staging and production.
Step 3: connect and read the handshake
Press Connect. The status changes to connecting and then to connected. The message log on the right shows the connection events as well as messages. Open Connection details to see the request headers that were sent and the response headers the server returned. This is where you check things like the negotiated subprotocol or a Set-Cookie from the upgrade response.
When a handshake fails, the log shows an error event followed by a close event, with the reason. A 401 or 403 here almost always means the token or origin was rejected; a 404 means the path is wrong; a 426 Upgrade Required or a plain 200 usually means you hit an HTTP endpoint that does not speak WebSocket at all.
Step 4: send messages
The Message tab is a composer. Pick a format first:
- Text sends a text frame exactly as typed.
- JSON, XML and HTML also send text frames, with syntax highlighting and a Beautify button.
- Binary sends a binary frame. Write the bytes as Base64 or hexadecimal and choose the encoding next to the format.
Type a message such as:
{ "type": "subscribe", "channel": "orders", "id": 1 }and press Send. Variables in the message are resolved before it is sent, so {"token": "{{token}}"} works. The Ping button sends a WebSocket ping frame, which is useful for checking that a quiet connection is still alive.
Every sent and received frame appears in the log with its direction, time and size. You can filter by sent or received, search the log, and view a message as text, JSON or a hexdump. Select two messages to see the time between them, which is a quick way to measure how long your server takes to answer a particular request. Download the shown messages as JSON exports the visible log if you want to attach it to a bug report.
Step 5: save messages and examples
Testing a WebSocket API usually means sending the same handful of messages over and over: authenticate, subscribe, send a command, unsubscribe. Instead of keeping them in a text file:
- Click Save message in the composer to keep the current message with the request. Saved messages appear under Saved messages, where you can rename them, load one back into the composer to edit it, delete it, or send it with one click while connected.
- Use Save as example on the log once the connection is closed. It stores the messages, status and metadata of that session as an example of the request, which is handy as documentation of what a typical exchange looks like.
Save the request itself to a collection (Ctrl+S or Cmd+S) so teammates in the same workspace get the URL, headers, auth and saved messages too. Connections you open are also recorded in your history, and reopening a history entry brings you back to the WebSocket editor.
A small WebSocket server to test against
If you are building the server yourself, here is a minimal Node.js server using the ws package. It answers a ping message, echoes everything else, and broadcasts a timestamp every five seconds so you can see server-initiated messages.
// server.mjs (npm install ws)
import { WebSocketServer } from 'ws';
const port = Number(process.env.PORT) || 8080;
const wss = new WebSocketServer({ port });
wss.on('connection', (socket, req) => {
const token = new URL(req.url, 'http://x').searchParams.get('token');
if (token !== process.env.WS_TOKEN) {
socket.close(1008, 'invalid token'); // 1008 = policy violation
return;
}
socket.send(JSON.stringify({ type: 'welcome' }));
socket.on('message', (data, isBinary) => {
if (!isBinary && data.toString() === 'ping') return socket.send('pong');
socket.send(data, { binary: isBinary }); // echo
});
});
setInterval(() => {
const msg = JSON.stringify({ type: 'tick', at: new Date().toISOString() });
for (const client of wss.clients) if (client.readyState === 1) client.send(msg);
}, 5000);
console.log(`listening on ${port}`);Deploy it behind HTTPS, then connect to wss://your-host/?token={{wsToken}} with wsToken defined in an environment. You should see the welcome message, a tick every five seconds, and your own messages echoed back. Try a wrong token to see how a policy close (code 1008) looks in the log.
Things worth testing on any WebSocket API
A connection that works once is not the same as a robust API. A few checks catch most real-world bugs:
- Auth failures: connect with no token, an expired token and a token for another tenant. The server should refuse the handshake or close with a clear code, not accept and then ignore you.
- Malformed input: send invalid JSON, an unknown
type, a huge message and an empty message. The server should answer with an error message or close politely, and the connection should not hang. - Ordering and correlation: if your protocol uses request ids, send several commands quickly and check that each reply carries the right id.
- Idle behaviour: leave the connection open. Does the server close idle sockets, and after how long? Use the ping interval setting to keep it alive and compare.
- Reconnection: turn on automatic reconnection, then restart your server. Check what your server sends to a client that reconnects, and whether subscriptions need to be repeated.
- Binary frames: if you accept binary data, send a few bytes as hex (for example
01 02 ff) and confirm they arrive unchanged.
Troubleshooting
"Sign in to use WebSocket, gRPC, MQTT and other protocols in the browser." Sending protocol traffic from the web app needs an account, because it goes through the swastik.codes relay. Create a free account and try again.
The connection is refused immediately for a local or private address. The relay blocks private and loopback addresses on purpose. Use a public hostname.
Handshake returns 400. Check the subprotocols in Settings. If the server requires a specific subprotocol (some GraphQL and STOMP servers do), it must be listed; if it does not support the one you sent, some servers reject the upgrade.
Messages arrive, but they look like gibberish. The server is sending binary frames, often MessagePack or Protobuf. Switch the log view to hexdump to inspect the bytes.
The connection closes after about a minute of silence. Many proxies and load balancers close idle connections. Set a ping interval in Settings, and consider sending application-level heartbeats from your server.
Close code 1006. This code is never sent on the wire; it means the connection dropped without a close frame. Look at your server logs and any proxy in front of it.
Frequently asked questions
Can I test a WebSocket API without installing anything?
Yes. Swastik Codes runs in the browser. You need a free account to send traffic, but there is nothing to install.
Can I connect to ws://localhost from the web app?
No. The web app relays connections through the swastik.codes server, which refuses private and loopback addresses. Use the desktop app, deploy the server to a public host, or expose it through a tunnel with a public HTTPS hostname.
Does it support binary WebSocket messages?
Yes. Choose Binary as the message format and write the payload as Base64 or hexadecimal. Received binary frames can be viewed as a hexdump.
How do I send an auth token in a WebSocket handshake?
Use the Authorization tab (Bearer, Basic, API key or OAuth 2.0), add a header on the Headers tab, or put the token in a query parameter on the Params tab. Which one works depends on your server; browser-based clients often use a query parameter because browsers cannot set handshake headers.
Is Socket.IO the same as WebSocket?
No. Socket.IO runs its own protocol on top of WebSocket or HTTP long-polling, so a plain WebSocket client cannot talk to a Socket.IO server properly. Use the Socket.IO request type instead; see how to test a Socket.IO server.
Try it
Open Swastik Codes, create a WebSocket request and connect to your endpoint or to wss://echo.websocket.org. If you do not have an account yet, sign up for free. The WebSocket client feature page lists every option, and if your API streams in one direction only, read how to test Server-Sent Events. For HTTP endpoints that sit next to your socket server, the REST API client works the same way.