Developing a tracking pixel
Asked Answered
S

6

47

I am trying to build a pixel that would track the current URL the user is on when they visit. I can use either JS (preferred) or a 1x1 image pixel. With JS I am assuming that I'd need to run an AJAX request to a PHP script to capture the info that I need and with an image pixel I am having issues getting the currently URL.

I also thought about URL encoding the current URL with JS and dynamically placing the image pixel with the encoded current URL as a query string to a PHP script, but that I can get to be very long.

If I am to go the AJAX route, which AJAX library can I use? JQuery is too bloated for this purpose.

Any other ideas?

Sifuentes answered 26/10, 2012 at 1:37 Comment(9)
You don't need ajax at all as a pixel image generated in PHP would just be included and requested as an image in your HTML.Chalmer
just use the server log, or google analytics.Grenier
@Dagon This is for a custom built app that I need to capture several pieces of info for.Sifuentes
@Chalmer What do you mean? How would I pass post variables into this PHP script/image pixel in that way?Sifuentes
@AlexMarkov such as? I'm having to make a lot of guesses as to what you want to achieve.Grenier
Currently scouring my codebase for an applicable script :)Chalmer
@Dagon I am actually create a 404 tracking script app for a shopping cart. I need this to be a standalone app. This means that I need the pixel to take the current URL that it is on and eventually add it into the database.Sifuentes
the 404 page can get the current url from the $_SERVER varGrenier
@Dagon I can't get this from within the pixel PHP script, because it will only give me the URL of the actual pixel script, not the page the pixel itself is displayed on.Sifuentes
C
74

You can write a script that creates and returns a .gif, .jpeg or .png image using PHP for tracking purposes using the GD library (which is often distributed with PHP in modern versions). If you don't have access to GD, you can always recompile PHP with GD enabled.

Example:

pixel.php (commented for the purposes of explanation):

<?php

  // Create an image, 1x1 pixel in size
  $im=imagecreate(1,1);

  // Set the background colour
  $white=imagecolorallocate($im,255,255,255);

  // Allocate the background colour
  imagesetpixel($im,1,1,$white);

  // Set the image type
  header("content-type:image/jpg");

  // Create a JPEG file from the image
  imagejpeg($im);

  // Free memory associated with the image
  imagedestroy($im);

?>

In a simple example, you can then call this tracking pixel using the following example URL in an email or other page:

<img src="http://example.com/pixel.php?a=value1&b=value2&c=value3">



Using variables:

Within your pixel.php you can then parse and interpret any $_GET variables that are passed to it within the image tag, simplistically:

if (isset($_GET['a'])) {
  // (Do|log) act on a
}
if (isset($_GET['b'])) {
  // (Do|log) act on b
}
if (isset($_GET['c'])) {
  // (Do|log) act on c
}

Apply and repeat as you need, but you can be quite sophisticated about what you do and especially as you have access to quite a lot of information about the user through being able to set vars on the $_GET string.

A more applicable example might be:

<img src="http://example.com/pixel.php?userid=98798&campaign=302&last=8">



Tracking more than just $_GET variables:

You can also pick up much more information using PHP, such as:

// Server variables
$ip = $_SERVER['REMOTE_ADDR'];
$referer = $_SERVER['HTTP_REFERER'];
$useragent = $_SERVER['HTTP_USER_AGENT'];
$browser = get_browser(null, true);
etc...

and then perhaps insert into a tracking table in your database:

$sql = "INSERT INTO campaign_tracking 
        ('when','campaign','last','ip','useragent') 
        VALUES 
        (NOW(),'$campaign','$last','$ip','$useragent')";

This is a(the) basic method used widely for tracking email marketing campaigns and specifically in PHP, but the same method is applicable using other scripting/programming languages and libraries - and for other purposes too.

Further and useful information on GD:

Chalmer answered 26/10, 2012 at 2:5 Comment(9)
But how I do I access the URL that the pixel fire on with this type of implementation? Only way I can think of is to add the document.URL as a query string parameter to the pixel, but my fear is that it would make the pixel URL too long. No?Sifuentes
I can't see calling it via JS would cause you many issues, unless your URL-string was ridiculous in length!? You can call a long $_GET without problems, but it's a subjective issue. It depends what you're doing. @Baba Whilst you have to generate the image on the fly, I've never seen any issues with it @ circa 1m (million) requests per day included in an email!! This is, effectively, how email tracking systems work.Chalmer
Understood. It seems like I may need to just go with $_SERVER['HTTP_REFERER'] ... Really appreciate your help!Sifuentes
@AlexMarkov Exactly! Let us know how you get on.Chalmer
This generates a new image every time. Bad Bad Bad! Very expensive. You should load an existing image and render it.Forbidding
@AlexV It would be more expensive at scale, but for smaller implementations it's not really an issue at all... I'll update my answer with a version including an existing image too. The non-blocking answer from thaddeusmt is great, but quite hardcore for the less experienced. My post wasn't just about the method but what could be accomplished with a tracking pixel.Chalmer
I'm getting a 500 internal server error when I try and insert the ip data into the database. Anyone else get that problem?Chu
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. I'm using method from riceball.com/tracking-pixel-works and just save results to MySql (instead of SQlite3) ... PS, maybe it's better to use SQLite3, since it's a file??Hunkers
@Levchik, No. 3K writes per day is nothing in terms of DB stress/inserts even on small DB instances. I've seen this work well in the past with more than 3m+ writes per 24hrs. It really depends on what you're writing to the DB to be honest.Chalmer
T
57

