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_KEYNote 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
closeand reconnect. ethers/viem do this for you; rawwsdoes 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
newPendingTransactionsstream 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:
- Detect close events promptly
- Wait with exponential backoff (start at 1s, cap at 30s)
- Reopen the connection
- Re-issue every
eth_subscribecall from before - 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.