Because sharing is caring

Tracking Facebook likes, shares and sends in Google Analytics

Posted: May 23rd, 2011 | Author: | Filed under: Javascript, JQuery, SEO, Web Development | Tags: , , | No Comments »

Following up on my previous post about Tracking External links with Google Analytics. Here’s something you can use to track Facebook likes and shares.

We’ll track clicks using the Facebook Events. Note that this only works if you’re using FBML!
Here’s the things we’re going to be tracking:

  • Somebody clicks the ‘Like’ button on your website to ‘Like’ your Facebook page
  • Somebody clicks the ‘Like’ button on your website to share the current page on his ‘Wall’
  • Somebody clicks the ‘Send’ button to share this page with some friends on Facebook

And it’s all in here:

FB.Event.subscribe("edge.create",function(response){
	if(response.indexOf("facebook.com") > 0){
                 //if the returned link contains 'facebook,com'. It's a 'Like' for your Facebook page
		_gaq.push(['_trackEvent','Facebook','Like',response]);
	}else{
                 //else, somebody is sharing the current page on their wall
		_gaq.push(['_trackEvent','Facebook','Share',response]);
	}
});
FB.Event.subscribe("message.send",function(response){
	_gaq.push(['_trackEvent','Facebook','Send',response]);
});

As you may have noticed, the Facebook event contains the liked/shared/sent link as response


Easily track outgoing links with jQuery and Google Analytics

Posted: May 19th, 2011 | Author: | Filed under: Javascript, JQuery, SEO, Web Development | Tags: , | 1 Comment »

Outgoing links on your websites cause 3 things:

  • Take linkjuice away from your page
  • Drive traffic away from your webiste
  • They don’t allow you to measure the amount of clicks on that link

The first problem, you have to sort manually by adding the rel=”nofollow” attribute to all external links, as recommended by Google.

The second and third problem, can be easily fixed by using jQuery. I’ll show you how:

Opening external links in a new tab

By opening those links in a new tab, your page stays open, therefore not driving the user away from your page.
Normally, this is done by manually appending target=”_blank” to each link. Let’s let jQuery do that for us.

$(document).ready(function(){
    $("a[@href^='http']").attr('target','_blank');
});

(Do note that I chose to define links starting with ‘http’ as external links)

Tracking clicks on external Links

We can track links by using Google Analytics Event tracking:

$(document).ready(function(){
    $("a[@href^='http']").click(function(){
        _gaq.push(['_trackEvent', 'External Link','Click', $(this).attr("href")]);
    });
});

Putting it all together

$(document).ready(function(){
    $("a[@href^='http']")
        .attr('target','_blank')
        .click(function(){
            _gaq.push(['_trackEvent', 'External Link','Click', $(this).attr("href")]);
        });
});

Help! My internal links also start with ‘http’

No problem, you can do like me and borrow this trick from Karl Swedberg:

$('a').filter(function() { return this.hostname && this.hostname !== location.hostname; })
.attr('target','_blank')
.click(function(){
    _gaq.push(['_trackEvent', 'External Link','Click', $(this).attr("href")]);
});


Google Breadcrumbs come from … Breadcrumbs

Posted: March 29th, 2011 | Author: | Filed under: SEO, Web Development | Tags: , , , | No Comments »

Google sometimes shows breadcrumbs in their search results.
Instead of showing the URL of the page you’re going to visit (in the green bit), hey’ll show a path kind of like so:
Homepage › Category › Subcategory > Something something.
Many SEO experts have been trying to figure out just where they come from. So have I.
So recently, on one of my websites: promoties.be. I had the chance to figure it out.

All promotions are divided into categories and subcategories. The URL of these categories are always hierarchically mapped.
e.g. http://www.promoties.be/categorie/autos-motoren-27/aanhangwagens-1419 is a subcategory of http://www.promoties.be/categorie/autos-motoren-27 making the URL logically traversable.
However a specific offer or product under this category is not in this structure. Mainly because that would make the URL way too long.
An example is http://www.promoties.be/promotie-bw1-aanhangwagen-864809. As you can see, the categories do not appear in the URL.

