Saturday, 9 April 2011

Did I help? Gauge if your articles are solving real world problems with Google Analytics and jQuery

Its is easy to keep churning out articles and watch your hit count steadily increase but how do you know if you've really helped a developer solve a real world problem? In this article we explore how to create a client-side solution using Google Analytics and jQuery to track if the visitors problem has been solved.

Introduction

So you have published some articles on your blog, added Google Analytics, even implemented depth tracking to see if your readers are scrolling all the way down through your article but how do you know if your advice has solved the readers problem?

In this article we are going to implement a simple widget style application which will ask the users a simple yes / no question: "Did this article solve your problem?".

Its UI will look like the screenshot below, but you can easily amend the code for this to suit your particular blog theme:

was-your-problem-solved-by-this-article-ui

I say "widget style" because we aren't going to program against any particular widget API - in fact this feature could be implemented with the same technique on any blogging or CMS platform which runs on any language. All of the code lives on the client-side: HTML, CSS, and JavaScript.

Clicking either yes or no will simply show a thank you message and invite further feedback via the existing comments form on the blog.

While the comments form already allows this kind of feedback to be collected it normally involves registration / logging in and is more effort to type out than simply clicking this form. If your article hasn't solved the persons problem then you might find they are even less inclined to go through this process.

Also from your point of view you cannot integrate your comments form into your Google Analytics reports.

So to summarise, providing a simple Yes / No form gives an easy way to collect a valuable indicator of whether your article is actually helping anyone without:

  • Requiring the user to login / register
  • Appearing to be aggressive or negative
  • Being a target of spammers attention

The UI itself is very simple, comprising only of html and css markup. This is so that you can implement this on your own hosted blog solution without needing extra hosting space to store image files.

Implementation Overview

The other articles in this series have built upon a simple framework which I have continued with here. The first method, SetupGoogleAnalyticsTrackEvents, is simply a placeholder method which separates your Analytics code from the rest of your JavaScript code.

If you want to integrate this into a real world website, using other Google Analytics enhancements such as scroll depth tracking, pdf downloads, image enlargement tracking and other non-analytics JavaScript code then you will soon see that partitioning your methods in this way keeps things clean.

The HTML mark-up simply sets up two links with some CSS styling and an extra div to say thank you. We then use jQuery to attach a click handler to each of the yes/no links and pass that response on to Google Analytics using the _trackEvent feature. The users response (problem solved / not solved) and the current url are both recorded so you can monitor which of your articles are really helping people and which are falling short.

Markup and Styling

As I have already mentioned the UI consists of a container div, a yes link, a no link and a panel which is displayed afterwards to thank the user for their feedback. I have written it like this:

<div id="WasProblemSolvedPanel" style="display: none;">
  <h2>Was your problem solved by this article?</h2>
  <div id="WasProblemSolvedLinkPanel">
     <a id="ProblemSolved" href="#" class="ButtonPane Yes">Yes</a>
     <a id="ProblemNotSolved" href="#" class="ButtonPane No">No</a>
     <div style="clear: both;"></div>
  </div>
  <div style="display: none;" id="WasProblemSolvedThanksPanel">
     <p>Thank you for clicking!</p>
     <p>If you have additional feedback please use the <a href="#comments">comment form</a>.</p>
  </div>
</div>

The main container div has an inline "display: none" style on it. This is because the entire feature depends on JavaScript for it to work. To make sure this isn't displayed on browsers that don't have JavaScript enabled it's hidden by default. When the jQuery code is run to set this feature up it will unhide this panel. If the user has JavaScript disabled it will stay hidden.

The thanks panel is also hidden at the start, showing only the Yes / No buttons to the user. You should customise the message in the WasProblemSolvedThanksPanel panel to your own liking. The link to #comments is specific to Blogger so if you're implementing this on a different blog you might have to change this link.

The styling is straightforward:

<style type='text/css'>
    #WasProblemSolvedLinkPanel .ButtonPane
    {
        float: left;
        display: block;
        width: 49%;
        text-align: center;
        line-height: 3em;
    }
        
    #WasProblemSolvedLinkPanel #ProblemSolved
    {
        font-size: 2em;
        margin-right: 3px;
    }
        
    #WasProblemSolvedPanel .Yes
    {
        background-color: #ccff99;
        border: 1px solid #336600;            
    }
        
    #WasProblemSolvedPanel .No
    {
        background-color: #ffcccc;
        border: 1px solid #ff0000;
    }
        
    #WasProblemSolvedLinkPanel #ProblemNotSolved
    {
        font-size: 2em;            
    }
        
    #WasProblemSolvedThanksPanel
    {
        height: 4em;
        text-align: center;
    }
