Today we are going to see how to build a realtime polling system over Blockchain. We have already covered a tutorial on how to build a realtime polling system without involving blockchain with PieSocket, you can read it here.
You can see the demo of the application we are about to build here: Real-time Poll Over Blockchain Demo
You need an Ethereum wallet like MetaMask to cast vote on blockchain. You also need some ether in your wallet to pay for the gas fee.
This demo uses Rinkeby Test Blockchain Network, which means you can cast your vote using fake Ethereum and save real money.
Guide to get fake Ether for testing: https://medium.com/compound-finance/the-beginners-guide-to-using-an-ethereum-test-network-95bbbc85fc1d
Why Blockchain?
Two words answer: Trust & Transparency
Data/contracts/transactions stored on blockchain can not be changed and there is a transparent record for all the changes that are made.
Blockchain contracts can be considered as trustworthy evidence of events and transactions.
We are building a polling system for which trust and transparency are the core factors. Keeping that in mind, we will manage record of each vote on the blockchain.
Transparency does not mean anyone will be able to see who voted whom. While anyone can see who voted when and how many times, they will not be able to see the contents of the blockchain contract (vote).
We will use PieSocket’s Blockchain realtime feature to build this system and PieSocket takes care of all the security practices out of the box.
PieSocket provides an API secret which can be used by admins to decode the data in a blockchain transaction, giving the admin power to see the votes.
Frontend
Let’s quickly build the frontend UI for our polling system considering the following features:
We will build two pages.
- For voters: To cast their vote
- For admins: To see the poll results in real-time.
Lets begin by creating a file voter.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Blockchian Polling</title> <!-- Tailwind CSS --> <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.6.1-rc.2/web3.min.js"></script> <script src="https://unpkg.com/piesocket-js@1.4/dist/piesocket.js"></script> </head> <body> <div class="bg-white pt-24"> <div class="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:py-16 lg:px-8"> <div class="lg:grid lg:grid-cols-2 lg:gap-8 lg:items-center"> <div> <h2 class="text-3xl font-extrabold text-gray-900 sm:text-4xl"> Vote For Your Favourite Cartoon Character </h2> <p class="mt-3 max-w-3xl text-lg text-gray-500"> Vote for your favorite cartoon character. You can change your mind later but not the vote, this is going on Blockchain. </p> <div class="mt-8 sm:flex"> <div class="rounded-md shadow"> <a href="https://metamask.io/download" target="_blank" class="flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700"> Install MetaMask Wallet </a> </div> <div class="mt-3 sm:mt-0 sm:ml-3"> <a target="_blank" href="https://piesocket.com/blog/realtime-polling-over-blockchain" class="flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-indigo-700 bg-indigo-100 hover:bg-indigo-200"> View Tutorial </a> </div> </div> <a class="mt-6 inline-block underline text-blue-500" href="./admin.php">View Poll Results</a> </div> <div class="mt-8 grid grid-cols-2 gap-0.5 md:grid-cols-3 lg:mt-0 lg:grid-cols-2"> <a href="javascript:voteFor('Tom')"> <div class="hover:bg-blue-200 cursor-pointer col-span-1 flex justify-center py-8 px-8 bg-gray-50"> <img class="max-h-24" src="/img/demos/tom.png" /> </div> </a> <a href="javascript:voteFor('Spongebob')"> <div class="hover:bg-blue-200 cursor-pointer col-span-1 flex justify-center py-8 px-8 bg-gray-50"> <img class="max-h-24" src="/img/demos/spongebob.png" /> </div> </a> <a href="javascript:voteFor('Jerry')"> <div class="hover:bg-blue-200 cursor-pointer col-span-1 flex justify-center py-8 px-8 bg-gray-50"> <img class="max-h-24" src="/img/demos/jerry.jpeg" /> </div> </a> <a href="javascript:voteFor('Mickey Mouse')"> <div class="hover:bg-blue-200 cursor-pointer col-span-1 flex justify-center py-8 px-8 bg-gray-50"> <img class="max-h-24" src="/img/demos/mickey-mouse.jpeg" /> </div> </a> </div> </div> </div> </div> </body> </html> |
This HTML with Tailwind CSS creates the following UI

