FOSS Fridays - Tracking Your Users

The other night I thought it’d be helpful to see how people browse your site. I think you can probably learn a lot about how a user moves over your site. You can tell a lot about your user’s experience by watching their mouse. You can see where they look on the page for specific information. I’ve created a demo of the tracking.

I know that there are some products out there that already do user session tracking and replays. Also there are click heat maps which are interesting when you are looking on your site to see what links the user clicks the most. I decided to just rebuild the session replay just out of curiousity on how difficult it’d be to do. It was fairly simple and took me only 15-20 minutes. There are a number of improvements you could make to the script such as the window.unload handling is not 100% depending on your browser. You could also do much more parsing on the client side of the information by using JSON. If you wanted to store more than one page of tracking data you could quickly modify the script to pass the name page which it was tracking and to store the data separately for each page.

To use the script all you need to do is add a little Javascript on the bottom of the page you want to track a user. The script tracks a users mouse movement as soon as they open the site. It keeps track of time so that during the replay you can get the proper mouse movement at the right times to replay the users session. While the user moves their mouse it continues to store all the data client side. Once the window is closed it sends all the information to the server. The server simply parses the data string. For session replay it is done via setTimeout and it moved an image(of a cursor) at different intervals to simulate the users session.

While the script is not very pretty it was written very quickly and just as a proof of concept. It goes to show you can easily track your user’s session without having to purchase expensive products, and that it can be done fairly simply.

The code is below with descriptions of what each snippet does. The script uses jQuery. To deploy this on numerous pages all you really would need to add would be a script tag that pulls in the tracking javascript.

Tracking the users movements and sending the server the information javascript:

var points='';
var timeSeconds=0;
$(document).ready(function(){
  $('body').append('');
  timer();
   $().mousemove(function (e){
    points=points+e.pageX+","+e.pageY+","+timeSeconds+"|";
  });
  $(window).unload(function(){
    sendData();
  });
});
function timer()
{
  timeSeconds=parseInt(timeSeconds)+1;
  setTimeout("timer()",10);
}
function sendData(){
    $.post('index.php','data='+points);
}

To parse the information on the server:

if($_SERVER['REQUEST_METHOD']=='POST')
{
  $fp=fopen($_SERVER['REMOTE_ADDR'].'tracking.dat','w+');
   fwrite($fp,$_POST['data']);
  fclose($fp);
  exit(1);
}

To replay the session first get the data:

if(file_exists($_SERVER['REMOTE_ADDR'].'tracking.dat'))
{
 $data=explode("|",file_get_contents($_SERVER['REMOTE_ADDR'].'tracking.dat'));
}

The moving of the cursor image javascript:

function moveMouse(x,y){
 $('#cursor').attr('style','position:absolute;left:'+x+"px;top:"+y+"px;");
}

Create different calls for each time the mouse was moved and have them execute at the times the user moved the mouse:

foreach($data as $d)
{
  $parts=explode(',',$d);
  if(count($parts)==3)
  echo 'setTimeout("moveMouse('.$parts[0].','.$parts[1].')",'.($parts[2]*10).");\n";
}

And you are all set. As I said the script is only for proof of concept and not too pretty. Let me know if you have any questions.

Skinning your jQuery UI Components quick and easily - ThemeRoller

We use jQuery on almost every project we do. As many know updating your theme for your website widgets can take a long time. Recently we found the http://jqueryui.com/themeroller">jQuery UI - ThemeRoller. This allows you to quickly skin all of your jQuery UI widgets within a matter of couple of mouse clicks.  For those of us who can’t pick matching colors for their life, ThemeRoller has many template themes. ThemeRoller allows you to start with a templated theme, and to easily modify it via the GUI.

This will save you time and money as hand editing the CSS files to update your jQuery UI widgets is slow and tedicious.

FOSS Fridays: sfSCMIgnoresTaskPlugin version 1.0.3 released - Doctrine Supported

In the past we have always used Propel as our main ORM for our Symfony projects. Recently with Doctrine becoming the default ORM for Symfony 1.3 we decided we should make sure our plugin supports Doctrine. For those who don’t know about the plugin, it automatically creates ignores for your Source Code Management(SCM) if you use Git or CVS. When you have a large project it gets tiring to create all the different ignores for all the bases, logs, configuration files and such.

Let us know if you find any problems with Doctrine support or have any additional suggestions for the plugin.

More information on the plugin can be found on the Symfony Plugins site: http://www.symfony-project.org/plugins/sfSCMIgnoresTaskPlugin

You can download the most recent pear package manually at: http://plugins.symfony-project.org/get/sfSCMIgnoresTaskPlugin/sfSCMIgnoresTaskPlugin-1.0.3.tgz

or you can install it via:

./symfony plugin:install sfSCMIgnoresTaskPlugin

Iterating over Symfony Forms for Custom Output

Recently we were working on a project in which we needed to switch from forms auto-formatting themselves ( <?php echo $form;?>) to allow for much more customization in the output. While there is a Symfony Forms for Designerschapter in the forms documentation, it doesn’t help much for iterating over a form object and customizing the output. There is a simple foreach($form as $field) that will iterate over every field in the form. The problem with this is when you have embedded forms and you want to do something different with the formatting on them. This will iterate over all the fields and you will not know when the field is the embedded form or not. So we came up with the following which works:

<?php
foreach($form as $field)
{
  // If this is true, then that means its an embedded form.  
  if(get_class($field)=='sfFormFieldSchema')
  {
    foreach($field as $f)
    {
      // Don't want to see hidden field labels
      if(!$f->isHidden())
        echo $f->renderLabel()." ";
      echo $f->renderError();
      echo $f->render();
    }
  }
  else
  {
    if(!$field->isHidden())
        echo $field->renderLabel()." ";
    echo $field->renderError();
    echo $field->render();
  }
}

This will work fine for a form with as many as single embedded forms. It allows you to easily use the same view for multiple forms and be able to customize their embedded forms easily. If you have only one form that you will be doing this with, and are worried about performance we recommend then not using a foreach loop and doing it by hand, this will save you on performance as you will not have as many if statements in each iteration.

Loading Different Javascript/CSS Files in Different Environments

Today we were working on minifying our Javascript and CSS files for a site we are launching tomorrow. We came across that we didn’t want to have to get the repository out of sync and update view.yml to only include our single CSS style sheet and one javascript file when working between developement environment and production. What we wanted was the following in view.yml the javascripts: and stylesheets: parameters to change depending on what environment you are loading, however using prod: and dev: in this didn’t work like app.yml does. An example of this would be:

all:
  title: My site
dev:
  stylesheets:[styleone.css,styletwo.css,stylethree.css]
  javascripts:[one.js,two.js,three.js]
prod:
  stylesheets:[style.min.css]
  javascripts:[main.min.js]

This way we could have them load in production much quicker and reduce load time, however still easily debug the files in development environments. After looking around a bit we couldn’t find any standard current solution so we came up with the following. In app.yml we defined two variables for the dev and production environments - javascript_files and css_files. Here you put the list of the files you wanted to loaded in each environment. Then in view.yml it now looks like:

all:
  title: My Title
  stylesheets: [<?php echo sfConfig::get('app_css_files');?>]
  javascripts: [<?php echo sfConfig::get('app_javascript_files');?>]

The configuration variables get their value depending on the environment you are running in so it loads the proper files. With this configuration we can easily debug in development environment and still have minified versions of the CSS and Javascript in production environement. Hopefully this will save some of you time and make your life easier.