Enhanced Visitor Event Tracking With Google Analytics and JQuery

February 16th, 2010 Rob 7 comments

Google Analytics has fast become the industry standard to track a plethora of web based information about your website. Whilst being totally free and easy to setup, you are limited to tracking elements that physically render in the browser – so items such as PDF, ZIP and RSS feeds links are not tracked, this because Google Analytics has a great reliance upon JavaScript. However, tracking such links can be achieved with a small amount of extra work.

Personally, I wasn’t aware you could track specific links with Analytics and only ever considored this when a client asked ‘why doesn’t Google show me the numbers of times my marketing report (read: a PDF file) has been clicked?’ – a totally valid request that I wanted to investigate.

Use JQuery to improve Google Analytics and track downloads, RSS, Email & external links

First things first, make sure you have a google Analytics account, the latest version of JQuery and the latest version of the analytics code running on your website :)

As with the majority of the JQuery magic, everything happens within the doc ready event listener – this will used to capture various clicks to select elements.

Tracking Download Link Clicks (PDF, ZIPs etc.)

$(document).ready(function() {

	$("a[rel=download]").click( function() {
		var fileName = $(this).attr("href");
		pageTracker._trackPageview(fileName);
		return true;
	});

});

Then on every link you wish to track, simply add the rel attribute to your non HTML files as follows:

<a href="myData.zip" rel="download">Download My ZIP Data File</a>

Tracking Downloads of Specifc File Types (E.g. PDF files)

Using the dollar sign to match against links that end in .pdf (or any extension you wish to track).

$(document).ready(function() {

	$("a[href$=pdf]").click( function() {
		var myPDF = "/pdfDownloads/" . $(this).attr("href");
		pageTracker._trackPageview(myPDF);
		return true;
	});

});

The /pdfDownloads/ is used to identify and seperate report data within Google Analytics.

Tracking the click of a specific link such as an RSS feed

Simply add an identifier to your RSS feed link (in this example the link was given an id of ‘rssFeed’):

$(document).ready(function() {

	$("a#rssFeed").click( function() {
		pageTracker._trackEvent("RSS", "RSS Subscriber Link Clicked");
		return true;
	});

});

Tracking mailto: Link Clicks

$(document).ready(function() {

	$("a[href^=mailto:]").click( function() {
		pageTracker._trackEvent("Mail", "User clicked on mailto link");
		return true;
	});

});

Tidying up….

You should also disable the clicked element to prevent multiple event recording and provide feedback. To do this, simple add the following at the start of each piece of code – disbabling the element and changing the cursor to an egg timer (although you could display a small graphic to make things look prettier):

$(this).css("cursor", "wait");
$(this).attr("disabled", true);
Categories: JQuery, SEO, google analytics Tags:

Prevent Duplicate Content using the Canonical Url Tag

December 19th, 2009 Rob 3 comments

I was recently doing an seo audit of a small ecommerce website. One of the first things I did was to do a ’site:www.domain.com’ in Google. Amazingly, the site in question has approximately 8200 pages indexed in Google. This was quite surprising when the store only sold less than 1500 unique products. The site used a horrible ecommerce module bolted onto phpnuke and has a horrible url structure, appending lots on unecessary querystring data onto the url.

Whilst looking through the Google results for this site the majority of pages were as follows:

/index.php?tab=123&txtSearch=ALL&List=oasc&Sort=PName%2CPName&CreatedUserID=1&pageindex=40&Language=en-GB

The site has an advanced search page, whereby you can sort products using a variety of options such as ascending order, descending order, size, price etc. This is bad for a number reasons, but mainly due to duplicate content (not to mention lower serps ranking, traffic loss and decreased page relevancy) . A page of results in ascending and descending order is essentially the same page, simply a different view of your data – you can help search engines via using the relatively new canonical url link tag.

To illustrate I’ll use an example of a typical category page, whereby you can sort a list of products in ascending and descending order, leaving you with a number of urls as follows:


