Heatmaps – Click tracking tutorial

click_trackingAs you can tell by the title, this tutorial is going to be how to implement click tracking and display them on an overlay to your website.

I recently launched a new website (CheckAttacks.com) and wanted to implement this to do further browsing habit analysis, for example if a user always clicks a certain link after a picture I could tailor that link to direct them better.

The example to the left of here is what the finished result should look like. Click for a bigger picture.

For this it is expected that you have an understanding of the technologies already, those being PHP, MySQL and JavaScript (jQuery)

This article will be in 2 sections, section 1 is how to implement logging the clicks and section 2 will be how to implement the heatmap using the previous data. So without further ado.

Section 1: Logging clicks

first things first you will need to do some obvious things. Include jQuery (you should know how to do this) then use the following javascript:

$(document).ready(function() {
	$(document).click(function(e){
      log_click(window.location.href.toString().split(window.location.host)[1], e.pageX, e.pageY);
   });
	var canvas = document.getElementsByTagName('canvas')[0];
	canvas.style.display = "none";   
});

function log_click(page, x, y){ // log clicks for heatmap
	$.post("/log_click.php", {
		page: page, 
		x_coord : x,
		y_coord: y
	}, function(data){
		if (data == 1){ 
			console.log("Click logged: " + x + ", " + y);

	} else{
      console.log("Error - click not logged " + x + ", " + y);
   }
  }) 
}

Ignore the canvas changes, that will be useful for later on!
That will try to send (via a post request) the current page, x-coordinate and y-coordinate to /log_click.php
Before we create log_click.php lets create the database table “clicks” to store the results. The structure should be:
timestamp datetime
page varchar(200)
x int(255)
y int(255)

Now on to log_click.php

<?php
include('../config.php');

if(isset($_POST['x_coord']) && isset($_POST['y_coord'])){
	$page = htmlentities($_POST['page']);
	if($page == "/"){ $page = "/index.php"; }
	$xcoord = htmlentities($_POST['x_coord']);
	$ycoord = htmlentities($_POST['y_coord']);
	$time = date( 'Y-m-d H:i:s');

	 $conn = mysql_connect('localhost', $dbuser, $dbpass);
		mysql_select_db($dbname, $conn);

		$page = mysql_real_escape_string($page);
		$xcoord = mysql_real_escape_string($xcoord);
		$ycoord = mysql_real_escape_string($ycoord);

		mysql_query("INSERT INTO clicks (timestamp, page, x, y) VALUES ('$time', '$page', $xcoord, $ycoord)");

	mysql_close($conn);
	echo "1";
}else{
	echo "0"; // error not all values set
}
?>

Config.php should contain the variables needed to access the database. And that should be all… click around your page and refresh the database to see it fill up with locations. That’s all well and good, but it would be better if we had a meaningful way to display this data.

Section 2: Heatmaps

For this we will use a jQuery plugin called “High Performance JS heatmaps” a copy can be downloaded from the github repository.
Once that is downloaded include it in the usual way.
You will need to add “<canvas><canvas>” just after the opening body tag. This is where the heatmap will be generated. The code in the previous js was to hide the canvas so you can still use the website (the overlay obviously stops allowing you to click freely)

You might want to use the following CSS code if the canvas tag isn’t behaving properly:

canvas{
	width: 100%;
	height: 100%;
	margin: 0;
	padding: 0;
	font-family: sans-serif;
	color: black;
	overflow: visable;
	position: absolute;
    top: 0;
    left: 0;
}

Now were going to need a way to display the heatmap… this can be however you like, the jist of it is to call the function showcanvas(<var>); Where var will be replaced with a number between 1&4 (daily, weekly, monthly, yearly) for example:

<a onclick="showcanvas(1);">[daily]</a>
<a onclick="showcanvas(2);">[weekly]</a>
<a onclick="showcanvas(3);">[monthly]</a>
<a onclick="showcanvas(4);">[yearly]</a>

The JavaScript to make the canvas work and update is:

var visable = false;
var visable2 = false;
var timescale = "day";
var page = window.location.href.toString().split(window.location.host)[1];

function showcanvas(scale){
	var canvas = document.getElementsByTagName('canvas')[0];
	canvas.style.display = "";
	visable = !visable;
	visable2 = !visable2;
	if(scale == 1){var timescale = "day";}
	if(scale == 2){var timescale = "week";}
	if(scale == 3){var timescale = "month";}
	if(scale == 4){var timescale = "year";}
	console.log("Timescale changed to: "+timescale);
	 $('html, body').animate({ scrollTop: 0 }, 0); 
}

