Testing WebSocket with curl, wscat, and websocat
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
| Feature | curl | wscat | websocat |
|---|---|---|---|
| Installation | Usually pre-installed | npm install -g wscat | Download binary or cargo install |
| Interactive mode | No | Yes | Yes |
| Scripting support | Limited | Good | Excellent |
| Piping support | Basic | Limited | Excellent |
| Binary frames | No | Limited | Yes |
| Multiple messages | Via stdin only | Yes | Yes |
| Custom headers | Yes | Yes | Yes |
| Subprotocols | Yes | Yes | Yes |
| Server mode | No | No | Yes |
| Learning curve | Minimal | Low | Moderate |
| Best for | Quick tests | Manual testing | Automation |
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.