tests.ws

Testing WebSocket with curl, wscat, and websocat

websocket testing curl wscat websocat cli

Testing WebSocket connections from the command line gives you precise control over connection parameters, headers, and message flow. The three most capable tools for command-line WebSocket testing are curl (version 7.86+), wscat, and websocat. Each tool has distinct strengths: curl WebSocket support integrates with existing HTTP workflows, wscat provides interactive sessions with Node.js simplicity, and websocat offers powerful piping and scripting capabilities through a standalone Rust binary.

Understanding what WebSocket is helps clarify why specialized CLI tools are necessary. Unlike HTTP requests where curl has been the standard for years, WebSocket connections maintain persistent bidirectional channels that require tools capable of handling ongoing message exchange, not just request/response cycles.

curl WebSocket Support

Starting with version 7.86.0 released in October 2022, curl added native WebSocket support. This makes curl a viable option for basic WebSocket testing without installing additional tools. The implementation supports both ws:// and wss:// protocols, custom headers, and bidirectional messaging.

Version Requirements

Check your curl version before attempting WebSocket connections:

curl --version

You need curl 7.86.0 or higher. On macOS, the system curl may be outdated. Install the latest version via Homebrew:

brew install curl

On Ubuntu 22.10 or later:

apt-get update
apt-get install curl

For older Ubuntu versions or other Linux distributions, you may need to build from source or add a PPA repository.

Basic curl WebSocket Usage

The --include flag (or -i) enables WebSocket mode when connecting to ws:// or wss:// URLs:

curl --include \
  --no-buffer \
  --header "Connection: Upgrade" \
  --header "Upgrade: websocket" \
  --header "Sec-WebSocket-Version: 13" \
  --header "Sec-WebSocket-Key: $(echo -n $RANDOM | base64)" \
  ws://echo.websocket.org/

However, curl simplifies this significantly. For most WebSocket connections, you only need:

curl --include ws://echo.websocket.org/

The --include flag tells curl to use WebSocket mode. Without it, curl treats the URL as a regular HTTP request and fails.

Sending Messages with curl

To send a message and receive a response:

echo "Hello WebSocket" | curl --include --no-buffer ws://echo.websocket.org/

The --no-buffer flag ensures messages display immediately rather than being buffered.

For testing JSON payloads:

echo '{"type":"ping","timestamp":1676390400}' | curl --include ws://echo.websocket.org/

curl WebSocket Limitations

While curl supports WebSocket connections, it has significant limitations for testing:

  • No interactive mode for sending multiple messages
  • Cannot keep connections open for extended periods
  • Limited control over frame types (text vs binary)
  • No built-in support for automatic reconnection
  • Minimal debugging output compared to dedicated tools

These constraints make curl suitable for quick connectivity tests but less ideal for comprehensive WebSocket testing scenarios.

wscat: Interactive WebSocket Testing

wscat is a WebSocket client built on Node.js that provides an interactive command-line interface. It excels at manual testing sessions where you need to send multiple messages and observe responses in real-time.

Install wscat

Install wscat globally using npm:

npm install -g wscat

Or with yarn:

yarn global add wscat

Verify installation:

wscat --version

wscat Windows Installation

On Windows, ensure Node.js is installed first. Download the Windows installer from nodejs.org, then open PowerShell or Command Prompt:

npm install -g wscat

If you encounter permission errors on Windows, run the terminal as Administrator or configure npm to use a different global directory:

npm config set prefix "%APPDATA%\npm"

Basic wscat Usage

Connect to a WebSocket server:

wscat -c ws://echo.websocket.org/

The -c flag specifies the connection URL. Once connected, wscat enters interactive mode. Type messages and press Enter to send them. The server’s responses appear prefixed with <.

Example session:

Connected (press CTRL+C to quit)
> Hello
< Hello
> {"type":"test"}
< {"type":"test"}

wscat with Custom Headers

Add custom headers using the -H flag:

wscat -c ws://localhost:8080 \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "X-Client-ID: test-client-123"

