So, you have a great-looking AJAX website. You’re Zillow, or Google Maps, or whatever. You have a billion visitors, but as a great entrepreneur, you understand that the only way to keep afloat is to give users the features that they want.

How do you do this?

1) Ask your users. Focus groups and similar methods still apply.

2) Talk to your users. Open a blog, get the comments. Put a comment box right there on the website. Have you noticed the “rate this content” concept on MSDN?


Do it.

3) Gather statistics on what users are doing on your site. We’ll be talking about this method in depth here.

You surely noticed that the first two methods require either a major money investment, or proactive users; the vast majority of your users, however, won’t be this “early adopters” crowd, willing to debug your JavaScript and bring you coffee just for making the coolest Ajax app around.

Average users want their problems solved. They don’t want to help you. They want to help themselves. You want to help them, too, but how do you help, if they don’t say what they want?? You track their behavior. You use tracking cookies. You record every single click they make within your application, look through the session information, and research interesting sessions. You personally, the site owner, need to read through these logs to understand what users do in your app.

Let me give you a more concrete feeling of what I’m talking about. Here’s how a sample log excerpt may look like in CocktailBuilder:

  1. Added ingredient “absolut vodka”
  2. Tried to add an ingredient “absinte”, but failed, because there was no match in the database of ingredients.
  3. Added ingredient “orange juice”
  4. Expanded the details for the “melon ball” cocktail
  5. Expanded the details for the “mandarin passion” cocktail
  6. Added the “mandarin passion” cocktail to favorites

This is just like conducting a customer visit: you’re observing the user do their thing. Except that it’s not happening in real-time, and you’re not really seeing a video, but you know your app enough to make sense of it.

Plus, it’s all quantitative, unlike videos: you can make a query such as “how many times in the last month folks tried to add an ingredient, but failed”. Or you can draw conclusions over time, determining whether your efforts to improve the ingredient database is paying off. This, my friends, really is business intelligence for the Ajax world.

How do you set this kind of logging system up? You need to do this by hand; I haven’t seen any good frameworks for this just yet, unfortunately. I told you about my love for Google Analytics – it’s a great product to measure your site-wide performance (i.e. how many visitors came to your site in the last month? which country were they from?), but it’s utterly useless for any kind application usage analysis for Ajax apps (since everything is on the same page, likely, with the same URL). So old-school metrics tools won’t help you, and Apache log files won’t, either.

You need a custom solution. At it’s basis, there are 2 components:

1) A database table that defines the “datapoints” that you want to collect. Sample:


2) Client-side data collection mechanism. Really, just a backlog of things that happened on the client side. Things that may happen are defined in the first step. The backlog will be sent to the server every 5-10 seconds, and when that’s done, the backlog is back to empty.

// submit user actions to the server every X milliseconds
window.setInterval(submitUserActions, 5000); 

function registerUserAction(id, data) {
   userActions[userActions.length] = [id, data];

// Send the usage data back to the server to track what
// the user was doing on the site
function submitUserActions() {
   if (userActions.length > 0) {
        // Ajax call sending userActions to the server

        // We’ve sent the data to the server,
        // so let’s clear the buffer        
        userActions = [];

Every time something interesting happens in the app, I’d just call registerUserAction; for example, when the user is adding an ingredient, I call


Simple, isn’t it?

One question remains: where is the DataPoint array coming from? At some point in the past, I mentioned a technique for generating semi-dynamic content. You’d use just that here: at build time, your script will dump the contents of the datapoints table into a .js file (it would have to do some minimal formatting to be syntactically correct). Then, at runtime, you just include that .js file as you would any other JavaScript resource. Several good things about this approach:

  1. Your code remains readable. You can easily tell that in the code fragment above I was trying to capture the fact that someone entered an ingredient. That fact could have been captured by using the datapoint id (1), not it’s name (ADD_INGREDIENT_BY_NAME). This would have saved us some JS size, but I’ll trade maintainability for download size any day.
  2. It’s really easy to add new datapoints. Just add them to your database table, and code a single registerUserAction() call. Then, at build-time, everything will start working automagically. Again, ease of maintenance.

For dessert, take a look at some reports that I was able to generate from CocktailBuilder usage data. Answering the “how did you make this??” question: these were done using Rico/Prototype and the LiveGridPlus extension. 200 lines of code (PHP, JS, HTML, SQL, all intermingled – yeah, I don’t drink my own Koolaid when I build quick-and-dirty things).

Cocktail Builder: JavaScript Alcoholic