How to Use Ethereum WebSocket RPC

WebSocket lets you subscribe to blockchain events instead of polling. Lower latency, less bandwidth, simpler code. This guide shows three common subscriptions on Ethereum: new blocks, pending transactions, and contract event logs.

Why WebSocket over HTTP?

With HTTP RPC you have to poll eth_blockNumberrepeatedly to detect a new block — wasteful, slow, and rate-limited. WebSocket holds a single persistent connection and pushes events to you the moment they happen. Typical use cases:

  • Trading bots that need to react to a new block within hundreds of milliseconds
  • Indexers that follow chain head and don’t want to poll
  • Wallet UIs that show live balance updates
  • Front-running detection (watching the mempool via newPendingTransactions)
  • Contract event monitoring (e.g. watching DEX swaps in real time)

The endpoint

wss://rpc.swiftnodes.io/ws/eth?key=YOUR_API_KEY

Note the wss:// scheme (secure WebSocket) and the /ws/ path prefix. The same API key works for both HTTP and WebSocket.

Example 1: Subscribe to new blocks (ethers.js)

import { WebSocketProvider } from "ethers";

const provider = new WebSocketProvider("wss://rpc.swiftnodes.io/ws/eth?key=YOUR_API_KEY");

provider.on("block", (blockNumber) => {
  console.log("New block:", blockNumber);
});

ethers handles reconnect-on-drop automatically. If the connection dies, it transparently reopens and re-subscribes — you don’t need to manage that yourself.

Example 2: Subscribe to a contract event (viem)

Listen for every Transfer event on the USDC contract:

import { createPublicClient, webSocket, parseAbiItem } from "viem";
import { mainnet } from "viem/chains";

const client = createPublicClient({
  chain: mainnet,
  transport: webSocket("wss://rpc.swiftnodes.io/ws/eth?key=YOUR_API_KEY"),
});

const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";

const unwatch = client.watchEvent({
  address: USDC,
  event: parseAbiItem("event Transfer(address indexed from, address indexed to, uint256 value)"),
  onLogs: (logs) => {
    logs.forEach(l => console.log(
      `${l.args.from} -> ${l.args.to}: ${l.args.value} USDC`
    ));
  },
});

Example 3: Pending transactions (raw JSON-RPC)

Watching the mempool with newPendingTransactions:

import WebSocket from "ws";

const ws = new WebSocket("wss://rpc.swiftnodes.io/ws/eth?key=YOUR_API_KEY");

ws.on("open", () => {
  ws.send(JSON.stringify({
    jsonrpc: "2.0", id: 1, method: "eth_subscribe",
    params: ["newPendingTransactions"],
  }));
});

ws.on("message", (raw) => {
  const msg = JSON.parse(raw.toString());
  if (msg.method === "eth_subscription") {
    console.log("Pending tx:", msg.params.result);
  }
});

Heads-up: pending-transaction subscriptions can fire thousands of events per second on Ethereum mainnet. Make sure your downstream processing keeps up, or filter early with a hash-only subscription and only fetch full data for transactions you care about.

Common pitfalls

  • Connection dropped silently. Always handle close and reconnect. ethers/viem do this for you; raw ws does not.
  • Subscriptions lost on reconnect. If the connection drops, the server forgets your subscriptions. Resubscribe on every reconnect.
  • Rate limits still apply. WebSocket usage counts toward your plan’s message-per-second limit. A noisy newPendingTransactions stream can exhaust it.
  • Don’t open one WebSocket per request. The whole point of WebSocket is to reuse a persistent connection. Keep one WS per process.

Reconnect strategy

Network blips happen. A production-grade WebSocket client should:

  1. Detect close events promptly
  2. Wait with exponential backoff (start at 1s, cap at 30s)
  3. Reopen the connection
  4. Re-issue every eth_subscribe call from before
  5. Optionally backfill any missed blocks via HTTP eth_getBlockByNumber

Want the full Ethereum RPC reference? See the Ethereum RPC page for all supported methods, code examples in ethers/viem/web3.py, MetaMask setup, and live status.