http://www.shop.com/category.php?catName=Shirts&sortOrder=ASC

In this example the part of the querystring creating the duplicate content would be the sortOrder parameter – as you would want your seperate categories indexed.

The solution is quite simple. In your head tag add the following:

<link rel="canonical" href="http://www.shop.com/category.php?catName=Shirts" />

By adding this to your category page you are telling search engines (currently Google, Yahoo, Ask and Bing use this tag) that this page is a copy of http://www.shop.com/category.php?catName=Shirts. Indicators such as Google Pagerank are also transferred to your preferred url.

The canonical url tag has many uses and can be used to help with the following issues:

  • Pages that contain session IDs appended to the querystring
  • Search results pages that append search data to the querystring
  • Print versions of page
  • Duplicate content for www. and non-www. pages 0 in your canonical tag you would include your preferred url
  • Same content contained in multiple categories – E.g. a product contained in multiple categories on an online store
  • Removing affiliate ids in the url
  • Preventing multiple pages of a discussion topic with comments from being indexed E.g. shop.com/post.php?id=123&page=1

You can read more about the canonical tag at the official Google Webmaster Blog. Matt Cutt’s also has a 20 minute video explaing the canonical tag in more depth.

The main point to consider is that the canonical tag is simply a hint and not a directive. It is another method to give search engines help in indexing your content. This is very useful when working on existing sites already indexed by Google. However, on new sites bit more planning can help. For instance, in a  previous article I covered 301 redirects for seo using htaccess – how to set a prefferred version of your site via htaccess. On an ecommerce store you could avoid appending search data to the querystring.

EDIT: wordpress and all in one seo plugin generate canonical link tags for blog posts. For example, comments are seperated into multiple pages E.g


http://www.web-design-talk.co.uk/157/how-to-deal-with-difficult-clients-using-split-testing/comment-page-1/#comment-344

With the actual content being at:


http://www.web-design-talk.co.uk/157/how-to-deal-with-difficult-clients-using-split-testing

If you have a quick look at the source code to the comments page you’ll see the following has been added:

<pre id="line34"><link rel="canonical" href="http://www.web-design-talk.co.uk/157/how-to-deal-with-difficult-clients-using-split-testing/" />
Categories: General Tags:

How to Deal With Difficult Clients Using Split Testing

December 12th, 2009 Rob 6 comments

Sometimes you can be in the process of trying to tell a client that their idea simply won’t work. Be it a flimsey campaign idea of extra design element that you know through experience will not work and produce the desired KPIs for a client project. You can even show the client links, articles and examples of why their idea will fail to deliver results. However, if this is potential or existing client they are likely to go elsewhere, to a company willing to follow their every word without consideration – I have come across web companies who will do this.

Recently an existing client came to me asking why his site isn’t showing up when people search for a particular long tail search term. Now, his existing site used a pretty awful content management system that didn’t even allow him to set his own pages titles or meta descriptions. Furthermore, he was lacking inbound links, which people ranked above him did have. This all sounds simple and straightforward but even after I had explained (in quite clear and non technical langauge may I add) the merits of good SEO and one page content the client simply wouldn’t accept this as a solution. He had his own short term and less costly solutions – basically revolving around the the idea me resubmitting his sitemap page to all the major search engines each day. I’m not debating that submitting a sitemap isn’t a good idea, because it is. However, the client’s main KPI for this project was increased site enquiries.

After much discussing this we had both come to a bit of an awkward silence – not a good thing if you’ve ever experinced this in client meetings. For some reason I remebered back to my unoversity days where I had read something about split testing (or A/B testing) – where you can turn a negative situation into a positive one.This is quite a delicate situation to be in as it can damage your client relationship quite quickly.

The idea was to use the client’s idea for a period of time and my idea for a period of time. At the start of this I would install Google Analytics (I was tempted to use Google’s website optimizer, but decided against it) and let the statisitics do the talking – as a no one can argue with statistics.