However the breadcrumb for this offer is as follows: Home > Promoties > Auto’s & Motoren > Aanhangwagens > Bw1 aanhangwagen with all the nested categories intact.

Now the Google search result block for this specific offer was the following:

Google search result for "Bw1 aanhangwagen"

In this case we can conclude that Google took the breadcrumbs in the search results, from the breadcrumbs on the page.

More info on breadcrumbs:

http://www.google.com/support/webmasters/bin/answer.py?answer=185417


Force AJAX calls no-cache in Java. The clean way

Posted: January 25th, 2011 | Author: | Filed under: Java, JQuery, SEO, Web Development | Tags: , , , , | No Comments »

Recently I discovered Internet Explorer caches some AJAX calls.

I was using jQuery to make some AJAX calls in a web-admin interface I’m building. I noticed none of the data changed as I tried to refresh (using an AJAX call). conclusion:: IE caches AJAX calls… very annoying.

You could go around and alter every method in your Struts/Spring/… application to force no-cache. But that would take some time. Instead, I wrote a Filter.

Hold on though, you don’t want every page to get the no-cache headers, that would seriously decrease your site performance (all pages would be force-reloaded instead of browser-cached). So we’ll only filter out AJAX calls.

Luckily, jQuery passes a header argument: X-Requested-With: XmlHttpRequest

x-requested-with header

X-Requested-With

The Code!

import java.io.IOException;
 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class AjaxCacheFilter implements Filter{
 
	@Override
	public void destroy() {
	}
 
	@Override
	public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
		if ("XMLHttpRequest".equals(((HttpServletRequest) request).getHeader("x-requested-with"))) {
			((HttpServletResponse)response).setDateHeader("Expires", 0);
			((HttpServletResponse)response).addHeader("Cache-Control", "no-cache");
			((HttpServletResponse)response).addHeader("Pragma", "No-Cache");
 
		}
		chain.doFilter(request, response);
	}
 
	@Override
	public void init(FilterConfig arg0) throws ServletException {
	}
}

And add it as the last filter in your web.xml

<filter>
	<filter-name>ajaxCache</filter-name>
	<filter-class>
		com.yoursite.web.filters.AjaxCacheFilter
	</filter-class>
