Real-Time Social Proof Ticker using WebSockets with Node.js

Use Case: To encourage ticket sales

We often feel peer pressure ... hard. We either want to join in the excitement or we just don't want to be left out.

In a project I did for a client (a theatre), I leveraged peer pressure or "social proof" to help encourage the sale of tickets to their shows. I had to install a new module in Node.js called Socket.IO which would allow the server to leverage websockets to communicate from the server back to the client without the need to refresh the page. I had to change a few things but all in all not very little additional code was needed.

Hey, Tyler here. I'm currently working on some great web development and digital marketing products and services over at ZeroToDigital.

If that sounds interesting to you, please check it out!

Update Server Configuration

My typical Node.js server configuration looks something like this:

JavaScript

const express = require('express')
const app = express()
app.listen(3000)

To leverage the Socket.IO module, the above changed to this:

JavaScript

const io = require('socket.io').listen(app.listen(3000))
app.use(function(req,res,next) {
	req.io = io
	next()
})

The first line sets up our socket to listen to the server, then, to be sure that our routes can access the io variable, we need to use middleware from Express.js to save the variable to the request object. We'll be able to use it later via req.io.

Send Messages on New Ticket Purchases

Once a customer has finalized their reservation and it's been stored into the database, etc., we want to send out a message to everyone currently on the website that the new tickets have been purchased. Nothing too descriptive, maybe just the person's first name and the name of the show.

We can send this data from the server side to the client side with this one line:

JavaScript

req.io.emit('tickets-reserved', `${first} just reserved tickets to ${showName}!`)

Note that this is inside our post route and after our ticket reservation logic.

We're levering the req.io variable with the function emit which sends the data with a name - 'tickets-reserved' and a message - `${first} just reserved tickets to ${showName}!`. And that's all we need to do in our routes file.

Listen and Print Messages in the Browser

On the client side we just need to set up our socket and then listen for the 'tickets-reserved' action:

JavaScript

a#tickets-reserved(href='/shows')
script.
	var socket = io.connect()
	socket.on('tickets-reserved', function(msg) {
		var resBlock = document.getElementById('tickets-reserved')
		resBlock.innerHTML = msg
		resBlock.classList.remove('is-active')
		resBlock.classList += ' is-active'
	})

Note that I'm doing this in Pug.js in case it looks a little different.

The first line is simply an <a> tag that will hold the message coming from the server. Then, inside of a <script> tag, we're creating our socket by simply setting socket equal to io.connect(). Then, inside the listener - 'on' - we manipulating the DOM by getting our <a> element, setting its inner HTML, removing the 'is-active' class if it exists from a prior message and then adding it back to trigger our CSS animation.

Here's the CSS:

JavaScript

#tickets-reserved {
	position: fixed;
	bottom: 20px;
	right: 20px;
	background-color: rgba(255,255,255,.8);
	@include transition(0.3s, opacity);
	opacity: 0;
	visibility: hidden;
	font-size: 14px;
	padding: 8px 10px;
	z-index: 100;
	border-radius: 5px;
	color: #333;
	box-shadow: 1px 1px 2px #d3d3d3;
	&:hover {
		color: $color-secondary;
	}
}
#tickets-reserved.is-active {
	@include animation(tickerFade, 7s);
}
@keyframes tickerFade {
	0% {opacity: 0;visibility: visible;}
	7% {opacity: 1;}
	93% {opacity: 1;}
	100% {opacity: 0;visibility: hidden;}
}

Note that the above CSS is actually SCSS to take advantage of mixins for transitions and animations in this example.

Here's a (low-quality) GIF of the finished product - what any user of the website will see on any page when an individual reserves tickets:

Tweet me @tylerewillis

Or send an email:

And support me on Patreon