This proves essential when testing authenticated WebSocket endpoints.

wscat Subprotocols

Specify a WebSocket subprotocol:

wscat -c ws://localhost:8080 -s chat

For multiple subprotocol options:

wscat -c ws://localhost:8080 -s chat,v2.chat

wscat Non-Interactive Mode

For scripting, use --execute to send a single message:

wscat -c ws://echo.websocket.org/ -x "test message"

Or pipe messages from a file:

cat messages.txt | wscat -c ws://echo.websocket.org/

Each line in the file becomes a separate WebSocket message.

wscat SSL/TLS Testing

Test WSS connections with custom certificates:

wscat -c wss://secure.example.com \
  --ca /path/to/ca-cert.pem \
  --cert /path/to/client-cert.pem \
  --key /path/to/client-key.pem

For development servers with self-signed certificates, use --no-check:

wscat -c wss://localhost:8443 --no-check

Never use --no-check in production environments as it disables certificate validation.

wscat Scripting Examples

Create a simple test script to verify connection and response:

#!/bin/bash
echo "ping" | wscat -c ws://localhost:8080 -x "ping" | grep -q "pong"
if [ $? -eq 0 ]; then
  echo "WebSocket server responding correctly"
  exit 0
else
  echo "WebSocket server test failed"
  exit 1
fi

For load testing, spawn multiple wscat processes:

#!/bin/bash
for i in {1..10}; do
  wscat -c ws://localhost:8080 &
done
wait

This approach works for basic concurrency testing but dedicated tools like WebSocket testing tools offer better performance metrics.

websocat: Advanced CLI WebSocket Client

websocat (WebSocket cat) is a powerful command-line WebSocket client written in Rust. It treats WebSocket connections like Unix pipes, enabling complex workflows through composition with standard Unix tools.

Install websocat

Download pre-built binaries from the GitHub releases page:


# Linux (download binary)
wget https://github.com/vi/websocat/releases/download/v1.12.0/websocat.x86_64-unknown-linux-musl
chmod +x websocat.x86_64-unknown-linux-musl
sudo mv websocat.x86_64-unknown-linux-musl /usr/local/bin/websocat

# Windows (download .exe from releases)

Or build from source with Cargo:

cargo install websocat

Verify installation:

websocat --version

Basic websocat Usage

Connect and enter interactive mode:

websocat ws://echo.websocket.org/

Type messages and press Enter. Press Ctrl+D (Unix) or Ctrl+Z (Windows) to close the connection.

websocat Piping and Redirection

websocat’s power emerges through Unix pipe integration. Send messages from stdin:

echo "test message" | websocat ws://echo.websocket.org/

Send file contents:

cat request.json | websocat ws://api.example.com/stream

Save responses to a file:

echo "get_data" | websocat ws://data.example.com/ > response.txt

websocat Binary Mode

Send binary data:

websocat -b ws://binary.example.com/ < binary_file.dat

The -b flag enables binary mode. Without it, websocat operates in text mode by default.

websocat with Headers and Authentication

Add custom headers:

websocat ws://localhost:8080 \
  --header "Authorization: Bearer token123" \
  --header "X-API-Key: abc123"

Shorter syntax with -H:

websocat ws://localhost:8080 \
  -H "Authorization: Bearer token123" \
  -H "X-API-Key: abc123"

websocat One-Message Mode

Send a single message and close:

echo "ping" | websocat --one-message ws://echo.websocket.org/

The --one-message flag makes websocat exit after receiving the first response, useful for scripting health checks.

websocat Protocol Options

Specify origin header:

websocat ws://localhost:8080 --origin https://example.com

Set WebSocket subprotocol:

websocat ws://localhost:8080 --protocol chat

Disable certificate verification (development only):

websocat wss://localhost:8443 --insecure

websocat Advanced Features

Create a WebSocket server that echoes messages:

websocat -s 8080

Proxy WebSocket connections:

websocat ws://external-server.com/ tcp:localhost:9000