</filter>
<filter-mapping>
	<filter-name>ajaxCache</filter-name>
	<url-pattern>/*</url-pattern>
 	<dispatcher>FORWARD</dispatcher>
		<dispatcher>REQUEST</dispatcher>
</filter-mapping>

Hope it helps somebody! If you used it, let me know in comments. I’d love to know!


Guide to Google’s mod_pagespeed

Posted: December 3rd, 2010 | Author: | Filed under: SEO, Web Development | Tags: , , , , , | 1 Comment »

Google recently released a specific Apache mod: mod_pagespeed.
Here are my findings:

Introduction: goal

Often, when developing websites/webapplications, you find yourself telling yourself: I’ll quickly write that piece of CSS inline or Fudge it, I’ll leave compressing that piece of JavaScript for when I get out of development phase and maybe even never mind resizing that image, I’ll just use ‘width’ and ‘height’ to get the dimensions right.
And oh how you promise yourself you’ll fix those issues later. But let’s be honest: deadlines are cruel.

So a lot of websites go live without a lot of speed omtimizations. They get a bad score in YSlow or PageSpeed.
And the word on the street is, google prefers website that load faster!

Optimizing your CSS/JS/Images takes time. Compressing your content, combining CSS/JS also makes it difficult to adjust any of these later. You’ll have to dig through compacted code. Nobody likes that.

The solution

The new mod_pagespeed is an Apache Output Filter. This means your website renders your website (in PHP, Java, Ruby, …) and just before Apache serves your HTML page to the browser, this thing comes into action.

You can configure it to do a lot of things. I listed the ones I find most important below. But you can get the full feature list here

  • Compress CSS and JS (less traffic)
  • Move inline CSS/JS to an external file (so they can get cached)
  • Combine external CSS/JS to one file (less requests)
  • Caching (of HTML,CSS,JS,images)
  • Automatically resize images based on the ‘width’ and ‘height’ attributes of an img-tag (less traffic)
  • Add ‘width’ and ‘height’ attributes if you forgot any (usability)
  • Base64 encode images and include them in HTML when small (less requests)

Bottomline: it’s genius

My Configuration

I played around with mod_pagespeed today. Here’s the configuration I came up with (I added comments)
(your configuration resides in /etc/apache2/mods-enabled/pagespeed.conf)

<IfModule pagespeed_module>
	ModPagespeed on
	AddOutputFilterByType MOD_PAGESPEED_OUTPUT_FILTER text/html
 
	ModPagespeedFileCachePath            "/var/mod_pagespeed/cache/"
	ModPagespeedGeneratedFilePrefix      "/var/mod_pagespeed/files/"
 
	ModPagespeedRewriteLevel CoreFilters
 
 
	ModPagespeedFileCachePath            "/var/mod_pagespeed/cache/"
	ModPagespeedGeneratedFilePrefix      "/var/mod_pagespeed/files/"
	#Add head section to HTML (if not already there)
	ModPagespeedEnableFilters add_head
	#Move CSS and JS to outline (external file)
	ModPagespeedEnableFilters outline_css,outline_javascript
	#If inline CSS is used, move this to head section
	ModPagespeedEnableFilters move_css_to_head
	#Combine external CSS files to 1 fil
	ModPagespeedEnableFilters combine_css
	#Compress CSS and JS by removing whitespace/comments
	ModPagespeedEnableFilters rewrite_css,rewrite_javascript
	#Cache/compress images. Couold also move the image to  HTML code (base64 encoded) if image size is small enough
	ModPagespeedEnableFilters rewrite_images
	#Add longer expires headers
	ModPagespeedEnableFilters extend_cache
	#Insert "width" and "height" attributes if not used
	ModPagespeedEnableFilters insert_img_dimensions
	#Remove HTML comments
	ModPagespeedEnableFilters remove_comments
	# Removes quotes around HTML attributes that are not lexically required
	ModPagespeedEnableFilters remove_quotes
 
	#pagespeed enabled domain 1
	ModPagespeedDomain tv.bartv.be
	#Pagespeed enabled domain 2
	ModPagespeedDomain cloudcast.bartv.be
	#pagespeed enabled domain 3
	ModPagespeedDomain notes.bartv.be
 
	#Maximum filesize cache
	ModPagespeedFileCacheSizeKb          10240
	#Interval to which cache is refreshed
	ModPagespeedFileCacheCleanIntervalMs 3600000
	ModPagespeedLRUCacheKbPerProcess     1024
	ModPagespeedLRUCacheByteLimit        16384
	#Minimum allowed bytes in CSS before exporting to external CSS
	ModPagespeedCssOutlineMinBytes       1000
	#Minimum allowed bytes in JS before exporting to external JS
	ModPagespeedJsOutlineMinBytes        3000
        #Maximum allowed filesize for embedding images inline (base64)
        ModPagespeedImgInlineMaxBytes        2048
 
</IfModule>

Carefull with writing permissions

On my webserver, I run every website under a different user account (e.g. mycoolwebsite.bartv.be is run by user ‘coolwebsite’ or something). They all belong to the group ‘www-data’.
Now one consequence of this is that the cache being written by mod_pagespeed gets written by the user running the website. So be carefull with writing permissions in /var/mod_pagespeed/

Footnote

Even though this article might suggest it. I’m in no way promoting quick and dirty development.
You could think: to hell with it, I’ll just write whatever I want, mod_pagespeed will solve it for me. Don’t

mod_pagespeed is great, but in my eyes, it helps you find errors you might have missed. And it lets you use your development CSS/JS files without compressing them first.
But don’t use it to clean up your mess!