window.onload = function(){		
	var canvas = document.getElementsByTagName('canvas')[0];
	canvas.style.display = "none";
	var heatmap = createWebGLHeatmap({canvas: canvas});
	document.body.appendChild(heatmap.canvas);

	canvas.onclick = function(){ // hide the canvas and stop it updating in the background
		heatmap.clear();
		canvas.style.display = "none";
		visable = !visable;
		visable2 = !visable2;
		 $('html, body').animate({ scrollTop: 0 }, 0);
	}
	var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame;
	var update = function(){

		var size = 20;
		var intensity = 50;
		var decay = 0;

		var postData = "timescale="+timescale+"&page="+page;
		if(visable2){
			$.ajax({
				type: "POST",
				dataType: "json",
				data: postData,
				beforeSend: function(x) {
				if(x && x.overrideMimeType) {
					x.overrideMimeType("application/json;charset=UTF-8");
				}
			}, url: '/heatmap.php',
				success: function(data) {
					if (data.amount > 0){
						for (i=0; i<data.amount; i++){
							heatmap.addPoint(data[i].x , data[i].y , size, intensity/1000);  
						}
					}
				}
			});
		}

		heatmap.adjustSize(); // can be commented out for statically sized heatmaps, resize clears the map
        heatmap.update(); // adds the buffered points
        heatmap.display(); // adds the buffered points
        heatmap.multiply(1-decay/(100*100));
        heatmap.blur();
        //heatmap.clamp(0.0, 1.0); // depending on usecase you might want to clamp it
		raf(update);	
    }
    raf(update);
}

Now this may look confusing, but it’s actually quite simple. Firstly is sets starting variables. The function showcanvas(scale) is what the links reference, it just makes the canvas visible, sets the timescale and scrolls the page to the top.

Then there is some more setting up after the windows.onload.
After that is the canvas.onclick = function() – This clears and hides the heatmap, stops it from updating in the background, and scrolls to the top of the page again. (link shows canvas which overlays entire website, click anywhere to resume normal browsing)

The var update = function() is the main section of it. you will need to tailor the 3 variables size, intensity & decay to suit your own needs.
The section inside if(visable2) is an ajax request similar to the previous one. Except this time it is POST’ing the timescale (daily, weekly etc.) and the current page to heatmap.php.

heatmap.php returns JSON encoded data that is then interpreted and displayed on the canvas. I guess on that note, the last and final bit of code, heatmap.php:

<?php
include('../config.php');

if(isset($_POST['timescale']) && isset($_POST['page'])){

	$data = array();
	$page = htmlentities($_POST['page']);
	if($page == "/"){ $page = "/index.php"; }
	$mysqldatebefore = date( 'Y-m-d H:i:s', strtotime("-1 ".$_POST['timescale']) );

	  $con2 = mysql_connect('localhost', $dbuser, $dbpass);
              mysql_select_db($dbname, $con2);

	$result = mysql_query("SELECT x, y FROM `clicks` WHERE `timestamp` > '$mysqldatebefore' && page = '$page'");
			$i = 0;
			 while($row = mysql_fetch_array($result)){
				$data[$i] = array();
				$data[$i]['x'] = $row['x'];
				$data[$i]['y'] = $row['y']; 
				$i++;
			 }

			$data['amount'] = $i;
			mysql_close($con2);
echo json_encode($data);
}

?>

That’s it, you should have fully functioning click logging to a database, and heatmap display for various timescales. This script is also quick enough to display data in real-time… and the views are in fact updated so.

As always, likes, comments & shares are always appreciated. I hope this article has helped you, if you have any improvements or suggestions I would love to hear them.

4 thoughts on “Heatmaps – Click tracking tutorial

  1. Cool tutorial but have you solved the issue of tracking a tags? What I have noticed is that an a tag will cancel all ajax requests and you will not have a chance to save the click information when it is set to redirect you to another page (AKA Default anchor tag behavior)

  2. I’ve tried to integrate this in my project but I recive a white page… the PHP part works well (recording clicks/generationg json response) But I can’t add the heatmap…. Do you got any advices for me please?

  3. Pingback: How to implement Heatmap on Websites using PHP, MySQL, jQuery and Ajax? | Technoserene

Leave a Reply