This method has been very useful previously when demonstrating the merits of creating a dedicated landing page for Google Adword campaigns, but can be used anywhere if you’re willing to a little bit extra.

This method is beneficial for the following reasons:

  • The client’s idea are being dismissed as wrong (however right you think you are)
  • You are showing the client that you care enough to demonstrate your ideas
  • Occassionaly the client will back down as soon as you explain your plan of attack
  • It prevents those awful awkward silences
  • You have a real world example to use in your other client meetings
  • You are speaking the clients language in that you are demonstrating how your actions lead to increased conversions
  • You are being direct, which I personally think is alwasy a good thing – as such statistics are often a huge eye opener for clients
  • If and when the client comes to the same conslusion as you, they won’t blame you

There is always the arguement that the client is the client and that it’s all business at the end of the day. However, I personally pride myself on doing things properly. Others will say just get on with, do what the client wants and forget about it – you can only offer your opinion. This is a good point but can still damage your client relationships when they return later on and you need to charge them again. It all depends if you require long or short term client relationships – as they are definately an investment.

Categories: General, google analytics, web design Tags:

Improve SEO Through Home Menu Anchor Text Optimisation

November 12th, 2009 Rob 7 comments

seo-anchor-textIt’s a widely known fact that link anchor text is rated YH2Z675VXTC5 highly by search engines and is often the deciding factor in your SERP position for competitive terms, mainly because it gives meaningful information to users (amongst others). Correct use of anchor text (on both inbound and outbound links) will give your page increased meaning.

I’m sure you use this fact throughout your website while performing onsite SEO. Any tutorial will rightly tell you that keyword relevancy is of upmost importance here. However, a lot of the time you end up with a ‘Home’ link on your menu, linking to your main page.

This is bad for SEO for a number reasons. Firstly, the anchor text ‘home’ is very poor choice of word to use as it’s meaning is highly diluted nowadays. Now unless you have a site relating to homes, the keyword isn’t very useful at all, as we don’t want to rank highly for the term ‘home’. However, at the same time users are familiar with such a link and it makes sense to name such a link to your main page. The situation is worsened if your site is large with a great number of internal links. Imagine having a 100 page site, all with the anchor text ‘home’ – this is a lot of inbound links telling search engines each page is related to ‘home’! Furthermore, the menu link’s are usually towards to the top of the page, giving them inscreased relevancy to search engines.

The solution is a compromise, use ‘home’ along with you main keyword(s) – making sure to avoid obvious stop words like ‘and’. For example ‘Graphic Design Home’. Even better use your main keyword directly in the anchor text i.e. ‘Graphic Design’. This is quite a powerful and simple SEO trick that is easy to implement into your site.

Categories: SEO, web design Tags:

Process Custom eCommerce data using Paypal IPN

November 11th, 2009 Rob No comments

More often than not it’s hard to visualise how you can send custom information to Paypal during checkout. The list of available hidden field variables initially seems very specific and restrictive at best. Granted, you can easily send over simple things such as your shipping amountm and tax rate. However, during order processing (done in you IPN script that Paypal sends the transaction’s IPN post data to) you often want to record more information when creating and storingn order information.

For example, let’s say the user can enter a specific coupon code during checkout. You would want to make sure the Paypal transaction has been successful before making the voucher as used, to do this you would need to know what code was entered during checkout. In the following simple example we’ll use the ‘custom’ field variable  – this is an optional field, whereby the the data is never presented to the shopper and can be 256 character long. Whatever is placed in this field before clicking your checkout button will be invisibly sent ot Paypal and posted back to your IPN script (assuming you have youre ‘rm’ or return method set to 2, or ‘POST’). The HTML for the hidden field is very simple:

<input type="hidden" name="custom" value="YOUR CUSTOM INFORMATION HERE">

