WebSocket Compression
WebSocket compression shrinks message sizes for more efficient real-time data transfer, especially for repetitive or structured payloads like JSON, logs, and live updates.
Compression extensions are negotiated during the WebSocket handshake. If both client and server support the same compression method, messages are automatically compressed before transmission and decompressed upon receipt. Without compression, WebSocket frames are sent as raw, uncompressed data.
This is achieved by supporting the Per-Message Deflate extension, which is the standard for WebSocket compression.
Per-Message Deflate
Per-Message Deflate (permessage-deflate) is the standard WebSocket compression extension, defined in RFC 7692. It uses the DEFLATE algorithm—the same compression method found in gzip and ZIP files—to compress individual WebSocket messages.
We support per-message deflate on all WebSocket subscriptions, including Solana RPC and ChainStream.
WebSocket clients that support per-message deflate
Here's a non-exhaustive list of popular WebSocket libraries that support per-message deflate:
- ws (Node.js)
- websockets (Python)
- gorilla/websocket (Go)
- ratchet_rs (Rust)
Implementation Examples
- Python
- Go
import asyncio
import signal
import websockets
from websockets.asyncio.client import connect
async def client():
# NOTE: by default permessage-deflate is enabled
async with connect("wss://api.syndica.io/api-key/<YOUR_API_KEY>") as websocket:
print("CONNECTED")
await websocket.send("{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"solana-mainnet.slotSubscribe\"}")
# Close the connection when receiving SIGTERM.
loop = asyncio.get_running_loop()
loop.add_signal_handler(signal.SIGTERM, loop.create_task, websocket.close())
# Process messages received on the connection.
async for message in websocket:
print("Received message:", message)
asyncio.run(client())
package main
import (
"flag"
"fmt"
"log"
"net/url"
"os"
"os/signal"
"time"
"github.com/gorilla/websocket"
)
var addr = flag.String("addr", "api.syndica.io", "http service address")
var path = flag.String("path", "/api-key/<YOUR_API_KEY>", "websocket path")
func main() {
flag.Parse()
log.SetFlags(0)
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
u := url.URL{Scheme: "wss", Host: *addr, Path: *path}
log.Printf("connecting to %s", u.String())
dialer := websocket.DefaultDialer
// enable/disable compression here
// default value for sec-websocket-extensions is: `permessage-deflate; server_no_context_takeover; client_no_context_takeover`
dialer.EnableCompression = true
c, response, err := dialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
fmt.Printf("Response: %+v\n", response)
defer c.Close()
done := make(chan struct{})
go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
log.Printf("recv: %s", message)
}
}()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-done:
return
case t := <-ticker.C:
err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
if err != nil {
log.Println("write:", err)
return
}
case <-interrupt:
log.Println("interrupt")
// Cleanly close the connection by sending a close message and then waiting for the server to close the connection.
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}
}
Summary
WebSocket compression using per-message deflate can significantly reduce bandwidth consumption for real-time applications. Ensure your client library supports the extension, and monitor bandwidth savings to validate performance improvements.
FAQ and Troubleshooting
How do I reduce bandwidth usage?
Syndica automatically offers Per-Message Deflate compression (RFC 7692) on every WebSocket endpoint, typically reducing bandwidth by 70-90%. Most client libraries negotiate this extension automatically, but some require you to enable compression explicitly or install an additional dependency—check your client's docs to confirm it advertises permessage-deflate during the handshake.
How do I reduce ChainStream bandwidth usage?
Syndica offers Per-Message Deflate compression (RFC 7692) on every ChainStream endpoint—most clients negotiate it automatically, though some require enabling compression manually or adding an extra dependency to advertise permessage-deflate. For transaction-heavy streams, you can further trim payloads via metadataOnly: true, excludeVotes: true, and targeted accountKeys filters.