</style>

Again, as I stated at the start of this article the CSS has been kept simple and doesn't rely on any external graphics files for its UI. This means that it can be easily implemented on any hosted blogging platform without needing additional hosting. You can easily change the mark-up and styling in this section if you want to add some additional flair for your own implementation of this feature.

jQuery code

<script type='text/javascript'>
/* <![CDATA[ */
    $(document).ready(function () {
        SetupGoogleAnalyticsTrackEvents();
    });

    function SetupGoogleAnalyticsTrackEvents()
    {
        TrackEventsForWasProblemSolved();
    }

    function TrackEventsForWasProblemSolved()
    {
        $("#WasProblemSolvedPanel").show();

        $("#ProblemSolved").click(function(e){
            e.preventDefault();
            WasProblemSolvedClick("Yes");
        });

        $("#ProblemNotSolved").click(function(e){
            e.preventDefault();
            WasProblemSolvedClick("No");
        });
    }

    function WasProblemSolvedClick(answer)
    {
        TrackEvent("Was Problem Solved?", answer, document.location.href);
        $("#WasProblemSolvedLinkPanel").hide("fast");
        $("#WasProblemSolvedThanksPanel").addClass(answer);
        $("#WasProblemSolvedThanksPanel").show("fast");
    }

    function TrackEvent(Category, Action, Label)
    {
        _gaq.push(["_trackEvent", Category, Action, Label]);
    }     
/* ]]> */
</script>

This code follows a simple framework so that if you want to implement all of the analytics tutorials on this blog then they will all naturally fit together inside the SetupGoogleAnalyticsTrackEvents() function.