Lets add some Javascript to create the voting feature.
We will create a function voteFor
to cast a vote for the selected cartoon character.
But, before that lets add PieSocketJS to the code. Use the following tag to include PieSocket in your page.
1 |
<script src="https://unpkg.com/piesocket-js@1.4/dist/piesocket.js"></script> |
We are ready to use PieSocket. Add following code to initialise PieSocket. We are using a Test API key, replace it with yours.
1 2 3 4 5 6 |
var piesocket = new PieSocket({ clusterId: 'demo', apiKey: 'oCdCMcMPQpbvNjUIzqtvF1d2X2okWpDQj4AwARJuAgtjhzKxVEjQU6IdCjwm', blockchainTestMode: true, blockchainGasFee: 35000 }); |
blockchainTestMode: true
configures PieSocket to use Rinkeby Test Network (free to test) instead of Main Ethereum Network.
Next, we will subscribe to a channel. Let’s call it blockchain-polls
1 |
var channel = piesocket.subscribe("blockchain-polls"); |
Add two event handlers for when an error occurs and for when the voting is recorded.
1 2 3 4 5 6 7 |
channel.on('blockchain-error', function(e) { alert(e); }) channel.on('blockchain-hash', function(e) { alert("Your vote is recorded, you can vote again but Ethereum will know."); }) |
We are ready to write our voteFor
function.
1 2 3 4 5 6 7 |
function voteFor(name) { channel.publish("vote", { votedFor: name }, { blockchain: true }); } |
Above function will be called when users click on a candidate’s image.
It will open MetaMask on your browser, click confirm to accept the transaction and cast your vote on the Blockchain.

Backend
We need a backend to see the list of votes in realtime.
We are using PHP in this example, but writing similar code in any backend language should be as easy to write.
Let’s create a file admin.php
and add the following UI to it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Blockchian Polling Results</title> <!-- Tailwind CSS --> <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet"> <script src="https://unpkg.com/piesocket-js@1.4/dist/piesocket.js"></script> </head> <body> <div class="bg-white pt-24 px-24"> <a class="mt-6 inline-block underline text-blue-500" href="./voter.php">Back To Vote</a> <h2 class="text-3xl font-extrabold text-gray-900 sm:text-4xl"> Latest votes </h2> <p class="mt-3 max-w-3xl text-lg text-gray-500"> Following are the most recent 20 votes. </p> <div class="mt-10 mb-10 bg-white shadow overflow-hidden sm:rounded-md"> <ul id="votes" role="list" class="divide-y divide-gray-200"> </ul> </div> </div> </body> </html> |
And add the following Javascript in the page to show the incoming votes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<script> var piesocket = new PieSocket({ clusterId: 'demo', apiKey: 'oCdCMcMPQpbvNjUIzqtvF1d2X2okWpDQj4AwARJuAgtjhzKxVEjQU6IdCjwm' }); var channel = piesocket.subscribe("blockchain-polls"); channel.listen("vote", function(data, meta) { var template = `<li class="p-6"> <a target="_blank" href="https://rinkeby.etherscan.io/tx/${meta.transaction_hash}"> <button class="float-right bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">View on Etherscan </button> </a> <p>${data.votedFor}</p> <p>Transaction hash: ${meta.transaction_hash}</p> </li>`; var voterList = document.getElementById("votes"); voterList.innerHTML = template + voterList.innerHTML; }); </script> |
You should have a backend as shown below.

There is one problem yet.
Votes disappear when we refresh the page.
We can use PieSocket REST APIs to fetch previous blockchain messages for any channel.
Add the following code on the top of the PHP file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?php $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => 'https://www.piesocket.com/api/contracts?channel=piedemo-cartoon-polls', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_HTTPHEADER => array( 'key: oCdCMcMPQpbvNjUIzqtvF1d2X2okWpDQj4AwARJuAgtjhzKxVEjQU6IdCjwm', 'secret: d8129f82f8dd71910aa4a7efa30a7297' ), )); $response = curl_exec($curl); curl_close($curl); $previousVotes = json_decode($response,true)['data']; ?> |
Above code calls the PieSocket Account API to fetch blockchain contracts/messages and stores them in a variable $previousVotes
You can print them in the page like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<ul id="votes" role="list" class="divide-y divide-gray-200"> <?php foreach($previousVotes as $vote){ $data = json_decode($vote['message']); echo '<li class="p-6"> <a target="_blank" href="https://rinkeby.etherscan.io/tx/'.$vote['transaction_hash'].'"> <button class="float-right bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">View on Etherscan </button> </a> <p>'.$data->votedFor.'</p> <p>Transaction hash: '.$vote['transaction_hash'].'</p> </li>'; } ?> </ul> |
This covers our simple polling system with Blockchain integration.
Every vote is registered on the Blockchain network and can be viewed using the transaction hash.
Following is an example record: https://rinkeby.etherscan.io/tx/0x863575cfb66bc96a81e9f80e076e4fb56a47b48a2a91dae43c2b4fa59a18e075
You can see the input data of each contract on the link above. It is a AES-256 encrypted hash (military grade security) which can be decoded with your API secret.
