The Plan
- Record the X and Y coordinates of the mouse cursor when it is clicked on a web page.
- Save those coordinates to a database
- When called, display a “clickmap” on top of the web page visually displaying the locations of those clicks.
Why?
Because it’s a cool proof of concept. Should you use this in production and base major design decisions off it? Maybe not, but I could see it being used as a tool in examining user behavior in some situations.
The Technologies
The website will be built using PHP. We need PHP for a couple of reasons. Most importantly we need a server side language to deal with saving and retrieving from the database. Also, we’ll be abstracting that database interaction into a separate file to keep our code clean. PHP enables us to post variables back and forth between these files.
We’ll be using JavaScript of the jQuery variety to track the mouse clicks and post that click data to the PHP file doing the database saving. jQuery will also help us display the overlay and place the little graphics we’ll use to display the click locations.
Build the Database
Our code won’t be automatically creating the tables necessary for you, you’ll have to create a database and the structure on your own. Here is the SQL:
CREATE TABLE `clickmap` (
`id` int(10) unsigned NOT NULL auto_increment,
`x` smallint(4) unsigned NOT NULL,
`y` smallint(4) unsigned NOT NULL,
`location` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `location` (`location`)
)
We are keeping things as simple as we can for the demo. If you wanted to extend the idea, you may also want to add extra info to this table like IP address and date/time so you have more detailed info for each click.
The Markup (page being tracked)
Just some structure for us to work with here. We’ll link to a CSS file, load up jQuery, link to a JavaScript file of our own devising as well as set up a place to write JavaScript right here, and put some content in the page.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Click Map Demo</title>
<link rel="stylesheet" type="text/css" href="style.css" />
<script src="//www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript" src="js/jquery.js">
<script type="text/javascript" src="js/clickmap.js"></script>
<script type="text/javascript">
$(function() {
// do stuff
});
</script>
</head>
<body>
<img src="images/baywatch.jpg" alt="baywatch" />
<p class="button displayClicks"><a href="#demo">Display Click Map</a></p>
</body>
</html>
Not much content there, just a picture of the Baywatch crew and a simple button.
The jQuery JavaScript
The JavaScript is going to do two major things for us: saving clicks and displaying clicks.
Saving Clicks
For efficiencies sake, we’ll abstract into a couple of different functions that we can call anytime. One to start saving clicks and one to stop saving clicks.
(function($) {
$.fn.saveClicks = function() {
$(this).bind('mousedown.clickmap', function(evt) {
$.post('/examples/ClickMap/clickmap.php', {
x:evt.pageX,
y:evt.pageY,
l:escape(document.location.pathname)
});
});
};
$.fn.stopSaveClicks = function() {
$(this).unbind('mousedown.clickmap');
};
})(jQuery);
We are binding the mousedown event to the element it gets called on (it will be the whole document) and then using jQuery’s post function to send some data (the coordinates) to a special file (clickmap.php). Pretty neat really, the people will never know it, but each of those clicks is sending data back to the server.
Displaying Clicks
Again, two functions. One is in charge of creating the overlay and displaying the click graphics (the PHP sends all the data but the jQuery does the appending). The other removes everything. We make use of the jQuery get function.
$.displayClicks = function(settings) {
$('<div id="clickmap-overlay"></div>').appendTo('body');
$('<div id="clickmap-loading"></div>').appendTo('body');
$.get('/examples/ClickMap/clickmap.php', { l:escape( document.location.pathname) },
function(htmlContentFromServer) {
$(htmlContentFromServer).appendTo('body');
$('#clickmap-loading').remove();
}
);
};
$.removeClicks = function() {
$('#clickmap-overlay').remove();
$('#clickmap-container').remove();
};
Firing it all off
We’ll include some JavaScript right on the page to fire everything off.
<script type="text/javascript">
$(function() {
$(document).saveClicks();
$('.displayClicks').click(function() {
$.displayClicks();
$('#clickmap-overlay').click(function() {
$.removeClicks();
$(document).saveClicks();
});
$(document).stopSaveClicks();
return false;
});
});
</script>
The PHP
So now we’ve seen code that boths POSTS and GETS from a PHP file that we haven’t seen yet. That magic happens in a file we’ll call clickmap.php. In either case, we need to connect to the database and then close that connection. The rest of it is defendant on if we are POSTing or GETting.
<?php
$DB = mysql_connect("localhost", "db_user", "db_password");
mysql_select_db("db_name", $DB);
if (isset($_POST['l'])) {
$query = sprintf(" INSERT INTO clickmap
SET x = '%s', y = '%s', location = '%s'",
$_POST['x'], $_POST['y'], $_POST['l']);
$result = mysql_query($query);
};
if (isset($_GET['l'])) {
$query = sprintf(" SELECT x, y FROM clickmap
WHERE location = '%s'
ORDER BY id DESC
limit 200",
$_GET['l']);
$results = mysql_query($query);
$html = '<div id="clickmap-container">';
while ($row = mysql_fetch_array($results)) {
$html .= sprintf('<div style="left:%spx;top:%spx"></div>', $row['x'] - 10, $row['y'] - 10);
}
$html .= '</div>';
echo $html;
};
mysql_close($DB);
?>
Fairly straightforward… when POSTing, save the data to the database. When GETting, retrieve it. In this demo we only grab the last 200 clicks, but you can alter or remove that restriction as needed. Here you can see how the each of the click graphics positions itself when the overlay comes up. The exact coordinate data that was saved when the click was produced is used to set CSS “top” and “left” values.
The CSS
The actual clickmap stuff doesn’t need a heck of a lot in terms of styling. Just the overlay itself, a loading area (in case it takes a while to get all the click data), and the little graphics for the clicks themselves.
#clickmap-overlay {
position:fixed;
top:0; left:0;
width:100%; height:100%;
background-color:#000;
filter:alpha(opacity=70); opacity: 0.7;
}
#clickmap-loading {
position:fixed;
top:0; left:0;
width:100%; height:100%;
background:transparent url(images/loading.gif) no-repeat center center;
}
#clickmap-container div {
position:absolute;
width:20px; height:20px;
background:transparent url(images/click.png) no-repeat center center;
}
All Together
I know sometimes reading through all the code samples can be kind of mind bending and confusing. As always, you are welcome to download the code and see it all in context so it makes more sense. Special thanks again to Jay Salvat for the original creation of this idea. Jay is a 35 year old web developer living in the French Rivera and the lead developer at Kuantic. He is the creator of the very cool markItUp! rich text editor for jQuery and the new project Sunday Morning (coming soon).
That’s a nice little bit of scripting, even if you applied it to something other than a Click-Map. I could see it being implemented on an e-commerce site to track which page an item is selling best on (i.e. does the ‘Today’s Hot Deals!’ page of a site attact more attention to a product or not?)
Cheers Chris & Jay!
For your case you wouldn’t need the mouse coordinates and could simply use the product ID as identifier.
Chris’ example on the other hand makes explicitly use of the cursor position in relation to the viewport but doesn’t mind so much what the screen is currently displaying (products details, Baywatch imagery,…)
—trice
I see what you’re saying and understant ‘those newbies’ comment about google analytics. But to expand on trice22’s thought, maybe you could set it up to see if a particular product sells more in the first position of the gallery or maybe when on the right side of the gallery.
Firstly, yes I have heard of Google Analytics.
Secondly, I knew exactly what I meant in my head, it just didn’t transfer to comment that well!
I was thinking of the methods large supermarkets use to sell you more stuff; they move the product’s position around the store and track how many units are sold in each location. The process is then repeated with products of a different type (ambient first, then electrical, then frozen etc).
This gives them an ideal selling layout for the store, with high-sale hot-spots for certain product types.
Hope that’s kinda clearer…
Ever heard of Google Analytics?
Clever, very clever, Thanks Chris!
I once tested a hit counter that utilised this feature to track clicks on the page itself. It would create an overlay with the “heatmap” that showed where visitors clicked the most on each page. Pretty neat idea as it shows where the main area of interest across the site.
The above could easily be modified to use colours for different click frequencies I imagine
And thanks Jay, my apologies!
Thanks a lit for this tut, it’s gr8, just like everything else at CSS Tricks:)
Thanks a lot*, I meant, sorry for the typo
Very useful as always. Neat little feature…
Wonderful stuff!
You can make a plugin out of this, and track where, and when users click each element of your site. This could be a very powerful tool of marketing, and development.
Who knows where users decide to click expecting something in return, but no, that’s just a simple image, not a fancy button.
Very cool… I’ll definitely try this out next time I have a chance.
Interesting, a bit like CrazyEgg…
The only problem is that it relies on event propagation.
I don’t understand…is that a problem?
Nice! I will give it a shot next time I am doing some usability testing.
Fantastic walk through on how to map user activity on page. You weren’t kidding when you mentioned a good tutorial yesterday via Twitter.
Run Yasmine Run! This is really cool Chris!
Thanks so much for this — it’s great. It seems like it uses similar principles to Google Analytics’ site overlay feature, though that is responding directly to clickable links, and this may not be. It’s very helpful from a UI design standpoint, and marketing standpoint, to know where people are clicking and what’s working.
A must have to for tracking the good zones of your website !
Thanks a lot Jay, I’ve just modifying CSS with big z-index and add mysql_escape_string in sql request (sql injection).
The script is in use on my website, i’ll see tomorrow the results :)
Cool, but…
LabsMedia ClickHeat is better :)
Not bad. Too bad I don’t use jQuery…
It is a very nice script and the information that can be attained from the results would definitely help in determining the best positioning of items.
Overall this will give you a cleaner process on what directions to take. Usually it is a hit and miss and test and test process to determine the best areas for visitor interaction.
A plugin form of this script would be great.
I am considering converting my site PHP-Learn-It into wordpress and would love the ease of the plugin.
I’ve actually already built something very similar to this, and was planning on building a module for CMS Made Simple – then I hit an issue.
How do you account for variable-width sites? Center-aligned is doable, as you can find the position of the encapsulating element, and account for it in the JS – but with variable width… I suppose you could store the information in percentages from the left, instead of pixel values?
/me hurries off to try this.
Tadaaaa this is the point where you create the SQL Injection flaw and I get paid for finding it ;-)
Thanks!
Nice write up — I’d add that you might need to record font size, screen size, browser details of the user if you are only capturing x y coordinates, because if you are overlaying, you might be viewing in a different configuration to your users. (I think OS differences such as dpi etc could also have an effect.) Good idea though.
recording every single mouse click into the database is going to exert huge performance impact on the db server, not really practical to major applications. But still very nice script though.
This is a fantastic concept. I wonder how useful it i so the average webmaster? As a newbie to php, I find I work best with cheat sheets. Since I always have my iPhone with me, I keep them there. The best one I’ve found so far is from these guys:
http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=302760278&mt=8
They also have great cheat sheets for jQuery and Javascript. Hope this is helpful.
This is just Superb!!! Great work.
Great tutorial. I am porting some of this to a wordpress plugin. I ran into a problem. Most websites are aligned in the middle. In that case the x coordinate from the left is not accurate because of the middle of the screen and screensize.
I made some changes. Now the screensize is reported to the database, but I am stuck with the calculation, on where to put the dots accurately. Someone got some advise ?
Have you found a solution? I have the same problem with accuracy, but can’t figure out how to solve it.
Great tutorial! Thanks.
Since I’m quite new to jQuery and JavaScript in general I just wanted to know if someone could point me to a tutorial where I learn how to change the saved values. I want to save also a time stamp and some other data of the site hidden in some input tags next to x and y.
Does anyone know of a tutorial like that?
Thanks in advance
Hi Andy,
Just add some properties to the ajax query :
$.post(’/examples/ClickMap/clickmap.php’,
{
x:evt.pageX,
y:evt.pageY,
someExtraInfoHere:$(‘#myHiddenInput’).val(),
l:escape(document.location.pathname)
});
For the timestamp, just add a ‘myDateField = NOW()’ to the mysql Insert query. Of course, fields must be added to the mysql table too.
Sorry bothering you again, but I found a tutorial which helps me out.
This clickmap is awesome, but I can’t seem to get it to work on my server. When I click on “display click map” the spinner spins forever! I have created the mysql database and table and its still not working. Could anyone know how to fix this problem?
Hi Alex,
Don’t forget to modify the /examples/ClickMap/ path in the .js file ? :)
Jay
Hi there!
For those who are interested in the initial idea of this article, I just add the project on Github project with many enhancements.
http://github.com/jaysalvat/clicktracker/
i want to know where is that id “#demo” that you mentioned in hyperlink tag?
This is AWESOME! It is just what I was looking for. I’m curious though if there is a way to show all user’s mouse locations as well as user’s click events in the database? Any suggestions? Ideas? Thanks!