Skip to main content

WebSocket connections

Sei supports eth_subscribe over WebSocket. With the WebSocket transports in standard libraries, you can subscribe to new blocks, event logs, and pending transactions.

Endpoints

Connecting

Watching new blocks

Watching contract events

Watching ERC-20 transfers across all contracts

viem

Notes

  • Sei has instant finality, so every block emitted over WebSocket is already final. You do not need to wait for more confirmations before you act on an event.
  • Sei does not support newPendingTransactions subscriptions. You can subscribe only to newHeads and logs.

Frame size and concurrency limits

WebSocket connections use the same request limits as HTTP JSON-RPC. Operators set them in the [evm] section of app.toml:
  • max_request_body_bytes (default 5 MiB) caps each WebSocket frame and each HTTP request body. If a frame is larger, the node closes the connection with WebSocket close code 1009 and does not send a JSON-RPC error.
  • max_concurrent_request_bytes (default 128 MiB) caps the request bytes that the node processes at the same time. WebSocket and HTTP each have their own budget.
  • ws_admission_timeout (default 30s) sets how long a WebSocket request waits for budget. When the wait expires, the client gets JSON-RPC error -32005 and the node closes the connection, which ends its subscriptions.
Before v6.7.0, the WebSocket frame limit was 10 MiB. If your clients send frames between 5 MiB and 10 MiB, set max_request_body_bytes = 10485760 in app.toml before you upgrade. This setting also raises the HTTP body limit to 10 MiB.

newHeads under Autobahn consensus

When a node runs under Autobahn consensus, eth_subscribe("newHeads") notifications come from an in-process notifier, not from the legacy consensus event bus. The notifier publishes committed-block headers directly. Subscribers still observe headers only for fully committed blocks. However, the header payload differs from the legacy path in a few ways:
  • parentHash, receiptsRoot, and transactionsRoot are returned as zero hashes (0x0000…0000). The Autobahn block-execution path does not build a Tendermint-style hash chain, so there is no meaningful value to return in these fields.
  • stateRoot comes from the finalized block’s AppHash (the post-execution application hash), not from a pre-execution header field.
  • hash is the Autobahn block-header hash. It is the same value that eth_getBlockByNumber and the receipt APIs report as blockHash. This keeps newHeads consistent with the rest of the EVM RPC surface.
  • gasUsed is an approximation (summed from per-transaction results) that keeps the notification cheap.
Because of these differences:
  • Subscribers that chain-validate the head stream by linking parentHash values cannot rely on newHeads under Autobahn. They need a different mechanism.
  • If you need the exact gasUsed or the omitted hash fields, fetch the block explicitly with eth_getBlockByNumber.