Now, let’s say when you’re recording all the order information you weant to record the exact coupon code, delivery method id, the method by which the customer found your site (E.g. another id) and referrer id number. For convenience and for the sake of the example, I’ll assume you’ve done all the necessary processing to get your four pieces of information. The code to create our hidden field data is as follows:

/* ...logic to get below variables here! */

$shipping_method_id = '33';
$coupon_code = '45895';
$found_out_method = '9';
$referrer_id = '200';

$custom_info =
                       array(
			'shipping_method_id' => 33,
			'coupon_code'=> 45895 ,
			'found_out_method' => 20 ,
			'referrer_id' => 9
			);

/* Initiase field data and looping variable */
$field_data = NULL;
$i = 0;

/* Loop through info array to build data string */
foreach ($custom_info as $key => $field) {

	$field_data .= $field;
	$i++;

	if ( $i !== count($custom_info)) {
	      $field_data .= '-';
	}

}

/* create the hidden field
generated HTML is <input type="hidden" name="custom" value="33-45895-20-9"> */
echo '<input type="hidden" name="custom" value="'.$field_data.'">' . "\n";

Printing the value of $field data will give you the string ‘33-45895-20-9′. This translates to shipping method id 33, coupon code 45895, found out id 20 and referrer id 9. The dash symbol has been used to delimit values for convenience, as we need to split this string up later on.

To process these variables in your IPN script (see the Paypal PHP sample script) you simply use PHP’s explode method to split the data into an array:

/* $_POST['custom'] contains the custom information we initially sent to Paypal */
$data = explode('-',$_POST['custom']);

/* Convert $data array into variables for further processing */
$shipping_method_id = $data[0];
$coupon_code = $data[1];
$found_out_method = $data[2];
$referrer_id = $data[3];

So you’ve now posted a string of custom information to Paypal and got this custom data back via IPN during the transaction processing. Now you have assigned each piece iof the array to a variable, you can easily continue to create your order header and save it to a database.

Categories: PHP, Paypal Tags:

Tracking Twitter Performance Using Google Analytics

November 11th, 2009 Rob No comments

If you use the ever popular twitter there’s a high chance you’ll be linking to your company webiste or personal blog in your tweets or profile link. As the aim is use twitter as a marketing tool to drive traffic, you can use Google Analytics to track the link you placed the twitter profile – just like an email campiagn or PPC advert

If you use Twitter as a marketing tool to drive traffic to your site then you should treat it in exactly the same way as you would a newsletter, a PPC advert or a banner and track each Tweet’s performance beyond simple click data. How many visits do you get, how long do they stay on your site, how deep do they go, what is the bounce rate like and how much revenue do they generate?

The benefit to ‘tagging’ this link is that Google Analytics will record more than use basic click data – you can record a whole host of advanced user data such as how they navigate your site and length of visit. By default Google will track such links, but traffic from services such as bit.ly will be dumped into the direct traffic area of Google Analytics. The steps to get the latter up and running are quite simple:

1: Go to Google’s URL builder to generate an url . Enter the following information:

Website URL: your website address

Campaign Source: enter a relevant source here to identify your campaign E.g. twitter

Campaign Name: enter a name used to identify the campaign, this is used to identify the campaign in Google Anlytics E.g. twittertracking

2: Click generate URL and something similar to the following will be created: http://www.web-design-talk.co.uk/?utm_source=twitter&utm_medium=social&utm_campaign=twittertrack


3: If posting to twitter you can paste this URL directly in the tweet box, as twitter will automatically shorten this url.

4: After approximately 24 hours data will appear in your analytics account. Simply navigate to Traffic Sources. If you’ve used the same terms to build the url as above you’ll see an entry called ‘twitter / social’. You can also view information by navigating to Traffic Sources > Campaigns where you can click the campiagn name (‘twittertrack’ was used in he example above).

Google Analytics Once Tracking is Installed

Google Analytics Once Tracking is Installed