Chain multiple connections:

websocat ws://source.example.com/ ws://destination.example.com/

This forwards all messages from one WebSocket to another, enabling protocol bridging and testing.

Tool Comparison

Featurecurlwscatwebsocat
InstallationUsually pre-installednpm install -g wscatDownload binary or cargo install
Interactive modeNoYesYes
Scripting supportLimitedGoodExcellent
Piping supportBasicLimitedExcellent
Binary framesNoLimitedYes
Multiple messagesVia stdin onlyYesYes
Custom headersYesYesYes
SubprotocolsYesYesYes
Server modeNoNoYes
Learning curveMinimalLowModerate
Best forQuick testsManual testingAutomation

Choose curl for simple connectivity tests when you already have it installed. Use wscat for interactive testing sessions and when working in Node.js environments. Select websocat for automation, complex scripting, or when you need to integrate WebSocket communication with Unix pipelines.

Common Testing Tasks

Test WebSocket Connection

Verify a WebSocket server accepts connections:

# curl
curl --include --max-time 5 ws://localhost:8080

# wscat
wscat -c ws://localhost:8080

# websocat
websocat --one-message ws://localhost:8080 < /dev/null

Add a timeout to prevent hanging on unresponsive servers.

Send JSON Messages

Most WebSocket APIs use JSON for message formatting:

# curl
echo '{"action":"subscribe","channel":"prices"}' | curl --include ws://api.example.com/

# wscat (interactive)
wscat -c ws://api.example.com/
> {"action":"subscribe","channel":"prices"}

# websocat
echo '{"action":"subscribe","channel":"prices"}' | websocat ws://api.example.com/

For complex JSON, store the payload in a file:

# request.json
{
  "action": "subscribe",
  "channels": ["prices", "trades"],
  "symbols": ["BTC/USD", "ETH/USD"]
}

# Send with websocat
cat request.json | websocat ws://api.example.com/

Test WebSocket Authentication

Many WebSocket servers require authentication via headers or initial messages.

Header-based authentication:

# wscat
wscat -c ws://api.example.com/ \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

# websocat
websocat ws://api.example.com/ \
  --header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Message-based authentication:

# websocat with auth message
(echo '{"type":"auth","token":"secret123"}'; cat) | websocat ws://api.example.com/

This sends the auth message immediately upon connection, then reads additional input from stdin.

Test WSS (Secure WebSocket)

Test encrypted WebSocket connections:

# curl (validates certificates by default)
curl --include wss://secure.example.com/

# wscat
wscat -c wss://secure.example.com/

# websocat
websocat wss://secure.example.com/

For development environments with self-signed certificates:

# wscat
wscat -c wss://localhost:8443 --no-check

# websocat
websocat wss://localhost:8443 --insecure

Test with custom CA certificates:

# wscat
wscat -c wss://secure.example.com/ --ca /path/to/ca-cert.pem

# websocat (set SSL_CERT_FILE environment variable)
SSL_CERT_FILE=/path/to/ca-cert.pem websocat wss://secure.example.com/

Scripting and Automation

Health Check Script

Create a simple health check for monitoring:

#!/bin/bash
# websocket-health.sh

ENDPOINT="ws://localhost:8080"
TIMEOUT=5

response=$(echo "ping" | timeout $TIMEOUT websocat --one-message "$ENDPOINT" 2>&1)

if [ $? -eq 0 ] && echo "$response" | grep -q "pong"; then
  echo "OK: WebSocket server is healthy"
  exit 0
else
  echo "CRITICAL: WebSocket server is down or not responding"
  exit 2
fi

Use this with monitoring systems like Nagios, Prometheus, or custom alerting.

Automated Test Suite

Combine multiple tests into a test suite:

#!/bin/bash
# test-websocket.sh

ENDPOINT="ws://localhost:8080"
PASSED=0
FAILED=0

