Grow your CSS skills. Land your dream job.

Tracking Clicks, Building a Clickmap with PHP and jQuery

Published by Chris Coyier

This demo and article was originally created by Jay Salvat and can be seen here in French. Thanks Jay!

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.

View DemoDownload Files

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="http://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).

View DemoDownload Files

Comments

  1. Chris Gedrim
    Permalink to comment#

    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!

    • trice22
      Permalink to comment#

      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

    • Permalink to comment#

      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.

    • Chris Gedrim
      Permalink to comment#

      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…

    • those newbies
      Permalink to comment#

      Ever heard of Google Analytics?

  2. Les Adams
    Permalink to comment#

    Clever, very clever, Thanks Chris!

  3. Sven
    Permalink to comment#

    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

  4. Les Adams
    Permalink to comment#

    And thanks Jay, my apologies!

  5. Permalink to comment#

    Thanks a lit for this tut, it’s gr8, just like everything else at CSS Tricks:)

  6. Permalink to comment#

    Very useful as always. Neat little feature…

  7. Wonderful stuff!

  8. 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.

  9. JMS
    Permalink to comment#

    Very cool… I’ll definitely try this out next time I have a chance.

  10. Permalink to comment#

    Interesting, a bit like CrazyEgg

    The only problem is that it relies on event propagation.

  11. Nice! I will give it a shot next time I am doing some usability testing.

  12. Permalink to comment#

    Fantastic walk through on how to map user activity on page. You weren’t kidding when you mentioned a good tutorial yesterday via Twitter.

  13. Permalink to comment#

    Run Yasmine Run! This is really cool Chris!

  14. 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.

  15. Permalink to comment#

    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 :)

  16. Cool, but…
    LabsMedia ClickHeat is better :)

  17. Permalink to comment#

    Not bad. Too bad I don’t use jQuery…

  18. Permalink to comment#

    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.

  19. 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.

  20. Tadaaaa this is the point where you create the SQL Injection flaw and I get paid for finding it ;-)

    Thanks!

  21. Permalink to comment#

    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.

  22. Permalink to comment#

    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.

  23. Jerry Ford
    Permalink to comment#

    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.

  24. Sandy
    Permalink to comment#

    This is just Superb!!! Great work.

  25. Permalink to comment#

    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 ?

    • Poulsen
      Permalink to comment#

      Have you found a solution? I have the same problem with accuracy, but can’t figure out how to solve it.

  26. Andy
    Permalink to comment#

    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.

    $.post(‘/examples/ClickMap/clickmap.php’,
    {
    x:evt.pageX,
    y:evt.pageY,
    l:escape(document.location.pathname)
    });

    Does anyone know of a tutorial like that?
    Thanks in advance

    • Permalink to comment#

      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.

  27. Andy
    Permalink to comment#

    Sorry bothering you again, but I found a tutorial which helps me out.

  28. alex13
    Permalink to comment#

    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?

  29. 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/

  30. sharayu
    Permalink to comment#

    i want to know where is that id “#demo” that you mentioned in hyperlink tag?

  31. Permalink to comment#

    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!

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".