Add a Feefo rating to your site

Feefo is a popular service that allows businesses to aggregate reviews and ratings of their services. You can then promote your fine work to the world in the form of a star rating on your site – hopefully giving your potential customers some confidence in what you’re offering.

Recently I created a generic script for displaying a Feefo rating on your site – on first load the script gets the data from Feefo and renders the data appropriately. It will then save that data in the users session storage for subsequent page loads.

The HTML

Pretty self explanatory. This is the container for the star rating and the Feefo logo:

<div class="feefo-percentage"></div>

The next bit displays the number of reviews the rating was based on – I’ve also added a link opportunity for your Feefo page if required:

<p><a href="">Read the reviews</a> (<span class="feefo-responses">0</span> reviews)</p>

I have generally added this inline but you can also incorporate this in your core JS files or add it to your feefo.js file if you only ever intend to use the script with one site:

<script type="text/javascript">

	/* Feefo setup */

	var feefoLogin = 'www.yoursite.tld';

</script>

Lastly, make a reference to your feefo.js file – this should be called last as it may block the loading of more important objects on your page if loaded in the header:

<script type="text/javascript" src="/path/to/scripts/feefo.js"></script>

The JavaScript

The main JS for the functionality can be put in a file on its own for reuse on multiple sites or templates or incorporated into your larger codebase – ensure it is placed after the script snippet above:

var FeefoData = {

	use: function(data) {

		if (sessionStorage.feefoPercentage && sessionStorage.feefoResponses) {

			feefoPercentage = sessionStorage.feefoPercentage;
			feefoResponses = sessionStorage.feefoResponses;

		} else {

			feefoPercentage = data.FEEDBACKLIST.SUMMARY.AVERAGE;
			feefoResponses = data.FEEDBACKLIST.SUMMARY.TOTALRESPONSES;
			feefoExpires = Date.now();

			sessionStorage.feefoPercentage = feefoPercentage;
			sessionStorage.feefoResponses = feefoResponses;
			sessionStorage.feefoExpires = feefoExpires + (1000 * 60 * 60 * 24);

		}

		var feefoPercentageBlocks = document.querySelectorAll('.feefo-percentage');

		for (var f = 0; f < feefoPercentageBlocks.length; f++) {

			var ghostPercentage = document.createElement('div'),
				activePercentage = document.createElement('div');

			activePercentage.style.width = feefoPercentage + '%';
			activePercentage.setAttribute('title', feefoPercentage + '% approval rating from Feefo');

			feefoPercentageBlocks[f].appendChild(ghostPercentage);
			feefoPercentageBlocks[f].appendChild(activePercentage);

		}

		var feefoResponsesBlocks = document.querySelectorAll('.feefo-responses');

		for (var t = 0; t < feefoResponsesBlocks.length; t++) {

			if ('textContent' in document.body) {
				feefoResponsesBlocks[t].textContent = feefoResponses;
			} else {
				feefoResponsesBlocks[t].innerText = feefoResponses;
			}
		}

	},

	get: function() {

		/* Has data expired? */

		if (sessionStorage.feefoExpires) {

			if (sessionStorage.feefoExpires < Date.now()) {
				sessionStorage.clear();
			}

		} else {

			sessionStorage.clear();

		}


		/* Feefo content */

		if (sessionStorage.feefoPercentage) {

			FeefoData.use();

		} else {

			var head = document.querySelector('head'),
				feefoURI = 'https://www.feefo.com/feefo/xmlfeed.jsp?logon=' + feefoLogin + '&json=true&since=year&limit=0&callback=FeefoData.use',
				scriptElement = document.createElement('script');

			scriptElement.setAttribute('src', feefoURI);
			scriptElement.setAttribute('type', 'text/javascript');
			head.appendChild(scriptElement);

		}

	}

}


/* Run initialisation */

if (window.addEventListener) {
	window.addEventListener('load', FeefoData.get);
} else {
	window.attachEvent('onload', FeefoData.get);
}