For example, my real method currently looks like this (don't copy and paste this if you are just following this tutorial, its just to show how they all fit together):

function SetupGoogleAnalyticsTrackEvents()
{
    TrackEventsForCodeSampleDownloads();
    TrackEventsForImageClicks();
    TrackEventsForMinimumPageScroll();
    TrackEventsForWasProblemSolved();
}

The first thing this code does is to find the WasProblemSolvedPanel and .show() it. This is how the feature is hidden to non-JavaScript visitors.

After that we hang click() events off of each of the Yes / No links:

$("#ProblemSolved").click(function(e){
    e.preventDefault();
    WasProblemSolvedClick("Yes");
});

You will notice that rather than passing an empty function I have added the e parameter. Then in the first line I call e.preventDefault(); This is a way to stop the browser from actually trying to visit the href in the <a> tag. In this case the <a> tag simply points to a #. We don't want the browser to try to visit that because the visitor would be jumped up to the top of the page and would miss the "thank you" feedback panel.

Both the Yes and No links basically perform the same task, they just pass a different value back to Google Analytics. When I had initially completed this code I went back and applied the DRY principle - Don't Repeat Yourself - and combined the duplicated code into a function called WasProblemSolvedClick(answer).

function WasProblemSolvedClick(answer)
{
    TrackEvent("Was Problem Solved?", answer, document.location.href);
    $("#WasProblemSolvedLinkPanel").hide("fast");
    $("#WasProblemSolvedThanksPanel").addClass(answer);
    $("#WasProblemSolvedThanksPanel").show("fast");
}

This method passes the feedback to Google Analytics and then swaps out the UI to hide the button and show the thank you message.

Google Analytics Seam

One thing you should try to do when implementing third party libraries into your own code is to keep them isolated as much as possible. A particularly effective technique for this is to create a seam; a wrapper around any code that calls the library. Then when you need to use that 3rd party library throughout your code you call your own methods which you have control over.

The Google Analytics tutorials on this site are all relatively simple and comprise only about 100 lines of code combined but real world apps are much larger than this. However, having said that, we have already seen the benefit of this technique pay dividends. The Google Analytics team have released new versions of their API several times now and have completely changed the way their API works more than once.

This has happened since I started writing the articles on this site and when it was time to update my blog to support this new API I had to change 1 single line of code rather than picking through every line and updating it.

There are other benefits to putting the extra effort in to isolate your 3rd party code with seams. If you use Test Driven Development techniques then you will already see that it would be easier to write tests against code like this. It also reduces your dependency on one specific vendor. Should the 3rd party vendor raise prices too high, go out of business or discontinue the product you are protected against your dependency on their code.

Our Google Analytics seam now uses the new _gaq object instead of the pageTracker object in the previous version and looks like this:

function TrackEvent(Category, Action, Label)
{
    _gaq.push(["_trackEvent", Category, Action, Label]);
} 

Old Google Analytics Code

The new Google Analytics code sits just before the </head> tag and uses the _gaq object.

The previous Google Analytics code sits just before the </body> tag and uses the pageTracker object.

If your Google Analytics is still using the older version and you don't have control over upgrading you can use the following TrackEvent function instead:

function TrackEvent(Category, Action, Label)
{
   pageTracker._trackEvent(Category, Action, Label);
}

Blogger Widget

As I have mentioned throughout this article I am currently using Blogger as my platform. Setting this up in the blogger template was a bit more tricky than I expected so I'm going to cover it briefly in this section.

This doesn't mean however that you have to use Blogger for this code to work. You can put this into any platform you like, the only challenge that faces you is adding into the relevant platforms article template. Despite this primarily being an asp.net blog you could even integrate this into a php powered blog.

I implemented this into Blogger by going to the admin panel of my blog, clicking the Design tab, then Edit HTML. I added all of the JavaScript and CSS styles into the <head> tag and pressed save.

I then clicked on the Page Elements and selected "Add a Gadget" in the main Blog Posts column of the design. I chose the type HTML/JavaScript and pasted the html mark up into the content field of this section. Leave the Title field empty and press save.

The tricky part is that now your "Was Problem Solved" panel is displayed on EVERY page of the blog - the main index page, search results, tag indexes, the works. Blogger supports a special language called GML which you can use to modify the template. You can use some GML mark-up to insert a conditional that only shows the widget on article pages.

Click the Design tab. Click Edit HTML menu option. Tick "Expand Widget Templates" checkbox. This will reveal all of the various GML tags that are mostly hidden from you during normal use. I cannot tell you exactly where to add this code because it will depend on your template.

Basically each of your HTML/JavaScript widgets are automatically given a numbered ID such as HTML1, HTML2, HTML3 etc. You will have to scroll down the code until you spot the main blog post template code (it will have things like posted by, timestamp, comments, backlinks etc). Right after that you should find the template for your HTML/JavaScript widget. In my case my widget was the fourth one that I had added to the template so it was called HTML4. It looked like this:

<b:widget id='HTML4' locked='false' title='' type='HTML'>
<b:includable id='main'>
  <!-- only display title if it's non-empty -->
  <b:if cond='data:title != &quot;&quot;'>
    <h2 class='title'><data:title/></h2>
  </b:if>
  <div class='widget-content'>
    <data:content/>
  </div>

  <b:include name='quickedit'/>
</b:includable>
</b:widget>

The trick is to check if the current page the widget is being displayed is of type "item" (a blog post). To do that you need to wrap a <b:if> </b:if> block around the title and contents of your widget. The code should look like this:

<b:widget id='HTML4' locked='false' title='' type='HTML'>
<b:includable id='main'>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
  <b:if cond='data:title != &quot;&quot;'>
    <h2 class='title'><data:title/></h2>
  </b:if>
  <div class='widget-content'>
    <data:content/>
  </div>
  <b:include name='quickedit'/>
</b:if>
</b:includable>
</b:widget>

Click Save Template and you're all done. As a final check I would visit the blog in Firefox and then check the page to see if any JavaScript errors are being thrown at all.

Your visitors can start using the feature right away but don't forget that Google Analytics is not a real-time reporting system. It will be up 24 hours before you start seeing events appear in your Google Analytics account.

Seeing Your Feedback Levels

I know that the Google Analytics team are currently working on a brand new user interface so the exact step by step process below might not work by the time you read this. If should be pretty intuitive to find the Event Tracking section but if not you can always consult Google Analytics help.

  1. Log in to Google Analytics and click into your report so you see the dashboard
  2. Click the Content menu option down the left hand side
  3. Click Event Tracking

All of your custom events will be shown in here.

Conclusion

In this article we have looked at a lightweight solution to asking your readers if a particular article has helped them solve their problem. It is a low-friction interface that does not require the user to type anything out or log-in to use it. The user is invited to use the comments form if they want to provide additional feedback.

The entire feature is implemented client-side in HTML, JavaScript and CSS which means that it is platform agnostic. You could easily implement this in any blogging platform, help desk software, product description pages, faq's, in fact any page that you would like your visitors to easily indicate a yes / no response.

This may have been the first time you have seen the technique of passing a parameter to the click handler in jQuery and using it to prevent the href being visited after the handler code has run.

We have also looked at the technique of using seams in your code to protect you from changes to third party libraries and shown how easy it is to change the seam to support both new and older Google Analytics tracking codes.

This article has added another technique to your arsenal of ways to use the event tracking mechanism of the Google Analytics API. If this is your first Google Analytics article on this site then check out the Further Reading section below to see more Google Analytics API tutorials.

Further Reading

kick it Shout it

No comments:


-->