Share |

Archive for March, 2010

5 Years of Blogging – Part 1

March 16th, 2010

As I mentioned a few days ago, I’m shortly coming up on 5 years of blogging, which still astounds me when I think of it. There are now many people who have been blogging for five or more years, so it’s not that unusual anymore, but it’s longer than I expected to be running this blog. The official anniversary date will be May 30, 2010, which is exactly five years after my first post. In preparation for this anniversary, I’m going to run a retrospective series about this blog, blogging in general, AdSense, search engine optimization, Internet marketing, and other related topics — whatever comes to mind, I guess, as I peruse five years worth of posts.

Let’s start with a few stats. Not counting this post, I have 1048 posts, which comes out to be about 210 posts per year, or just under 18 posts per month. Oddly enough, that’s pretty close to the 20 or so working days there is in a month. My output’s decreased quite noticeably in the last year or so, mind you, but for a while I was pretty much posting something once or twice a day.

Comments… There are over 3000 approved comments. I currently have 2400 pending comments, but most of those are spam (both out-and-out spam but also lots of “I like your site!” and “Keep up the good work!” and “Nice article!” type comments) and I’ve gotten into the habit of blowing away the entire pending comment pool when it gets too big to navigate… Lots of commenters are showing up lately because the blog is near the top of list of “dofollow” blogs and everyone’s trying to get a nice juicy link from a PR4 page back to their site. Too bad I moderate all comments… if you don’t have anything worthy to say, don’t bother commenting!

I can’t say this blog ranks highly for many keywords in Google. For “adsense” it’s around #70. Even though I have a fair number of inbound links (about 50,000 according to Yahoo!), only about half of the pages on this site are actually in Google’s index and only 400 or so of them show up when you do a “site:memwg.com” query. There are different reasons for this. One is that the site’s been hacked numerous times — I took out some injection code just yesterday that was putting lots of links for popular pharmaceuticals into my pages. It’s also been losing link velocity — the speed at which incoming links are made — because I haven’t been updating it very much lately. And I don’t have a lot of deep links into the site, which is another problem — most of the links are directed at the root of the domain.

Anyhow, in part 2 we’ll actually start the retrospective by looking at 5 things I’d wish I’d done different from the beginning.

Coming Up To 5 Years Of Fun!

March 11th, 2010

I just realized the other day that this blog is almost 5 years old now…. the first post was on May 30, 2005. Wow. I should do something to celebrate. But what? Let me know what you think….

ClickBank Tracking Script

March 9th, 2010

Here is a simple ClickBank tracking script written in PHP that you can install on any of your websites free of charge. It can be used to track sales from AdWords and sales from EzineArticles and other article directories.

Installation

Installation is simple, just copy the index.php file shown below (after modifying it slightly) up to your web hosting service. If you’re doing EzineArticles-friendly domain serving, install it in the root of the server, otherwise you can just create a new folder and install it there. For example, I might create a folder called “burnthefat” and place the index.php file in there. Any subsequent access to “http://www.mydomain.com/burnthefat/” would invoke the script and do a redirection.

Before uploading the script, be sure to modify the default $affiliateid and $vendorid values. They are currently set to ‘egiguere’ (my primary CB affiliate ID) and ‘burnthefat’ (the vendor ID for Burn the Fat, Feed the Muscle). Set them to appropriate defaults. You can override these settings when invoking the script. (If you’re planning on using the domain with EzineArticles, you MUST set the affiliate and vendor ID values correctly because you can only link to the root of the URL with no parameters.)

Now this is totally optional, but you may also want to add these lines to a .htaccess file that you place in the same directory as the index.php file:

<Files *.log>
order allow,deny
deny from all
</Files>

These lines ensure that no one can download the .csv files the script creates — you’ll have to fetch them yourself using an FTP client. (Like I said, optional…)

Tracking EzineArticles and Other Sites

The script looks at the referrer header and tries to build a tracking ID that incorporates part of the domain name and some kind of unique identifier. For EzineArticles, for example, it uses the “id” field (the article identifier). So you can easily tell which article of yours generated the click. It looks for “id”, “C” (which is used by GoArticles) and “kw”. You can easily modify it to look for other things.