Categories: General, SEO, google analytics Tags:

MySQL Cheatsheet – Useful MySQL Queries

November 5th, 2009 Rob No comments

What follows is a list of some very useful MySQL queries for use in projects, enjoy. I won’t go into detail how and why they work, I’ll leave that up to you :)

/*** select records from the previous day ***/
SELECT * FROM users WHERE TO_DAYS(last_login) = ( TO_DAYS(NOW()) - 1 )

/*** select records from last 90 minutes ***/
SELECT* FROM users DATE_SUB(NOW(),INTERVAL 90 MINUTE);

/*** select records from last 1hr 5 mins ***/
SELECT DATE_ADD('1970-01-01 12:00:00', INTERVAL CAST(6/4 AS DECIMAL(3,1)) HOUR_MINUTE);

/*** select records from last hour ***/
select DATE_SUB(NOW(), INTERVAL 1 HOUR);

/*** using the SIGN function to mark a number as positive, negative or null ***/
SELECT backlist, SIGN(backlist) AS user_to_backlist
FROM users
WHERE user_banned IS NOT NULL;

/*** select records from last week ***/
select DATE_SUB(NOW(), INTERVAL 1 WEEK);

/*** get the last day of next month ***/
SELECT LAST_DAY('2006-03-06' + INTERVAL 1 MONTH) AS last_day;

/*** select unique records only ***/
SELECT user_name FROM users GROUP BY users HAVING ( COUNT(user_name) = 1 );

/*** select records from one table that are in another table i.e. all the customers that have placed an order ***/
SELECT DISTINCT cust.customer_id, cust.customer_name
FROM cust INNER JOIN orders ON cust.customer_id = orders.customer_id;

/*** insert data from one table into another ***/
INSERT INTO customers(customer_id, customer_name)
SELECT cus_key, cus_name
FROM customers_2 WHERE customer_name LIKE 'W%';

/*** update information based upon a seperate table ***/
UPDATE cust SET status = '1'
FROM orders WHERE orderdate > '2009-01-01' and orders.customer_id = cus.customer_id;

/*** classic self join example - who is an emoployees manager ***/
SELECT emp.empID, emp.Name, emp.Salary, managers.Name AS manager_name
FROM emp
LEFT JOIN emp AS manager_name
ON emp.ManagerID = Manager.EmployeeID
WHERE (emp.empID= '123456');

/*** using UNION to combine results from multiple queries into a single table ***/
SELECT users.name
FROM users WHERE (users.name BETWEEN 'A%' AND 'M%')
UNION
SELECT banned_users.name FROM banned_users
WHERE (banned_users.name BETWEEN 'A%' AND 'M%');

/*** concatenate column data into a single column ***/
SELECT CONCAT(emp.firstname, '-', emp.lastname) AS emp_full_name FROM emp;

/*** select count of records for each hour ***/
SELECT HOUR(last_login) AS last_login_hour, COUNT(*) AS the_count FROM users GROUP BY HOUR(last_login);

/*** import a csv file ***/
LOAD DATA INFILE '/path/xxx.csv' INTO users_table csv_test_table FIELDS TERMINATED BY ',' LINES TERMINATED BY "\n" (user_name, access_level , user_email);

/*** display current mysql user ***/
SELECT USER();

Getting htaccess Mod-rewrite rules working locally with XAMPP

September 15th, 2009 Rob No comments

After spending a whole 2 hours of my life trying to get Apache mod-rewrite rules working with XAMPP on a local computer, I thought I’d share my results as I seemingly tried everything. The problem, I have a simple mod-rewrite rule in my htaccess file. When I upload this to my online web host everything is fine – the working htaccess file for my online host:

RewriteBase /
RewriteEngine on
RewriteRule amnesia/resetpass(.*) recover-password.php$1 [PT]