Here is another PHP implementation of a tracking pixel, from the Open Web Analytics project, which attempts to basically be a PHP clone of Google Analytics.

It returns a 1x1 transparent GIF image (without using a PHP image library!), with a no-cache header (important for accurate tracking), and flushes the output so you can continue processing the analytics without blocking the HTTP response (performance). It seems like a pretty advanced implementation, worth trying out.

<?php
ignore_user_abort(true);

// turn off gzip compression
if ( function_exists( 'apache_setenv' ) ) {
  apache_setenv( 'no-gzip', 1 );
}

ini_set('zlib.output_compression', 0);

// turn on output buffering if necessary
if (ob_get_level() == 0) {
  ob_start();
}

// removing any content encoding like gzip etc.
header('Content-encoding: none', true);

//check to ses if request is a POST
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  // the GIF should not be POSTed to, so do nothing...
  echo ' ';
} else {
  // return 1x1 pixel transparent gif
  header("Content-type: image/gif");
  // needed to avoid cache time on browser side
  header("Content-Length: 42");
  header("Cache-Control: private, no-cache, no-cache=Set-Cookie, proxy-revalidate");
  header("Expires: Wed, 11 Jan 2000 12:59:00 GMT");
  header("Last-Modified: Wed, 11 Jan 2006 12:59:00 GMT");
  header("Pragma: no-cache");

  echo sprintf('%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%',71,73,70,56,57,97,1,0,1,0,128,255,0,192,192,192,0,0,0,33,249,4,1,0,0,0,0,44,0,0,0,0,1,0,1,0,0,2,2,68,1,0,59);    
}

// flush all output buffers. No reason to make the user wait for OWA.
ob_flush();
flush();
ob_end_flush();

// DO ANALYTICS TRACKING HERE
Tauten answered 17/9, 2013 at 14:11 Comment(4)
This doesnt work for me... outputs a broken image :(Thermionics
echo base64_decode('R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEA') also works instead of the sprintf, bit shorter.Xenogamy
@nights, make sure there's no whitespace before the opening <?php tag!Wage
@Wage yes, but still the same. i should mention that this only happens on apache/windowsThermionics
D
13

Output 1px x 1px this way:

header('Content-type: image/png');
echo gzinflate(base64_decode('6wzwc+flkuJiYGDg9fRwCQLSjCDMwQQkJ5QH3wNSbCVBfsEMYJC3jH0ikOLxdHEMqZiTnJCQAOSxMDB+E7cIBcl7uvq5rHNKaAIA'));
Danzig answered 25/8, 2014 at 11:13 Comment(1)
Works in 2019 on chrome 👍Squeak
S
4

Here's an extremely simplified tracking pixel written in PHP.

How a Tracking Pixel Works

A tracking pixel is like the most primitive beacon possible, and it operates by exploiting a fact of web pages: images are a separate request from the page.

If you are already able to run your JS code on someone else's page, you should just POST the data back to your server. No need to display a tiny pixel that will only get the same kind of data.

Schnapps answered 26/2, 2018 at 12:21 Comment(0)
C
0

It is a similar problem with this effect, since a call to a function to execute a mark of when the email was seen or opened was introduced in the alt of the pixel, but it does not throw the action correctly.

<img src="https://datafeeds.baruwa.com/1x1spacer.gif" width="1" height="1" alt="Web Bug from https://devorpenguin.des1.net/module/cartabandonmentpro/FrontCartAbandonment?token_cart=87c83b8f77318a54fdd6be91aacc3574&amp;id_cart=1002&amp;action=visualize&amp;wichRemind=1">

public static function visualize()
{

    $wichRemind = Tools::getValue('wichRemind');
    $id_cart = Tools::getValue('id_cart');
    $token = Tools::getValue('token_cart');

    if ($token == md5(_COOKIE_KEY_.'recover_cart_'.$id_cart)) {
        $query = "UPDATE "._DB_PREFIX_."cartabandonment_remind SET visualize = 1 WHERE wich_remind = ".(int)$wichRemind." AND id_cart = ".(int)$id_cart;
        Db::getInstance()->Execute($query);
    }

    header('Content-Type: image/png');
    echo base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=');

}
Cologarithm answered 25/6, 2018 at 10:21 Comment(0)
S
0

Using OpenPixel will take care of most of the heavy lifting if the scope of your project calls for it.

Scrim answered 6/12, 2020 at 19:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.