Socket.IO · WebSocket · Testing

How to test a Socket.IO server online (v2, v3 and v4)

A hands-on guide to testing Socket.IO servers with Swastik Codes: client versions, namespaces, the auth payload, emitting events, acknowledgements, listeners and common connection errors.

By · · 8 min read

To test a Socket.IO server you need a client that speaks the Socket.IO protocol, not just raw WebSocket. Socket.IO wraps its messages in its own packet format, runs a handshake, multiplexes namespaces over one connection and supports acknowledgements, so a plain WebSocket tool will connect and then see nothing useful. In Swastik Codes you create a Socket.IO request, pick the client version (v4, v3 or v2), set the namespace and auth payload, press Connect, and then emit events and watch incoming ones in the log.

This guide shows the full flow against a small server you can deploy yourself, explains the version differences that trip people up, and lists the errors you are most likely to see.

What you need

  • A Socket.IO server reachable from the public internet. The Swastik Codes web app relays the connection through the swastik.codes server, which refuses private, loopback and other reserved addresses. A server on localhost:3000 cannot be reached from the web app, so deploy it to a staging host or put it behind a tunnel with a public hostname. The desktop app for Windows and Linux connects from your own machine, so it reaches local servers.
  • To know which Socket.IO major version the server runs. Check socket.io in its package.json (or the equivalent library in Python, Java or Go).
  • A free Swastik Codes account, because protocol connections run through the server.

Socket.IO versions in one paragraph

Socket.IO v3 and v4 share the same wire protocol (Socket.IO protocol 5 over Engine.IO 4), and a v4 client can talk to a v3 server. Socket.IO v2 uses the older protocol 4 over Engine.IO 3 and is not compatible with v3/v4 clients: the handshake query says EIO=3 instead of EIO=4, the namespace connection is different, and v2 has no handshake auth payload (credentials usually go in the query string). If your connection opens and then nothing happens, a version mismatch is the first thing to check. v4 servers can accept v2 clients only when they are started with allowEIO3: true.

Step 1: create a Socket.IO request

  1. Open the app and sign in.
  2. Click + in the tab bar and choose Socket.IO from the New request menu.
  3. Enter the server URL, for example https://realtime.example.com. Use the http(s):// form of the URL; Socket.IO starts its handshake over HTTP.
  4. Choose the Client version: v4, v3 or v2.

On the Settings tab you can also set:

  • Handshake path: the server's path option, /socket.io by default. Change it if your server mounts Socket.IO elsewhere, for example /ws/socket.io behind a proxy.
  • Namespace: / by default, or for example /admin or /chat.
  • Transport: WebSocket or HTTP long-polling. With WebSocket selected, the client falls back to long-polling if the WebSocket transport fails, and the log says so.
  • Auth payload (JSON, v3/v4 handshake): the object your server reads as socket.handshake.auth.
  • Timeouts for the handshake and for acknowledgements, automatic reconnection, the maximum message size and TLS certificate verification.

The Params, Headers and Authorization tabs work like they do for HTTP requests. Query parameters end up in socket.handshake.query on the server, headers in socket.handshake.headers, and the authorization types (Bearer, Basic, API key, OAuth 2.0) are sent as handshake headers or query parameters.

Step 2: listen for events

Open the Events tab and add the event names you care about, such as chat:message or order:updated. Incoming events with those names are highlighted in the log. Turn on Show only listened events to hide everything else, which helps on busy servers. You can add a description to each listener to document what the event carries, and switch individual listeners on and off.

All events the server sends are still received and shown unless you filter them, so you will not miss an event just because you forgot to add a listener.

Step 3: connect

Press Connect. The log shows the connection opening, the namespace being joined and any events the server emits on connect. Connection details shows the handshake request and response headers.

If the server rejects the connection in middleware (next(new Error('unauthorized'))), you will see an error event with the message the server sent, followed by a close. That message is exactly what your real clients would receive in their connect_error handler, which makes this a quick way to test your auth middleware.

Step 4: emit events and use acknowledgements

On the Message tab, enter an Event name and the Arguments. Arguments can be written in two modes:

  • JSON array: one array where each element is an argument, for example [{"room": "lobby", "text": "hello"}] for a single object argument, or ["lobby", "hello"] for two string arguments.
  • One per argument: a separate editor per argument with its own format (JSON, text, number, boolean or binary). Binary arguments are sent as Socket.IO attachments.

Turn on Ack to ask the server for an acknowledgement. The client then waits for the server to call the callback and shows the ack's arguments in the log. If no ack arrives within the ack timeout, you see a timeout error; set the timeout to 0 to wait forever.

Acks also work the other way. If the server emits an event with a callback and expects the client to acknowledge it, Swastik Codes answers the acknowledgement automatically (with no arguments), so server code that waits for an ack does not hang during your test.