So typing in www.domain.com/amnesia/resetpass does a simple re-write to www.domain.com/recover-password.php, without the user ever knowing. All is fine. However, when I treid to get this seemingly simple rule to work with XAMPP I ran into problems, getting 404 and 500 responses from the server – obviously quite a pain as this essentially means I can’t test the site using my own web server (E.g. localhost). The site hosted from my computer via the normal setup E.g. xampp/htdocs/mysite. I’ll jump straight to the solution and then explain exactly what things were changed – the working htaccess file is below:

RewriteEngine on
RewriteBase /mysite
options +FollowSymLinks
RewriteRule amnesia/resetpass(.*) recover-password.php$1 [PT]

Firstly, the extra line that uses the +FollowSymLinks directive was added. To explain this I’ll quote straught from the Apache documentation:

To enable the rewriting engine for per-directory configuration files, you need to set “RewriteEngine On” in these files andOptions FollowSymLinks” must be enabled. If your administrator has disabled override of FollowSymLinks for a user’s directory, then you cannot use the rewriting engine. This restriction is needed for security reasons.

The re-write base has been changed to the relative path of the website directory. To finish up, open the http.conf file (the default settings for XAMPP, that get overwritten with you .htaccess file rules on a directory basis), located by default at C:\xampp\apache\conf\http.conf. Find all occurances of AllowOverride None and change it to AllowOverride All. After restarting XAMPP everythign should work. In a nutshell changing the AllowOverride directive in the http.conf file decalres which directives in .htaccess files can override directives from httpd.conf, this is discussed in more dept over here, but basically by having this directive set to None, you’re stopping individual htaccess files from working locally.

SEO Friendly URLs With Mod Rewrite

August 23rd, 2009 Rob 3 comments

So called ‘dirty URLS’ (E.g. www.domain.com/products.asp?id=45&cat=34&mode=view) not only look untidy but also pose a security risk as they expose the underlying technology used, in this case, ASP. A much preferred URL in this case would be www.domain.com/product/45 or even better, www.domain.com/product/product_keywords-here. The latter URL structure not only improves useability for your site (the URL makes more sense to the user) and is argued to improve search engine rankings. There is a lot of debate on this subject, but everyone agress that these so called pretty URL’s don’t hurt anything and mainly improve user experience.  Google has also recently posted a video (obviously not giving much away) saying that SEO friendly URL’s do in fact make a small difference and don’t hurt SERPs’

Take the example of this very blog. Pretty urls are used to display the post title and id within the url. There is the option to simply include the title, but this has been proven to slow down general performance of your blog. I digress, let’s get onto some examples where simple URL rewriting with mod rewrite is useful.

» Read more…

Categories: General Tags:

Getting Multiple Array Form Values With PHP

August 18th, 2009 Rob 3 comments
php array code

PHP Arrays

Further to my article on using JQuery to dynamically append form elements, I have come across situations where multiple items should be appended to the form each time, as opposed to a single input in my article (I did this simplicity). For example, at work I’m currently working on an internal system whereby a user needs to add an unlimited amount of client contacts for a client. Pressing the ‘add contact’ link will append 3 fields – one for conatct name, contact telephone and contact email. Each of these fields are named exactly the same way as before (using square brackets at the end of the name E.g. ‘name[]‘) and appended the same way using JQuery.

There are lots of articles floating about explaing how to add fields, but I’ve not yet seen anything explaining how to retreive multiple elements like this.

The only differnce arises when retreiving these multiple values from the PHP’s POST array. In the example I have appended 3 inputs, named cname[], cemail[] and ctel[]. The values of each can be retreived using a slightly enchanced for loop:

if (isset($_POST['cname'])) {
for ( $i=0;$i<count($_POST['cname']);$i++) {
$contactname = $_POST['cname'][$i];
$conatctemail = $_POST['cemail'][$i];
$contacttel = $_POST['ctel'][$i];
}
}

That’s really all there is to it and I’m finding that the latter comes in useful quit regularly in every day projects.

<