Hackathon: Building a Sales Leaderboard with RabbitFeed and Websockets

As mentioned in this post, we’ve been aligning our approach to business intelligence with our architectural principles. One of our hypotheses was that by taking an event-based approach to analytics we would be able to be more agile with our data. In order to test this hypothesis, we needed a ‘killer-app’ that would not only prove the approach, but also help us sell it to the rest of the business.

Finding a Killer-App

We sell our product via two primary channels: online and offline. Our offline channel is served by a contact centre in our Northampton office. Sales consultants call potential customers and attempt to make sales over the phone. Previously, whenever consultants made sales, they would have to get up from their desks, walk to their team’s white board, and manually record the sale.

Our idea for the ‘killer-app’ was to utilise the wall boards scattered about the contact centre for displaying a sales leaderboard fed by events from our back office system. Not only would this remove an inefficient manual step in the sales process, it would also foster a sense of friendly competition amongst consultants (we hoped).

The Leaderboard

The leaderboard is a simple ranking of consultants by the total value of the product that they have sold for the day. Rankings can be split out by teams to show consultants not only how they rank with the rest of the contact centre, but also within their own team. It looks something like this (note that this is sample data):


How it Works

Whenever a consultant completes a sale on our back office system, it publishes a sales event. The leaderboard application subscribes to these sales events. Once a sales event is consumed, it is immediately pushed up to the leaderboard.

The Sales Event

The event publish/subscribe is performed using RabbitFeed.


The event publish is done at the point the consultant completes a sale in the back office. This event is then available to any downstream application for consumption.

The sales event is defined in the RabbitFeed initialiser like this:

The event is published from the Rails controller:


A RabbitFeed consumer process runs in the Rails environment on the leaderboard server. This process will apply the sale to the day’s rankings and will push the update to the clients.

The subscription is configured in the RabbitFeed initialiser like this:

When an event is consumed, a consultant ranking record is found or initialised and the sale is applied to the consultant’s ranking. The updated ranking is then pushed up to the clients. The event handling code looks like this:

Updating the Leaderboard

At any one time, there will be 10-15 clients displaying the leaderboard in a browser window. There are a few options available for updating the leaderboard with new data and sales. We could simply trigger the browser to refresh the page at specified time intervals, but this method doesn’t afford any interactivity or excitement when new data is displayed. Alternatively, we could have each client continuously poll the server for updates, but this requires the client to maintain some state about the updates it has processed. We wanted a mechanism by which all clients would be updated simultaneously and instantaneously whenever a sale was made. This allows the client to apply any updates to the leaderboard with a flash! We were able to achieve this via the use of Web Sockets.



First, we need to add the websocket-rails gem to our leaderboard application:

Next, we need to enable the RabbitFeed consumer process to trigger websocket events. Because the RabbitFeed consumer process is asynchronous, it runs as a separate process outside of the leaderboard web application. We needed a means for websocket events triggered within the RabbitFeed consumer process to be sent to clients connected to the leaderboard web application. Fortunately, websocket-rails has this capability built-in: Using Redis, a websocket event triggered on one process will be pushed onto Redis and synchronised to the other process.

Set this configuration option in the websocket-rails initialiser to enable websocket synchronisation:

The websocket event will be published to the consultant_ranking channel. The clients will subscribe to this channel. The event is published by calling trigger with the change event and a payload. The client handler will bind to this event type. The code to trigger the websocket event looks like this:

On the client side, we create a websocket pointing back to the websocket URL on our server. We then subscribe to the consultant_ranking channel and define a handler function for change events. The event handler will be called for every change event triggered on the server. The event handler will apply the change in ranking to the leaderboard with a flash. The code looks like this:


Due to the distributed nature of the design, there are no bottlenecks between the back office application and the leaderboard. As soon as a sales event is published, the leaderboard subscriber consumes the event and pushes it up to the clients. In fact, the sale often registers on the leaderboard before the back office system can load the post-sale page!


The leaderboard was an instant success: Sales consultants began vying for the top ranking on the leaderboard, team managers were able to get immediate feedback on the performance of their team members, and senior management gained improved insight on who the top performers in the contact centre were. The leaderboard proved that an event-based approach to analytics would allow us to be more agile with our data. Additional applications were soon built using the same approach. For example, we created a daily sales dashboard showing stats on the day’s sales, split by the online and offline channels as well as a business KPI monitoring and alerting system.

Find out more about how you can use RabbitFeed to unlock the potential of your data

Ready to start your career at Simply Business?

Want to know more about what it’s like to work in tech at Simply Business? Read about our approach to tech, then check out our current vacancies.

Joshua Fleck

This block is configured using JavaScript. A preview is not available in the editor.