Skip to main content
Recommended for production. Compression reduces bandwidth by ~60% with no latency impact. Every event is compressed once on the server and delivered to all subscribers — zero per-connection overhead. Enable it by adding &compress=zlib to your connection URL.

How it works

When you connect with &compress=zlib, the server sends settlement events as deflate-compressed binary frames instead of JSON text frames. Your client decompresses each binary frame with standard zlib inflateRaw — available in every language. Control messages (subscribe acknowledgments, errors, heartbeats, pong) are still sent as normal JSON text, so you can always read them directly.
wss://ws.polynode.dev/ws?key=pn_live_YOUR_KEY&compress=zlib

Bandwidth savings

Measured in production on real settlement data:
ModePer-connectionMax connections (1 Gbps)Max connections (10 Gbps)
Uncompressed~0.78 Mbps~1,000~10,000
Compressed~0.32 Mbps~2,500~25,000
Compression is applied once per event on the server, then the same compressed bytes are fanned out to all compressed subscribers. There is no per-connection compression overhead — it scales the same as uncompressed.

Client examples

import WebSocket from "ws";
import { inflateRawSync } from "zlib";

const ws = new WebSocket(
  "wss://ws.polynode.dev/ws?key=pn_live_YOUR_KEY&compress=zlib"
);

ws.on("open", () => {
  ws.send(JSON.stringify({ action: "subscribe", type: "settlements" }));
});

ws.on("message", (data, isBinary) => {
  let event;
  if (isBinary) {
    // Compressed event — decompress with inflateRaw
    const json = inflateRawSync(data).toString();
    event = JSON.parse(json);
  } else {
    // Control message (subscribe ack, heartbeat, error)
    event = JSON.parse(data.toString());
  }
  console.log(event.type, event.data?.market_title);
});

Key details

Only live event frames (settlements, status updates, trades) are sent as compressed binary.These are always sent as normal JSON text:
  • {"type": "snapshot", ...} — initial event snapshot
  • {"type": "subscribed", ...} — subscription acknowledgment
  • {"type": "unsubscribed", ...} — unsubscribe confirmation
  • {"type": "heartbeat", ...} — server heartbeat
  • {"type": "pong"} — ping response
  • {"type": "error", ...} — error messages
Check the WebSocket frame type:
  • Binary frame → compressed event, decompress with inflateRaw
  • Text frame → normal JSON, parse directly
Every WebSocket library exposes this distinction (e.g. isBinary in Node.js ws, isinstance(msg, bytes) in Python).
Raw deflate (RFC 1951) via the flate2 Rust crate with fast compression level. Decompress with inflateRaw / zlib.decompress(data, -zlib.MAX_WBITS)not inflate or gunzip.
No measurable impact. Each event is compressed once on the server (~0.05ms for a 1.2 KB message), then the same compressed bytes are sent to all compressed subscribers via zero-copy fan-out. Decompression on the client is equally fast.
Compression is set per connection at connect time. You cannot toggle it mid-session. Different connections from the same API key can use different modes.

When to use compression

ScenarioRecommendation
Production bots / trading systemsUse compression — saves bandwidth, no downside
Prototyping / debuggingSkip compression — raw JSON is easier to inspect
High-frequency firehoseUse compression — critical at scale
Browser dashboardsUse compression with pako — reduces data transfer