test_connection() {
  if timeout 3 websocat --one-message "$ENDPOINT" < /dev/null > /dev/null 2>&1; then
    echo "✓ Connection test passed"
    ((PASSED++))
  else
    echo "✗ Connection test failed"
    ((FAILED++))
  fi
}

test_echo() {
  response=$(echo "test123" | timeout 3 websocat --one-message "$ENDPOINT" 2>&1)
  if [ "$response" = "test123" ]; then
    echo "✓ Echo test passed"
    ((PASSED++))
  else
    echo "✗ Echo test failed (expected: test123, got: $response)"
    ((FAILED++))
  fi
}

test_json() {
  response=$(echo '{"ping":true}' | timeout 3 websocat --one-message "$ENDPOINT" 2>&1)
  if echo "$response" | grep -q "pong"; then
    echo "✓ JSON test passed"
    ((PASSED++))
  else
    echo "✗ JSON test failed"
    ((FAILED++))
  fi
}

echo "Running WebSocket tests against $ENDPOINT"
echo "---"

test_connection
test_echo
test_json

echo "---"
echo "Results: $PASSED passed, $FAILED failed"

if [ $FAILED -eq 0 ]; then
  exit 0
else
  exit 1
fi

Continuous Message Streaming

Stream log messages to a WebSocket endpoint:

#!/bin/bash
# stream-logs.sh

tail -f /var/log/application.log | while read line; do
  echo "{\"timestamp\":\"$(date -Iseconds)\",\"message\":\"$line\"}"
done | websocat ws://log-collector.example.com/

This creates a real-time log forwarding pipeline using WebSocket.

Load Testing

Generate concurrent connections for basic load testing:

#!/bin/bash
# load-test.sh

ENDPOINT="ws://localhost:8080"
CONNECTIONS=100

for i in $(seq 1 $CONNECTIONS); do
  (
    sleep $((RANDOM % 5))
    echo "client-$i" | websocat "$ENDPOINT" &
  ) &
done

wait
echo "Load test complete: $CONNECTIONS connections"

For production load testing, use dedicated tools, but this approach works for development verification.

Integration with Testing Workflows

These CLI tools integrate into broader WebSocket testing strategies. While command-line tools excel at automation and scripting, interactive testing often benefits from graphical tools like the WebSocket tester.

Combine CLI testing with:

  • CI/CD pipelines: Add health checks and integration tests to deployment workflows
  • Monitoring systems: Create periodic checks that alert on WebSocket failures
  • Development workflows: Quick connection verification during local development
  • Debugging sessions: Isolate protocol-level issues separate from application code

The curl test WebSocket capability proves particularly valuable in environments where installing additional tools is restricted, as curl is nearly universally available on Unix-like systems.

FAQ

Can curl test WebSocket connections without —include?

No. The --include flag is required for curl to activate WebSocket mode. Without it, curl treats ws:// URLs as malformed HTTP URLs and fails with protocol errors. This flag signals curl to perform the WebSocket handshake and maintain the bidirectional connection.

Which tool is best for testing WebSocket on Windows?

wscat works best for Windows users because it installs easily via npm without compilation. While websocat offers more features, downloading and managing the binary on Windows requires more steps. Install Node.js, then run npm install -g wscat in PowerShell or Command Prompt. wscat Windows installation is straightforward and provides a capable WebSocket CLI tool for most testing scenarios.

How do I test WebSocket authentication with these tools?

For header-based authentication, use the -H flag with wscat or --header with websocat to add Authorization headers. For token-based authentication sent as the first message, pipe the auth JSON before other input. Example: (echo '{"auth":"token123"}'; cat) | websocat ws://api.example.com/. This pattern sends the authentication message immediately upon connection, then allows interactive or piped input for subsequent messages.

Can these tools test WebSocket reconnection logic?

These command-line tools test individual connections but do not automatically reconnect. For testing reconnection logic, write shell scripts that loop connection attempts or use dedicated WebSocket testing tools that support automatic reconnection. You can simulate reconnection scenarios by running the tools multiple times with delays: while true; do websocat ws://localhost:8080; sleep 5; done.