How a Tracking Pixel Works

An explanation of how a tracking pixel works, with some sample PHP code that implements a simple event tracking pixel.

Tracking pixels are a way to track if a user has viewed a specific page. Typically, multiple pixels are used, with pixels placed in different pages within the “sales funnel”, and a final pixel on the page displayed when the user completes a transaction. They are also used to track if a specific user went from one site to the sales funnel.

A tracking pixel sets a cookie to track the movement of a user. Cookies are sent back to the server that set it, so they are sent back with the request for the pixel. (If the pixel is on multiple websites, the same cookie is sent back with each pixel requested. The pixel’s domain is the same, even though the pixel is placed on pages in different domains.)

Web browsers are “tricked” into requesting the pixel via an IMAGE tag, like this:

<img src="" />

Normally, these tags request image files, but in this case, it’s requesting the file from the pixel.php script. It also passes the e parameter in, so you can customize your pixel for each page.

Though using tracking pixel software, particularly Google’s, can be intimidating and confusing, the internal operation of a tracking pixel is pretty simple. The script below is for a very rudimentary, tracking pixel. It’s lacking many features of real tracking pixels, and there’s no creation or reporting application. It’s presented strictly to show you what’s happening.

Read the comments for explanations about what’s happening. You can click on the link below the code to see the file by itself.

// Tracking pixel script in php, with explanations.
// Donations:
// Set database to a file your server can access.
$database = "/tmp/tracking.sqlite";

 * PHP sessions set the PHPSESSIONID cookie on the browser, and, using that
 * value, creates a corresponding file on the server, which contains the values
 * accessible in the $_SESSION array.  This file is loaded whenever the session
 * is started.  It's saved at the end of the script.


 * We use a random number to identify a user.

if (! isset($_SESSION['user'])) {
    $_SESSION['user'] = rand(1, 9999999);

 * Pixels have the form <img src="" />
 * The 'e' paramter stands for "event", and whenever the browser loads the
 * graphic, it passes the value of e along with the request.
 * The value of e must be only lowercase letters and numbers.  If it's
 * missing, e will be the empty string.

$e = filter_input( INPUT_GET, 'e', FILTER_VALIDATE_REGEXP, 
        ['default'=>'', 'regexp'=>'/^[a-z0-9]*$/']);

 * We store our data in a sqlite3 file. Not the ideal database for this, 
 * but it's good enough for a demo.
 * SQLite3 presents an object oriented interface. For each database,
 * you create a subclass of SQLite3, and associate it with a database.

class DB extends SQLite3 {
    function __construct() {
        global $database;
        try {
            $this->query('CREATE TABLE events (user NUMERIC, e TEXT)');
        } catch(Exception $e) {
             * This soaks up the expected exception.
            if ('table events already exists' != $e->getMessage()) {
                echo $e;

     * The object oriented style of programming allows you
     * to encapsulate code that alters the database within
     * the class, so you can interact with the database
     * through methods.

    public function insert($user, $e) {
        $stmt = $this->prepare('INSERT INTO events (user, e) VALUES (:user, :e)');
        $stmt->bindValue(':user', $user);
        $stmt->bindValue(':e', $e);

 * We now store the user id and event in the database.
 * In a real tracker, we would save out additional browser information,
 * time, referrer, and other information.

$db = new DB();
$db->insert( $_SESSION['user'], $e );

 * Now, we pretend to be a graphic file that is a 1 pixel GIF.

header('Content-type: image/gif');

 * Instead of creating a graphic file, or reading one from disk, we just embed
 * the file as data, right into the script.


The code:

2 thoughts on “How a Tracking Pixel Works”

  1. I’m using this method and just save results to MySql (instead of SQlite3)

    What if I’m tracking impressions of CTA (call to action) form … Wouldn’t writing to MySQL DB every time a page loads be too much stress on server, if say I get 3000 pageviews / day, and most pages would display a CTA with Tracking Pixel. I’m NOT using GD Library … PS, maybe it’s better to use SQLite3, since it’s a file??

    1. 3,000 inserts a day is not much traffic for a database. If the 3,000 inserts happen across 8 busy hours, that’s less than 7 inserts per minute.

Leave a Reply