Build a Chrome extension to track cryptocurrency prices - Part 1: Build the app
You will need Node 4+ and the Heroku CLI installed on your machine. Knowledge of JavaScript will be helpful.
In this tutorial, we will build a Chrome application that will serve cryptocurrency prices in realtime. We will use CryptoCompare that provides a free cryptocurrency API to get the live prices. We will use Pusher to update the prices we fetch from CryptoCompare.
A Chrome extension is a very handy tool. It is a small program that can enhance a user’s browsing experience or provide on demand information. There are several million extensions on the Chrome web store by different developers. Some provide a unique solution, others provide a feature of a standalone application.
Prerequisites
- Knowledge of HTML, CSS and JavaScript
- Knowledge of Node.js and Node.js(^4.*) installed on your local computer
- A Pusher app for realtime price tracking
- A Heroku account
- Heroku CLI tool kit installed on your local computer
Setting up the project
To start off, we need to create a Pusher account so we can get API keys for realtime updates. Go to Pusher and create a free account. Once you have a new account and you are signed in to the dashboard, create a new application and keep note of the keys. We will use the keys subsequently.
Create a new Node project
Create a directory that will hold our application files:
$ mkdir cryptowatcher
$ cd cryptowatcher
Now, create a new node.js project in that directory:
$ npm init -y
Here is what my setup looks like when I finished:
{
"name": "crytowatcher",
"version": "1.0.0",
"description": "A simple application to track live cryptocurrency prices",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js"
},
"keywords": [
"crypto",
"pusher",
"chrome-extension"
],
"author": "A retired superhero",
"license": "ISC"
}
Install Pusher and set it up
Now, let us install pusher:
$ npm install pusher --save
After installing pusher, create an index.js
file in the root directory and add the following file:
// /cryptowatcher/index.js
"use strict";
const Pusher = require('pusher')
const https = require('https');
const config = require('./config')
const cryptos = require('./cryptos.json')
const pusher = new Pusher(config)
We have imported all the packages and configuration files we need to run our application. You may wonder “Why are we not using Express?” and that would be an excellent observation. For this application, we only want a server that will make requests to the API and return the modified response as we please. We do not intend for this application to receive any external requests, so there is no need to create a server.
Now, let us assume we want to extend the application and add a database to store these prices as we fetch them. We might also want to store cryptos we want to track and currencies we want to check them against. We can even go further and decide to allow users customise the cryptos they want to watch and the currencies they want to get the prices in. At this point, it will be wise to create a server to allow external requests to our application. But for this guide, we are keeping things very simple.
Call the CryptoCompare API
Next, let us define the call to the CryptoCompare API:
// /cryptowatcher/index.js
[...]
setInterval(() => {
https.get(`https://min-api.cryptocompare.com/data/pricemulti?fsyms=${cryptos.coins.join()}&tsyms=${cryptos.currencies.join()}`, (response) => {
response.setEncoding('utf8')
.on('data', data => handleResponse(data))
.on('error', e => console.error(e.message))
})
}, 10000)
We are using Node’s built-in https
get request function to make the call. We have to set the encoding to utf8
. If we do not do this, it will return gibberish data. When we receive data, we pass the data to the handleResponse
method that handles the response.
Let us define the handleResponse
method:
// /cryptowatcher/index.js
[...]
let handleResponse = data => {
pusher.trigger('cryptowatch', 'prices', {
"update": data
});
}
The handleResponse
triggers a Pusher broadcast over the cryptowatch
channel. On the channel, we will broadcast the message using the prices
event. If you are thinking “Uhm… Can we have multiple events on a single Pusher channel?” then I am pleased to inform you that you are absolutely right. It is like having multiple channels on a cable TV.
Create an HTTPS server to allow us bind our application to a port when we deploy it:
// /cryptowatcher/index.js
[...]
https.createServer().listen(process.env.PORT || 8080)
Define config and crypto files
Next, we will define the config.js
file. Create the file:
$ touch config.js
Open the file and add the following to it:
// /cryptowatcher/config.js
module.exports = {
appId: 'YOUR-APP-ID',
key: 'YOUR-APP-KEY',
secret: 'YOUR-APP-SECRET',
cluster: 'YOUR-APP-CLUSTER',
encrypted: true
};
Please replace the values in the object above with the values you received after creating your Pusher application.
Now, create the cryptos.json
file:
$ touch cryptos.json
Open the file and add the following:
// /cryptowatcher/cryptos.json
{
"coins" : ["BTC","ETH","LTC","XRP"],
"currencies" : ["USD","EUR","GBP"]
}
If there are more coins or currencies you will like to track, just add them to the list.
The last thing we need to do is define the start script in our package.json
file. Open the file and edit the scripts
sections:
// /cryptowatcher/index.js
[...]
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index"
},
[...]
Making the Chrome extension
There is one thing that defines a Chrome extension, without which your extension is never going to work — manifest.json
file. It is to Chrome extensions what package.json
is to Node applications (and even more).
The file contains important information the Chrome extension requires to function. Many extensions might not use the manifest file for so much more than starting up. The manifest specifies the popup for your extension shows, it gives it a name, sets the display icon and a host of other things.
Creating the manifest file
We will create a new directory inside our project folder to hold the extension files.
$ mkdir extension
Now, create the /cryptowatcher/extension/manifest.json
file and add the following to it:
// /cryptowatcher/extension/manifest.json
{
"manifest_version": 2,
"name": "Cryptowatcher",
"description": "A simple application to track live cryptocurrency prices",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "index.html",
"default_title": "Cryptowatcher"
},
"permissions": [
"activeTab"
]
}
We need to make a tiny logo and replace icon.png
with it. 19x19 logo would do just fine. For this tutorial, we will use this.
Now, let us make the index.html
file. Create the file in the directory and add the following:
// /cryptowatcher/extention/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Crypto Watcher</title>
<style type="text/css">
body {
min-width: 200px;
height: 300px;
}
</style>
</head>
<body>
<h1>Coin Prices</h1>
<ol id="crypto-prices"></ol>
<script src="./pusher.min.js"></script>
<script src="./scripts.js"></script>
</body>
</html>
Chrome extension security policy disallows the use of inline scripts or scripts from external sources, that is why we did not call Pusher script from Pusher’s CDN. This is to prevent XSS or any form of attack on a user. So, download the pusher.min.js
file from here, save it in this directory /cryptowatcher/extensions/
.
Now, create the scripts.js
file and add the following:
// /cryptowatcher/extensions/scripts.js
const pusher = new Pusher('Your-App-Key', {
cluster: 'Your-cluster-key',
encrypted: true
})
let channel = pusher.subscribe('cryptowatch');
channel.bind('prices', (data) => {
let priceLists = ""
let obj = JSON.parse(data.update)
Object.keys(obj).forEach( (key, index) => {
priceLists += `<li>${key}: </br>`
let currencies = obj[key]
let currencyLists = "<ul>"
Object.keys(currencies).forEach( (currency, index) => {
currencyLists += `<li>${currency} : ${currencies[currency]}</li>`
});
currencyLists += "</ul>"
priceLists += `${currencyLists}</li>`
});
document.getElementById('crypto-prices').innerHTML = priceLists
});
Remember to replace ‘Your-App-Key’ and ‘Your-cluster-key’ with the values you generated from Pusher’s dashboard
We subscribed to the Pusher channel we created on our Node application and bind it to an event. When our Node application broadcasts data, we take it and present it on the popup. Think of it like buying a cable TV subscription (Pusher channel), tuning into a particular station (subscribing to event) then arguing with your friends about what is showing on TV (using the data broadcast).
To view the what we have achieved so far, run this command on your terminal
$ npm start
Once Node is up, open up the extensions/index.html
file on your browser, your output should look like this. It will take up to ten seconds before it fetches our coin details
Deploy to Heroku
We are going to deploy the application to Heroku. This will ensure our service keeps running and everyone that installs our Chrome extension will always get a price update.
First, you need to create a Heroku app. If you have Heroku installed on your local system, then you can use your terminal. If not, you can visit Heroku’s website and deploy the application directly from GitHub.
For this tutorial, we will deploy the application using the terminal. First, we need to log in:
$ heroku login
Supply your Heroku email address and password when prompted to log in on your local. This will allow you perform all the necessary actions from your terminal.
Next, let us create an application. Run this command in the root of your application
$ heroku create
We did not specify an application name so that Heroku will automatically generate a name for us. However, if you have a name in mind, you can add it after … create
and Heroku would use that name instead.
Heroku app names are unique. There can be no two applications with the same name even if they are created by different users. Your app URL will take your app name, and that is a strong reason for this.
Please note the name of the app and git URL Heroku generates as we will use it for deployment.
Next, we will initialize git and commit all the files in we have created. Because we do not want to commit our node_modules
folder, we will add it to our gitignore file.
$ touch .gitgnore
$ echo "node_modules/*" > .gitignore
$ git init
$ git add .
$ git commit -am "initial commit"
Next, add the heroku app to your git remote
$ heroku git:remote -a #app-name
Remember to change “app-name” to the name provided by Heroku
You can then push to your application to Heroku:
$ git push heroku master
When the application is deployed, we need to scale it to keep it running.
$ heroku ps:scale web=1
Heroku free accounts are equipped with 1 dyno. The caveat is that the dyno runs 18 out of 24 hours a day. When you want to take the application live, subscribe to any of Heroku’s plans to get full 24 hour uptime and heroku’s support.
With our implementation, anybody with the Chrome extension will automatically receive an update whenever our application publishes one.
From your browser, open chrome://extensions/
and click Load Unpacked
Then select the directory containing your extension from the dropdown. Chrome will launch the extension and an icon will pop up on your extension bar.
Click on it and see what our extension looks like at the moment
Conclusion
In this tutorial, we have built a working Chrome extension. I know it is way simpler than you might have imagined, but best believe this is real. We used Node. and Pusher to enable us build upon this current extension and make it robust.
In the next part of this tutorial, we will allow users set the preference for the coin they wish to track and we equally send them aggregates of price shifts over a month period to enable them know more about the coins. We can personalise this data feed in realtime, all thanks to Pusher’s realtime API.
The source code to the application in this article is available on GitHub.
26 October 2018
by Fisayo Afolayan