Make your dApp realtime in 5 minutes with Ethereum websockets — Tutorial

Trevor Clarke
amberdata
Published in
7 min readMay 15, 2019

How can I detect when a specific transaction occurs on Ethereum? How can my dApp show activity?

Tutorial Outline:

  • Demo Example
  • Use cases for blockchain websockets
  • How to setup a websocket connection
  • How to listen for a transaction confirmation
  • How to listen for contract events
  • Get your free Amberdata API key

So you’ve built a decentralized application and want to make it respond to realtime updates from the blockchain? Or maybe you are learning blockchain development and want to keep tabs on the data being confirmed? This week we will look at the entire setup for building your connection via websockets to the Ethereum blockchain.

TLDR; Here is the example code we’re going to reference, a very fun representation of Ethereum as a fireworks show! Take a look here →

Ethereum Fireworks Show — Blockchain websockets powered by Amberdata.io

How does this demo work?

The page is using 100% websockets, meaning it does a few things:

  1. Establishes a connection the websocket server as a single connection
  2. Subscribe to events for Blocks, Transactions, Internal Messages & Uncles
  3. Updates user interface whenever new data arrives

As you can see above, websockets are extremely powerful! With a single connection, the application can receive lots of data without needing to poll repeatedly for new data.

A few use cases for blockchain websockets:

  • Make your dApp update when users interact with your Smart Contract
  • Get notified of confirmed transactions
  • Receive the latest token transfers for an address
  • Get notified of latest blocks, transactions & all raw blockchain data
  • Receive updates for cryptocurrency market trades, orders & BBO* (Amberdata is the first to support this!)

How to setup a new websocket connection

The code for setting up a connection is pretty straight forward. The key is to create a single instance of the connection, as you can have multiple “subscriptions” for one connection. It’s similar to plugging in an ethernet cable, then receiving/transmitting internet data.

Here is an example using vanilla javascript and the browser native implementation of WebSocket.
If you’d like to read the entire documentation view it here →

const socket = new WebSocket('wss://ws.web3api.io?x-api-key=YOUR_API_KEY_HERE')

Using socket we can then start a new connection:

// Open Connection
socket.addEventListener('open', event => {
console.log('Connection opened - ', event)
})

If the connection is opened, you will receive an acknowledgement in the console. This will now allow us to move to the next step — Subscribing to events! We also want to know if there are any connection errors, so before we jump ahead let’s add some error handling:

// Closed Connection
socket.addEventListener('close', event => {
console.log('Connection closed - ', event.data)
})

This will let us know if any errors have occurred with the websocket connection, and give helpful hints on how to connect. In most cases it’s as simple as a missing an API Key. We’ll go into that at the very end of the post.

Subscribing to specific events — After successful connection

The most important part of receiving data via websocket is subscribing to events. An event is similar to a chat conversation. Take the example of irrigation for instance. If you connect a hose to a water spout it is like “connecting”. Once you turn the spout knob and water starts flowing the connection is established. If the hose is connected to many other branching hoses, to water trees or shrubs, then opening each hose connection is like “subscribing” to get water when its available to that plant. Hopefully this analogy is helpful!

To setup a subscription, use the following code:

// Subscribe using 'socket' Connection
socket.addEventListener('open', event => {
socket.send(`{
"jsonrpc": "2.0",
"id": 1,
"method": "subscribe",
"params": ["block"]
}`)
})

A couple things to note here:
- We use jsonrpc spec version 2
- “method” — A type of action for the server to take, in this case “subscribe”, which keeps your connection setup with parameters you send.
- “id” — This is an arbitrary identifier you can use, which allows you to have many concurrent subscriptions. Very helpful if you need to have lots of different ranges of data, or many different types of data your app subscribes to.
- “params” — The event name and arguments needed to establish the subscription. In most cases, only an event name is required, however if you want to subscribe to a specific Ethereum address, it would be an additional argument using the 0x based hash address to filter results for you.

If successful, this subscription will now allow your application to start receiving data! BUT WAIT! We haven’t yet setup any logic to do anything once data is sent! Let’s take a quick look now:

// Response Handler
const responseHandler = event => {
const data = JSON.parse(event.data)
console.log('New Event', data.id, data)
}
// Listen for messages
socket.addEventListener('message', responseHandler)

This is the last critical piece of code needed, you should now be receiving data! Try running this locally and see what data returns! You can read the full documentation for subscribing here →
Here’s a quick recap on the code we have so far:

How to listen for transaction confirmations

Let’s answer a few popular questions with some examples. How can I detect when a specific transaction occurs on Ethereum? How do I get notified of a single transaction changing from pending to confirmed? Address specific transactions, how do I get updates?

Below is the code for two scenarios:
1. Listening to all blockchain transactions
2. Listen to updates for a single transaction, perhaps you want to know when it is confirmed

// https://docs.amberdata.io/reference#ws-transactions
socket.addEventListener('open', event => {
// Subscribe to all transactions
socket.send(`{
"jsonrpc": "2.0",
"id": 'txnTest',
"method": "subscribe",
"params": ["transaction"]
}`)
// Subscribe to a single transaction
socket.send(`{
"jsonrpc": "2.0",
"id": 'txnTest',
"method": "subscribe",
"params": ["transaction",{"hash":"0xf16c9...b43a81"}]
}`)
})

As described earlier, the “params” part allows us to pass extra filter arguments. In the above example, passing “hash” will mean we will only get data updates for the transaction matching the hash we sent. This also means we need to listen for the response correctly, see the following as example:

// Response Handler for a single subscription
const responseHandler = event => {
if (event.id === 'txnTest') {
const data = JSON.parse(event.data)
console.log('New Event', data.id, data)
}
}
// Listen for messages
socket.addEventListener('message', responseHandler)

The key here: “event.id”, this allows us to identify the response with the ID we sent. That ID is unique the whatever you want, but it allows you to keep track of all the unique channels & logic you want without having websocket subscription collisions.

How to listen for contract events

Another huge demand of Ethereum websockets is Smart Contract events. I am specifically referring the logs that get stored when a contract emits an event. Take the following as an example of solidity code for emitting an event:

contract SomeContract {
event UserWinsMoney(address userId, uint256 amount);
// Later in code...
function sendUnsafeMoney(address _userId, uint256 _amount) {
// This emits the event, which gets stored in Ethereum
emit UserWinsMoney(_userId, _amount);
}
}

When the “emit UserWinsMoney(…)” creates a log and gets confirmed by Ethereum blockchain, then the data is available to be sent via websocket. The event gets fired after the first confirmation. Now your website or dApp can respond to smart contract events! The key is sending important data within the event that your dApp or website needs to make critical interface updates. In most cases its best to send data that acknowledges an action is finished and used the right data.
Let’s look at another example of how to listen for contract events via websockets:

// https://docs.amberdata.io/reference#ws-address-logs
socket.addEventListener('open', event => {
// Subscribe to CryptoKitties events
socket.send(`{
"jsonrpc": "2.0",
"id": 'txnTest',
"method": "subscribe",
"params": ["address:logs",{"address":"0x06012c8cf97bead5deae237070f9587f8e7a266d"}]
}`)
})

In this example, we use “address” to filter the events getting sent to CryptoKitties address. This means we will only see data like “Birth(…)” or “Transfer(…)”. You can see a realtime example of this here →

So many websockets, so many possibilities!

We’ve only covered a couple of the websockets available! Here’s a huge list to get you started:

Get a Free Amberdata API Key to begin using websockets today!
Go to Amberdata.io, and click “Get Started” to get a Free Developer API Key. You will need this to access the data in the next steps.

All Done!

Adding websockets to any project is a huge capability! See if you can build a new project using blockchain websockets. If you integrate, send us a link and we’ll showcase your integration!

This is just one of many ways to build using the Amberdata API. We’re constantly adding more tutorials! You can view all previous tutorials in our new website page here →

That’s it for this tutorial, share with colleagues, friends and on social!
We’d love to hear your thoughts in the comments below.

Previous Tutorials:

For more information about Amberdata.io:

--

--

Trevor Clarke
amberdata

VP of Product - Amberdata.io, Passionate Software Engineer 🤓, Hobbyist in 3D Design & Robotics