The tracking ID generated in these cases consists of the date and time (in MMDDHHSS format — 8 characters long, i.e. “03091347″), some portion of the domain name (i.e. “ezineartic”), and the article ID (i.e. “672234″). So when you see this show up in your ClickBank report:

03091347ezineartic672234

you’ll know the click came on 13:47 on March 9 from EzineArticles article #672234.

Tracking AdWords Clicks

The script has some built-in features for tracking AdWords clicks, but only if you use a special syntax in your destination URLs, like so:

http://www.yoursite.com/?ag=rf01&nw={ifsearch:s}{ifcontent:c}
&kw={keyword:none}&pl={placement}

This is what the values mean:

  • ag — an identifier for the ad group or whatever unique thing you want to track, i.e. if you have two different ad texts you might want to assign two different values here
  • nw — the network being used. Note the special “{ifsearch:s}{ifcontent:c}” syntax. On the search network, the value will end up being “nw=s”, on the content network it will end up being “nw=c”. This is how you tell where the click comes from.
  • kw — the keyword that triggered the ad, if known, or “none” if not known.
  • pl — the website the ad was featured on if it’s shown on a third-party site.

As you see, you can pack a lot of information into the destination URL. The script will store all this information in the CSV files it creates and it will use it to create a tracking ID. The tracking ID will start with the date (MMDDHHSS as before) followed by “aw” (for “AdWords”), followed by one character for the network (“s” for search, “c” for content, “u” if unknown), followed by the ad group (the “ag” value), followed by as much of the keyword (the “kw” value) as will fit. (Tracking IDs are limited to 24 characters, remember.)

Other Sources

If the script doesn’t have enough information to create a (semi)human-readable tracking ID, it generates a random number and prefixes it with the date (in MMDDHHSS format) and uses that as the tracking ID.

Overriding Affiliate and Vendor IDs

You can set the affiliate ID and vendor ID explicitly by using the “affiliateid” and “vendorid” query parameters, as in:

http://www.feedthemuscleburnthefat.com/?vendorid=4idiots

This is useful if you want to use the same script for multiple redirections.

Analyzing the Data in Detail

The tracking IDs the script creates are meant to be easily eyeballed in the ClickBank sales report. But if you want to know more about the context of a particular tracking ID, the script stores information in simple CSV (comma-separated value) files that you can easily download and load into a spreadsheet application like Microsoft Excel. A separate file is created for each day, so the clicks for March 8, 2010 are found in “clicks.2010-03-08.csv”, in the same folder as the index.php file.

So when you see a click in your ClickBank sales report and you want to know more about it, look at the first 4 characters of the tracking ID to extract the month and day to know which file to download and open in Excel. The following data is stored, in this order:

  1. The full date and time
  2. The tracking ID
  3. The final affiliate ID
  4. The visitor’s IP address
  5. The full path that was requested, including any parameters
  6. The referrer URL, if any
  7. The user-agent header, if any (useful for discerning robots from humans)

The Script

Here it is. Either download this text file or copy the text below; place the text into a file called index.php and copy it up to your webserver.

<?php

//*************************************************************
//
// ClickBank Tracking Script
// Version 1.0
// Copyright 2010 by Eric Giguere
// ericgiguere@ericgiguere.com
//
// You may use this script for free on as many sites as you want.
// You cannot sell this script or otherwise claim ownership.
// This script is provided as-is, no warranties are implied.
//
// For installation instructions, see
// http://www.memwg.com/clickbank-tracking-script/
//
//*************************************************************
// Modify these values to set your affiliate ID, the vendor ID,
// and any additional data (i.e. '&page=1928') to append to the
// final hoplink after the tracking ID.
//*************************************************************

$affiliateid = $_GET['affiliateid'];
$vendorid    = $_GET['vendorid'];
$extra       = $_GET['extra'];

if( empty( $affiliateid ) ) $affiliateid = 'egiguere';
if( empty( $vendorid ) )    $vendorid    = 'burnthefat';

//*************************************************************
// You shouldn't need to change anything below this point.
//*************************************************************

// Gather information about the visitor.