The JavaScript loads the data from the Feefo web site then stores the relevant bits into sessionStorage - I also added a timestamp so I can expire the data after a day for those who never close their browsers (so that's me then).

The CSS

Styling for the rating stars and the logo. The logo is in Base64 format and inlined in the CSS below - the stars are in SVG format and have been urlencoded before being inlined:

.feefo-percentage {
	position:relative;
	width:85px;
	height:17px;
}

.feefo-percentage:after {
	content:'';
	background-image: url('data:image/png;base64,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');
	width: 82px;
	height: 19px;
	display: block;
	position: absolute;
	top: -4px;
	right: -92px;
	background-size: 82px 19px;
}

.feefo-percentage > div {
	background-image:url('data:image/svg+xml,%3Csvg%20width%3D%22149%22%20height%3D%2229%22%20viewBox%3D%220%200%20149%2029%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%0A%0A%09%3Csymbol%20id%3D%22sym%22%20viewBox%3D%220%200%2029%2029%22%3E%0A%09%09%3Cpath%20fill%3D%22%23fddf05%22%20d%3D%22m0%2C11.11l10.94%2C0l3.38%2C-11.11l3.38%2C11.11l10.94%2C0l-8.85%2C6.86l3.381%2C11.11l-8.85%2C-6.86l-8.85%2C6.86l3.38%2C-11.11l-8.85%2C-6.86l-0%2C0z%22%2F%3E%0A%09%3C%2Fsymbol%3E%0A%0A%09%3Cg%3E%0A%09%09%3Cuse%20xlink%3Ahref%3D%22%23sym%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2229%22%2F%3E%0A%09%09%3Cuse%20xlink%3Ahref%3D%22%23sym%22%20x%3D%2230%22%20y%3D%220%22%20width%3D%2229%22%2F%3E%0A%09%09%3Cuse%20xlink%3Ahref%3D%22%23sym%22%20x%3D%2260%22%20y%3D%220%22%20width%3D%2229%22%2F%3E%0A%09%09%3Cuse%20xlink%3Ahref%3D%22%23sym%22%20x%3D%2290%22%20y%3D%220%22%20width%3D%2229%22%2F%3E%0A%09%09%3Cuse%20xlink%3Ahref%3D%22%23sym%22%20x%3D%22120%22%20y%3D%220%22%20width%3D%2229%22%2F%3E%0A%09%3C%2Fg%3E%0A%0A%3C%2Fsvg%3E');
	background-repeat:no-repeat;
	position:absolute;
	top:0;
	width:0%;
	height:17px;
	background-size:85px;
	transition:all 2s ease-in-out 1s;
}

.feefo-percentage > div:first-child {
	background-image:url('data:image/svg+xml,%3Csvg%20width%3D%22149%22%20height%3D%2229%22%20viewBox%3D%220%200%20149%2029%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%0A%0A%09%3Csymbol%20id%3D%22sym%22%20viewBox%3D%220%200%2029%2029%22%3E%0A%09%09%3Cpath%20fill%3D%22%23ccc%22%20d%3D%22m0%2C11.11l10.94%2C0l3.38%2C-11.11l3.38%2C11.11l10.94%2C0l-8.85%2C6.86l3.381%2C11.11l-8.85%2C-6.86l-8.85%2C6.86l3.38%2C-11.11l-8.85%2C-6.86l-0%2C0z%22%2F%3E%0A%09%3C%2Fsymbol%3E%0A%0A%09%3Cg%3E%0A%09%09%3Cuse%20xlink%3Ahref%3D%22%23sym%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2229%22%2F%3E%0A%09%09%3Cuse%20xlink%3Ahref%3D%22%23sym%22%20x%3D%2230%22%20y%3D%220%22%20width%3D%2229%22%2F%3E%0A%09%09%3Cuse%20xlink%3Ahref%3D%22%23sym%22%20x%3D%2260%22%20y%3D%220%22%20width%3D%2229%22%2F%3E%0A%09%09%3Cuse%20xlink%3Ahref%3D%22%23sym%22%20x%3D%2290%22%20y%3D%220%22%20width%3D%2229%22%2F%3E%0A%09%09%3Cuse%20xlink%3Ahref%3D%22%23sym%22%20x%3D%22120%22%20y%3D%220%22%20width%3D%2229%22%2F%3E%0A%09%3C%2Fg%3E%0A%0A%3C%2Fsvg%3E');
	width:100%;
}

.feefo-percentage > div:last-child {
	width:0;
}

This script and the related other code should work in IE9 and above, plus all other modern browsers. If you want IE8 support, all you will need to do is replace the SVG backgrounds with something less exotic to the browser, like PNGs, as below:

.feefo-percentage:after {
	background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFIAAAATCAMAAAA09qpgAAABF1BMVEUAAABJRUVJRUVJRUX/3QBHQ0WhjypJRUVJRUVJRUVJRUVJRUVJRUVJRUVJRUVJRUVJRUX/3QBJRUVJRUVJRUVJRUVJRUVIREVJRUVJRUVJRUVJRUVJRUVJRUVJRUVJRUVJRUVJRUVGQ0ZJRUVJRUVDQEdJRUVJRUVJRUX/3QBJRUVJRUVJRUVDQEf/3QD/3QD/3QD/3gBJRUX/3QBJRUX/3QD/5AD/3QD/3QBJRUVJRUVJRUX/5QD/3QD/3QBJRUX/3QBJRUX/3QD/3QD/3QD/3QD/3QD/3QD/3QD/3QD/3QD/3QD/3QD/3QBEQUf/6AD/3QD/3QAtLlD/+QD/3QBJRUX/3QD/3QD/3QD/3QBJRUVJRUX/3QBHMCQSAAAAW3RSTlMAfvzxvA8D7+pS5b6oo51L99TSl4QrHBXarIp3V9+2spJoPzQwJxMI87ZvRiILC/Dn3MKxgR0WoIJcORoP+s3HwLusknBpTEU8Niv59eLd1qeKiHp4ZF5WPzMfnHfWGQAAAoNJREFUOMuFk9d64jAQhQ8hNrhgYxub3kLvATak180m2WzvxX7/54hmjH3B90H+C3wkDUcjzQiAXLaz/TZeoV1X/QY2eb88nM2/TUlOT+azw8ETiKIvOMNuRhRUxAbvAma+Ai6sUN8DMCm4MMZuNIoqb+YYrBkAXyP9CJRFrINX6KZElIsNjoOIo4tYLjHWRXAjPwHQUxq60zxHhJvIZHIHpKTTrO+nDro8W3Yaww4p2Yp9fj/G8hBJn2kBSjqUJTD5eji0xVIulBngvBbKYh64mAXLfcZ6+HsVqmVwGVm2UfIjNAg6qXhsRms6zrLRZLoDzIMVGFkAZiqyXOyJ9X5BUjiQBny1UoGHPO73Ktk9GgzltB/zWcKP4ATE0WA1HTyzvKephFh+gzwF652J1+Cc+ahqRZJMsjYgiZxTEjJ85pF5S9/vkL8EP8nxwzHw9vKZu+rTNLJs8j+JMndLVWTl8pWq4pAAWaJHt5SgWYd2nGB1FXy8sQLhKDwD62YWWEeILGn/RWahLYp1qkOHbku/1TTNKHDxhFkSB9TBMjcVHYqa4WFg3T2B+Xdn7f9hleCduZAx2mksmUqYpcJVZ2o8u4UwS53KEJfTrgiZ7ceWTbbkh1YDY1Mn7LLM8W8RntuRIEOWxkl+967riRHOe1SeJDx/fVwopMa7LV1qGYoenypK00MxOuOoYjZNdOkuJ7imKx4BdAhfw25LGLTvtVOjTqx20fK5QEaVvsPQMk/J0bLKn9Frlj3bj9hrARj6MQaQDy3R8GPK2Epu/awnUdHVFohfPFgvevR6PE4grth2lLpRV1iZ9apa1YY9hHglW1Vto01acnTdkUi1jUI6bZf+Yysv5XnbfvS0KhoAAAAASUVORK5CYII=');
}

.feefo-percentage > div {
	height:16px;
	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAQCAMAAAC2lwjzAAAAJFBMVEUAAAD93wX93wX93wX93wX93wX93wX93wX93wX93wX93wX93wUfG+E4AAAADHRSTlMAw7EMLZJ4SVve9P8upb9vAAABC0lEQVQ4y7XT227DIAyA4R9s1rTv/6ydijnsAmghqdqt0rhJvshxDHagLRGW9bH9vyW0XYC9TmB76whsFw1a6vx+CDu71WdXy5zwMuxHoU6XgiDMDkf72Sf3yNQqBpsrNojzVm9wm7cUR3y3Pbxl7xwXCMk7hw9lta4+1frSm5N6nkqPBf/1B3+7HFZrJt8bVrNBlp29uPHg4AK2WiDV2A78Wg2OzneX+N4ClK21pqT2nWHXz7mcntvHbtWHfe/ZPOTkHjhcnjuz/h1x3MsG1+t9ZECb9beW5k36GIkSM8gYdg0fmtwqLDUZWMaNHa12ZANLB5fV1VqFoql312dYTAXEp97NvYUKoLN/AHmxwMyCHcygAAAAAElFTkSuQmCC);
}

.feefo-percentage > div:first-child {
	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAQCAMAAAC2lwjzAAAAHlBMVEUAAADMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMwLbf+mAAAACnRSTlMAvAstfplLYd3/31pszwAAAPdJREFUOMul09GugyAQRdE9DPb6/19LHBn6ACpgrmlaX8gy5IAHhPqEwPB87XNcfgtc5sC4jRNinhxH58lbHANV1mHJcLOMXkWHwNNtmsCw5ALLk+M0/wUyBGawvpsNtifb4RZQoHUkfxvACiSAoPboJfujXxK03/ue+clJont3A7LBzV39s312KQLoUgtNofagvn7lYhkUKFoDvfVaXnWPsn9o1RZ4HJKfd4fjzLrhbp8s3esABIWUupvVrP853l0SxNACRbBSdo529e79bhucitUdBcDJO5hfl705nDawfNkN9nz9Zs1WPz+E0k6rttzZ/QMTe78BYwWeB9fsKxAAAAAASUVORK5CYII=);
}

Put all that in your IE8 CSS file and you should be done.