Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use favicon to track user visit to a website

I read in this answer to "How website can track users even after clearing browser cookies" that a user can be tracked via the website favicon:

Favicons are a third possibility--which most browsers request before the page is loaded, so if that request is satisfied, then the client is obviously a repeat visitor.

If this is actually possible it can be a good way of checking if the user visited the website before, don't needing to use cookies for that porpouse.

I'm not really sure if this is something that I can accomplish with PHP or Javascript (jQuery). How can this be achieved?

EDIT:

What I interpreted with this is that the user makes a call if he needs the Favicon. If he does not make that call it means he already has the favicon so he visited. So there is no need to store any file (cookie for example) in the user computer or keep its IP in the server. Is this correct?

like image 954
Alvaro Avatar asked May 30 '13 05:05

Alvaro


2 Answers

There are two things you need to do. First you need to redirect the favicon request to a script. You can do this in two ways. The first would be to add something like the following to your .htaccess file

RewriteEngine on
RewriteRule ^/favicon.ico   /favicon.php  [L]

or you could send another favicon location in the html code. However, I would not use this to directly redirect to the php script as some browsers have issues using the favicon correctly if its not realy a .ico or .png file. Perhaps you can use it to redirect to an alternative favicon.ico location and use it combined with the .htaccess. I used one icon location for all settings, which isnt realy needed. But this way you know how you can alter it.

<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="32x32">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" sizes="32x32">

Since you are redirecting to a PHP script, you can use the code below to handle the actual request.

<?php
//the location of the actual favicon
$favicon = '/favicon.ico';
$protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0';

//try to get the file info, to be able to get the correct content type
//if it doesnt work, return 404 error
$size = @getimagesize($favicon);
if (!$size) {
  header($protocol . ' 404 Not Found');
  exit();
}

// Content type
header('Content-type: ' . $size[2]);

//when is the icon last modified
//Keep in mind that if you modify the icon, all returning visitors will be handled as new visitors
$last_modified_time = @filemtime($favicon);

header("Accept-Ranges:  bytes");
//set a long max-age with a recheck marker, so people check if the icon is still the same and thus access this script.
header("Cache-Control: max-age=15724800, public, must-revalidate");
header("Vary: Accept-Encoding");
//some say the Etag is bad, some say it isnt. You can remove this part if you dont want to use it.
header("Etag: " . md5($favicon . $last_modified_time));


// exit if not modified
if (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) {
  if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) { 
      header($protocol .' 304 Not Modified'); 

      /*
      At this point you have a returning visitor.           
      */
      DoSomethingWithReturningVisitor();

      exit();
  }
}

// exit if not modified using Etag, remove it if you dont want to use it.
if (array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER)) {
  if ($_SERVER['HTTP_IF_NONE_MATCH'] == md5($favicon . $last_modified_time)) { 
      header($protocol.' 304 Not Modified'); 


      /*
      At this point you have a returning visitor.           
      */
      DoSomethingWithReturningVisitor();


      exit();
  }
}

//you are sending a new image to the user. Add the last modified time.
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");


//log that he is a new visitor
//If you dont to this, the user will be marked as returning visitor when he visits the 2nd page of your website
$_SESSION['newVisitor'] = true;

//return the content of the actual image
echo file_get_contents($favicon);


//A single point to handle returning visitors
//make sure you dont have any output in this function, because you are still returning a valid favicon. If you have any output the returned icon will be corrupted.

function DoSomethingWithReturningVisitor() {
  if (!empty($_SESSION['newVisitor']) && $_SESSION['newVisitor'] === true) {
    //already marked as new visitor, so skip for this session
    return;
  }

  //do something to give this user special treatment
  $_SESSION['returningVisitor'] = true;
}
?>

Now on the first request to your webpage, this will be hard to track. Because the request to your homepage will be made first and then afterwards it will try to load the favicon.ico. So the information for new/returning visitor is not directly available in php. The best way to check if its a returning visitor at the top of the homepage would be something like

<?php
if (empty($_SESSION['returningVisitor']) && empty($_SESSION['newVisitor'])) {
   //unknown if user is new or not
} else if (!empty($_SESSION['returningVisitor']) && $_SESSION['returningVisitor']===true) {
   //returning visitor
} else {
   //new visitor
}
?>

If you realy need to know it on the homepage (Or any other page the user request as the first page for this session), you best option would be to make an ajax call when the document is loaded, perhaps even with a short timeout because the favicon.ico request isnt always part of the body.

like image 193
Hugo Delsing Avatar answered Oct 04 '22 13:10

Hugo Delsing


To get information on favicon requests in Apache, edit your .htaccess file to reroute the favicon requests to a script of your choice. You would then need to log request IP addresses or use cookies to determine if a site visitor has just requested a favicon or not.

EDIT
Remember to return the favicon after handling the request.

like image 21
Fallexe Avatar answered Oct 04 '22 12:10

Fallexe