$ip       = $_SERVER['REMOTE_ADDR'];
$referrer = $_SERVER['HTTP_REFERER'];
$browser  = $_SERVER['HTTP_USER_AGENT'];
$request  = $_SERVER['REQUEST_URI'];
$reqtime  = date( 'Y/m/d H:i:s T' );
$logfile  = 'clicks.' . date( 'Y-m-d' ) . '.csv';
$prefix   = date( 'mdHi' );
$source   = '';
$tid      = '';

// Check query parameters to determine if we are being called
// from AdWords. If we are, gather the requisite info. If not,
// try to figure out where we're being called from using the
// referrer header.

if( !empty( $_GET['kw'] ) || !empty( $_GET['ag'] ) || !empty( $_GET['nw'] ) ){
    $nw      = strtolower( $_GET['nw'] );

    if( strlen( $nw ) != 1 ){
        $nw = 'u';
    }

    $source  = 'aw' . $nw;
    $keyword = $_GET['kw'];
    $adgroup = $_GET['ag'];

    $tid = substr( $prefix . $source . $adgroup . makealphanum( $keyword ), 0, 24 );
} 

// If we weren't called from AdWords, check the referrer header and
// see if we can suss out an identifier of some kind and combine it
// with the domain name to create a tracking ID.

if( empty( $tid ) && !empty( $referrer ) ){
    $referrerparts = parse_url( trim( $referrer ) );

    $host = ( $referrerparts['host'] ? $referrerparts['host'] :
               array_shift( explode( '/', $referrerparts['path'], 2 ) ) );

    $params = parse_query( $referrerparts['query'] );

    $hostparts = preg_split( '/\./', $host );
    $tld = count( $hostparts ) - 1;

    if( $tld > 0 ){
        $domain = $hostparts[$tld-1];
    $ids = array( 'id', 'C', 'kw' );

    foreach( $ids as $param ){
        if( !empty( $params[$param] ) ){
            $source = makealphanum( $params[$param] );
        }

        if( $source ) break;
    }

    if( !empty( $source ) ){
        $tid = $prefix . substr( $domain . $source, -16 );
    }
    }
}

// Last resort: we weren't able to create a tracking ID, so
// generate a unique string to server as our ID.

if( empty( $tid ) ){
    $tid = substr( getfaketid( $prefix ), 0, 24 );
}

$afflink = 'http://' . $affiliateid . '.' . $vendorid .
           '.hop.clickbank.net/?tid=' . $tid . $extra;

header( "Location: $afflink" );

// Write out the data to our CSV file

$fp = fopen( $logfile, 'a' );

if( $fp ){
  fputs( $fp, logmsg() );
  fclose( $fp );
}

//*************************************************************
// Functions used by the code above...
//*************************************************************

// Convert the string to a lower case alphanumeric-only string

function makealphanum( $str ){
    return ereg_replace( '[^a-z0-9]', '', strtolower( urldecode( $str ) ) );
}

// Parse a query string into its constituent parts

function parse_query( $var ){
    $var = html_entity_decode( $var );
    $var = explode( '&', $var );
    $arr = array();

    foreach( $var as $val ){
        $x          = explode( '=', $val );
        $arr[$x[0]] = $x[1];
    }

    unset( $val, $x, $var );
    return $arr;
}

// Encode URLs for saving in the CSV file by converting
// quotes and commas to URL escapes.

function csvencode( $str ){
    $str = str_replace( '"', '%22', $str );
    $str = str_replace( ',', '%2C', $str );
    return $str;
}

// Create the line of CSV data to append to the log file

function logmsg(){
    global $request;
    global $ip;
    global $referrer;
    global $browser;
    global $tid;
    global $reqtime;
    global $afflink;

    $msg = "$reqtime,$tid,$afflink,$ip," . csvencode( $request ) . ","
         . csvencode( $referrer ) . "," . csvencode( $browser );

    return $msg . "\n";
}

// Generate a fake TID with the given prefix.

function getfaketid( $prefix ){
    return uniqid( $prefix );
}

?>

Final Thoughts

OK, user-friendly this isn’t, I admit it. It’s very geeky. But if you’re even a bit technically inclined you should be able to install this script and use it. If you have questions about it, please leave them as comments here rather than mailing me, it’ll be more useful for others.