Skip to main content

Using WebSockets

alchemy
websockets
querying
javascript
Beginner
Elan Halpern
December 1, 2020
7 minute read

This is an entry level guide to using WebSockets to make requests to the Ethereum blockchain. The examples use standard JSON-RPC methods, so they work with any node or node provider that offers a WebSocket endpoint, including Alchemy.

 (opens in a new tab)WebSockets vs. HTTP

Unlike HTTP, with WebSockets, you don't need to continuously make requests when you want specific information. WebSockets maintain a network connection for you (if done right) and listen for changes.

As with any network connection, you should not assume that a WebSocket will remain open forever without interruption, but correctly handling dropped connections and reconnection by hand can be challenging to get right. Another downside of WebSockets is that you do not get HTTP status codes in the response, but only the error message.

Client libraries can handle this for you. For example, viem's WebSocket transport (opens in a new tab) reconnects on socket failure and sends keep-alive pings by default.

Try it out

You need a WebSocket URL for an Ethereum node. Node providers give you one when you create an API key, usually in the form wss://<provider-host>/<your-api-key>. For example, an Alchemy Ethereum Mainnet URL looks like wss://eth-mainnet.g.alchemy.com/v2/<your-api-key> (sign up for a free Alchemy account (opens in a new tab)). See nodes as a service for other providers, or use the WebSocket endpoint of your own node. Public endpoints such as wss://ethereum-rpc.publicnode.com also work for quick experiments, but they are rate-limited and may not support every subscription type.

The easiest way to test out WebSockets is to install a command line tool for making WebSocket requests such as wscat (opens in a new tab). Using wscat, you can send requests as follows:

npx wscat -c wss://<provider-host>/<your-api-key>

> {"jsonrpc": "2.0", "id": 0, "method": "eth_gasPrice"}

< {"jsonrpc": "2.0", "result": "0x41f9de2", "id": 0}

Lines starting with > are what you type, and lines starting with < are what the node sends back.

How to use WebSockets

To begin, open a WebSocket using your provider's WebSocket URL. With Alchemy, you can find it by opening your app in the dashboard (opens in a new tab) and viewing its API key. Note that the URL for WebSockets (wss://) is different from the URL for HTTP requests (https://), although most providers use the same API key for both.

Any of the JSON-RPC methods your provider supports can be used via WebSocket. To do so, use the same payload that would be sent as the body of a HTTP POST request, but instead send that payload through the WebSocket.

With Web3

Transitioning to WebSockets while using a client library like viem (opens in a new tab) is simple. Use the webSocket transport with your WebSocket URL instead of the http transport. For example, after npm install viem, save this as index.mjs and run node index.mjs:

Subscription API

When connected through a WebSocket, you may use two additional methods: eth_subscribe and eth_unsubscribe. These methods will allow you to listen for particular events and be notified immediately.

eth_subscribe

Creates a new subscription for specified events. Learn more about eth_subscribe (opens in a new tab).

Parameters

  1. Subscription types
  2. Optional params

The first argument specifies the type of event for which to listen. The second argument contains additional options which depend on the first argument. The different description types, their options, and their event payloads are described below.

Returns

The subscription ID: This ID will be attached to any received events, and can also be used to cancel the subscription using eth_unsubscribe.

Subscription events

While the subscription is active, you will receive events which are objects with the following fields:

  • jsonrpc: Always "2.0"
  • method: Always "eth_subscription"
  • params: An object with the following fields:
    • subscription: The subscription ID returned by the eth_subscribe call which created this subscription.
    • result: An object whose contents vary depending on the type of subscription.

Subscription types

  1. newHeads

Emits an event any time a new header is added to the chain, including during a chain reorganization.

When a chain reorganization occurs, this subscription will emit an event containing all new headers for the new chain. In particular, this means that you may see multiple headers emitted with the same height, and when this happens the later header should be taken as the correct one after a reorganization.

Example:

  1. logs

Emits logs which are part of newly added blocks that match specified filter criteria.

When a chain reorganization occurs, logs which are part of blocks on the old chain will be emitted again with the property removed set to true. Further, logs which are part of the blocks on the new chain are emitted, meaning that it is possible to see logs for the same transaction multiple times in the case of a reorganization.

Parameters

  1. An object with the following fields:
    • address (optional): either a string representing an address or an array of such strings.
      • Only logs created from one of these addresses will be emitted.
    • topics: an array of topic specifiers.
      • Each topic specifier is either null, a string representing a topic, or an array of strings.
      • Each position in the array which is not null restricts the emitted logs to only those who have one of the given topics in that position.

Some examples of topic specifications:

  • []: Any topics allowed.
  • [A]: A in first position (and anything after).
  • [null, B]: Anything in first position and B in second position (and anything after).
  • [A, B]: A in first position and B in second position (and anything after).
  • [[A, B], [A, B]]: (A or B) in first position and (A or B) in second position (and anything after).

Example:

This example listens for Deposit events from the WETH contract (opens in a new tab) on Ethereum Mainnet:

  1. newPendingTransactions

Emits the hash of each transaction that is added to the node's pending state (its mempool).

Example:

> {"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["newPendingTransactions"]}

< {"jsonrpc":"2.0","result":"0x1c2365b029179adf1e84b9e327315249","id":1}
< {"jsonrpc":"2.0","method":"eth_subscription","params":{"result":"0x4a62d0ad7c8868fbbfa10604e68638e637c6fc6f64fd1fb4ca042dcd0158c992","subscription":"0x1c2365b029179adf1e84b9e327315249"}}

Some providers also offer their own subscription types. For example, Alchemy's alchemy_pendingTransactions (opens in a new tab) emits full transaction objects instead of just hashes, and accepts optional fromAddress, toAddress and hashesOnly filters. These are not part of the standard JSON-RPC API, so they only work with that provider.

eth_unsubscribe

Cancels an existing subscription so that no further events are sent.

Parameters

  1. Subscription ID, as previously returned from an eth_subscribe call.

Returns

true if a subscription was successfully cancelled, or false if no subscription existed with the given ID.

A subscription only exists on the WebSocket connection that created it, so eth_unsubscribe must be sent over that same connection. It can't be sent as a separate HTTP request. Closing the connection also cancels all of its subscriptions.

Example:

> {"jsonrpc": "2.0", "id": 2, "method": "eth_unsubscribe", "params": ["0xe0d4abf5caf333fbf94c5f02182e6469"]}

< {"jsonrpc":"2.0","result":true,"id":2}

Sign up with Alchemy (opens in a new tab) for free, check out Alchemy's documentation (opens in a new tab), and for the latest news, follow Alchemy on Twitter (opens in a new tab).