Stream live blockchain data over WebSocket

Decoded blocks, swaps, transfers, and any Substreams DatabaseChanges output — delivered in seconds. Subscribe to one or many streams across SVM, EVM, TVM, HyperLiquid, Polymarket, and any chain Pinax supports. Resume exactly where you left off after a disconnect.

Real-time, multi-chain

One generic decoder for every db_out-style Substreams package. Solana, Ethereum, Base, Arbitrum, TVM, HyperLiquid, Polymarket — same URL pattern.

Reorg-aware

Every payload carries a Substreams cursor and module_hash. undo messages fire on chain reorganizations so subscribers can roll back deterministically.

Use the Try it button in the bottom-right corner to open a full-screen WebSocket client — connect, subscribe, and watch blocks roll in without leaving this page.

Available streams

Live snapshot of every stream this server is configured to broadcast. Click a tile to copy its network@stream selector. Data sourced from GET /streams.

Loading from /streams

URL modes

Stream selectors are <network>@<stream>. * is a wildcard on either side. Two ways to connect:

URLModeEnvelope
WS/ws/<a> Single, path raw payload
WS/ws/<a>/<b>/... Multi, path wrapped
WS/stream?streams=<a>/<b>/... Combined, query wrapped

When wrapped, every payload is delivered as:

{ "stream": "<network>@<stream>", "data": <raw payload> }

Bare /ws with no streams returns HTTP 400. Use /ws/*@* to opt into every stream explicitly. See the HTTP group in the sidebar for non-WebSocket endpoints (/streams, /healthz, /SKILL.md, /llms.txt).

Connected message

Sent once per connection. Lists every configured stream and echoes this connection's resolved subscriptions.

{
  "type": "session",
  "status": "connected",
  "client_id": 1,
  "streams": [
    {
      "stream": "swaps",
      "network": "solana-mainnet",
      "module": "db_out",
      "manifest": "https://.../svm-dex-v0.5.1.spkg",
      "module_hash": "bd388f2e39f5dcc237cfbdb8d6c96d9e5678c797"
    }
  ],
  "subscriptions": ["solana-mainnet@swaps"],
  "wrap_envelope": false
}

Block payload

One message per non-empty block. Empty blocks are skipped; their cursor is still persisted server-side.

{
  "stream":      "swaps",
  "network":     "solana-mainnet",
  "block_num":   350000000,
  "block_hash":  "Gsk6...",
  "timestamp":   "2026-05-13 17:00:00",
  "cursor":      "Mloz_-WpoBoZ...",
  "module_hash": "bd388f2e...",
  "events": [
    {
      "@table":        "swaps",
      "input_amount":  "1287000000",
      "input_mint":    "So11111111111111111111111111111111111111112",
      "output_amount": "6848381008732",
      "output_mint":   "13muFY...",
      "protocol":      "raydium_cpmm",
      "user":          "F2MUE..."
    }
  ]
}

Field rules:

Stream lifecycle

Same connection, distinguished by "type": "stream". Filtered by subscriptions just like block payloads.

{ "type": "stream", "status": "started",   ... }
{ "type": "stream", "status": "completed", ... }
{ "type": "stream", "status": "error",     ..., "message": "..." }
{ "type": "stream", "status": "fatal",     ..., "message": "..." }
{ "type": "stream", "status": "undo",      ..., "last_valid_block": 350000000 }

undo fires on chain reorganizations. Roll back any state materialized past last_valid_block.

SUBSCRIBE

Add to the per-connection subscription set. Idempotent.

// request
{ "method": "SUBSCRIBE",
  "params": ["solana-mainnet@swaps", "ethereum-mainnet@transfers"],
  "id": 1 }

// reply
{ "result": null, "id": 1 }

Wildcards accepted (["*@swaps"]). A single bad selector rejects the whole command — existing set unchanged. The wrap_envelope mode is fixed at upgrade time and is not affected by SUBSCRIBE.

UNSUBSCRIBE

Remove from the subscription set. Silent on unknown selectors.

// request
{ "method": "UNSUBSCRIBE",
  "params": ["ethereum-mainnet@transfers"],
  "id": 2 }

// reply
{ "result": null, "id": 2 }

To remove a wildcard subscription, pass the exact wildcard form (*@swaps removes the wildcard entry, not the individual streams it currently matches).

LIST_SUBSCRIPTIONS

Inspect the current subscription set.

// request
{ "method": "LIST_SUBSCRIPTIONS", "id": 3 }

// reply
{ "result": ["solana-mainnet@swaps", "ethereum-mainnet@*"], "id": 3 }

Insertion order preserved. Wildcards returned verbatim, not expanded.

Cursors

Every block payload includes cursor. To resume from an exact position across reconnects, persist the last cursor you processed and reconnect to a Substreams gRPC endpoint directly with it — this server has no replay buffer.

Heartbeats

The server sends WebSocket ping frames every SUBSTREAMS_WEBSOCKET_HEARTBEAT_INTERVAL_SECS seconds (default 180s). Standard WebSocket clients pong automatically. The server closes connections that do not pong within SUBSTREAMS_WEBSOCKET_HEARTBEAT_TIMEOUT_SECS seconds (default 600s).

Limits