Press Send. The emitted event appears in the log as sent, with its namespace and ack id, followed by whatever the server sends back.

Step 5: save events and examples

Save the events you emit often so you can send them again with one click from the Saved tab while connected. Each saved message remembers its event name and arguments. When the connection is closed, Save as example stores the messages and status of the session as an example of the request. Save the request to a collection with Ctrl+S or Cmd+S to share it with your workspace.

A Socket.IO v4 server to test against

Here is a small Socket.IO v4 server with auth middleware, an event with an acknowledgement, a broadcast and a second namespace. It covers every feature discussed above.

JavaScript
// server.mjs  (npm install socket.io)
import { createServer } from 'node:http';
import { Server } from 'socket.io';

const httpServer = createServer();
const io = new Server(httpServer, {
  cors: { origin: '*' },
});

// Reject connections without the right token in the auth payload.
io.use((socket, next) => {
  if (socket.handshake.auth?.token !== process.env.SIO_TOKEN) {
    return next(new Error('unauthorized'));
  }
  next();
});

io.on('connection', (socket) => {
  socket.emit('welcome', { id: socket.id, at: Date.now() });

  socket.on('chat:message', (msg, ack) => {
    if (!msg || typeof msg.text !== 'string') {
      return typeof ack === 'function' && ack({ ok: false, error: 'text is required' });
    }
    io.emit('chat:message', { from: socket.id, text: msg.text });
    if (typeof ack === 'function') ack({ ok: true });
  });

  // Ask the client for an ack; Swastik Codes answers it automatically.
  socket.timeout(5000).emit('server:ping', (err) => {
    console.log(err ? 'client did not ack' : 'client acked');
  });
});

io.of('/admin').on('connection', (socket) => {
  socket.emit('stats', { clients: io.engine.clientsCount });
});

httpServer.listen(Number(process.env.PORT) || 3000);

Deploy it, set SIO_TOKEN, then in Swastik Codes:

  1. URL https://your-host, Client version v4, Auth payload {"token": "{{sioToken}}"}.
  2. Add listeners for welcome and chat:message.
  3. Connect. You should see welcome and the server:ping event; your server logs "client acked".
  4. Emit chat:message with arguments [{"text": "hello"}] and Ack on. The log shows the broadcast chat:message and the ack {"ok": true}.
  5. Emit chat:message with [{}] to check the error path: the ack carries {"ok": false, "error": "text is required"}.
  6. Change the namespace to /admin and reconnect to see the stats event.

Then remove the token from the auth payload and connect again to confirm that the middleware rejects you with unauthorized.

Troubleshooting

Connected, but no events and no errors. Most often a version mismatch (a v2 server with a v3/v4 client, or the other way round). Switch the Client version. Also check that you are in the right namespace.

Invalid namespace error. The namespace does not exist on the server. Namespaces are case-sensitive and start with /.

404 during the handshake. The Handshake path does not match the server's path option, or a reverse proxy does not forward /socket.io/ to the Node process.

WebSocket transport fails, polling works. A proxy is not forwarding the Upgrade header. The client falls back to long-polling so you can keep testing, but fix the proxy before production: polling uses more requests and adds latency.

Ack timeout. The server handler does not call the callback, or calls it only on some code paths. Raise the ack timeout to rule out a slow handler.

Connection refused for a private address. The relay blocks private and loopback addresses on purpose. Use a public hostname.

Frequently asked questions

Can I use a plain WebSocket client to test Socket.IO?

Only in a very limited way. You would have to write Engine.IO and Socket.IO packets by hand (40 to join the default namespace, 42["event", …] to emit). The Socket.IO request type does that for you, along with namespaces, acks and reconnection.

Which Socket.IO versions are supported?

Client versions v2, v3 and v4. Pick the one that matches your server; v4 also works with v3 servers.

How do I send a token to a Socket.IO server?

For v3 and v4 servers, put it in the Auth payload JSON, which the server reads as socket.handshake.auth. You can also send it as a query parameter or a header. v2 has no auth payload, so use the query string.

Can I send binary data?

Yes. In One per argument mode, choose the binary format for an argument and it is sent as a Socket.IO binary attachment.

Does it answer acknowledgements the server asks for?

Yes. When the server emits with a callback, the client acknowledges automatically, so server code waiting for the ack continues.

Try it

Open Swastik Codes, create a Socket.IO request and connect to your server. You need a free account to connect. The Socket.IO client feature page lists every option. If you also run raw WebSocket endpoints, read how to test a WebSocket API online, and for one-way streams see how to test Server-Sent Events.

Try it on your own API

Swastik Codes runs in the browser and is free to use. Create an account to send requests, sync your workspaces and invite your team.