Form Abandonment

NOTE: The code samples below are merely a proof of concept. This solution is not actively in place in any production environmetn that I am involved with.

I was talking to a fellow ColdFusion developer about a web site he was working on, specifically a registration form, and what were some of the best practices with form length and such that would facilitate users filling out the form and submitting.   This is a common issue with web sites that will not be going away anytime soon.  In fact the questions he had are the same ones I have seen in dozens of blog posts trying to figure this out.

  • How many questions to put on a form?
  • What type of questions work the best?
  • What question(s) scared off a user and kept them from completing the form?

I know that there are a few “Form Abandonment” plug-ins out there for Omniture and the likes, but from what I’ve seen the data you get is somewhat limited.   If your form has 20 elements on it and the plug-in only lets you know what the last element with focus was, you have to really think about the validity of that data.  How do you know for sure that the user filled out the elements in order?  Did the developer of the form set the tab index correctly?  Did the user glance at the form, click somewhere near the bottom and then bail?  Did the user fill out half the form the shut down the browser?

From my understanding of the tools out there today, you are not able to get accurate answers to the questions above.     However, this is an very interesting problem that got me thinking on how I could leverage ColdFusion to be able to capture and get more meaningful data from the abandoned forms.

The Challenge:

  • Capture data by users from abandoned forms
  • Push that data into Omniture SiteCatalyst
  • Create a report with real, actionable data on form abandonment

The Setup:

  • ColdFusion 8
  • Client Variables stored in a database (SQL)
  • jQuery

Step 1:  Capture the form data

The trick to capturing the data would be to find a way to save the form data in some persistent variable so that the data could be retrieved later.  Right away I thought of the Client Scope .   Then the task was to find a method that could be deployed to multiple forms across a site with minimal re-coding.    For that I wrote this snippet of jQuery:

<script language="JavaScript" type="text/javascript">
// Form Handling/Analysis Test
$('#Form2BeTracked').children().each(function() {
$(this).bind('change',function (event){
$.post("/includes/processFormProgress.cfm", $('#Form2BeTracked').serializeArray() );




This jQuery function simply binds an onChange event to every form on the page it finds with the id: Form2BeTracked.   This is an easy to deploy script site wide and has no impact on the normal form behavior.

The code on the proccessFormProgress.cfm is all of 3 lines :

<cfparam name="client.formProgress" default="#session.cfid##session.cftoken#">
<cfwddx action="cfml2wddx" input="#form#" output="wddxSession">
<cfset client.formProgress = wddxSession>

This code takes the entire Form Struct and saves it into the client scope/database

Form data is saved real time in the client scope.
Form data is saved real time in the client scope.

The nice part about this is that by default, ColdFusion saves the list of form elements in the form.fieldnames variable. Using that we can get a count of the number of variables for this form, and then see that only 2 of the fields were filled out and what the values of those fields are. All of this without the user clicking submit.

Step 2: Clear data on form submit

If the user submits the form, we need to clear the data in the client variable. This is an easy one line of code to be added on the page that handles the normal submitting of the form.

<cfset client.formProgress = "">

This will clear the form data out of the client variable. This is an important step that can not be skipped or your count of abandoned forms will be inflated.

Step 3: Check for abandoned form data

By saving the form data in the client scope it will be held there in the database for as long as the time frame defined in the ColdFusion Administrator. This setting will determine the frequency that you must check for abandoned form data.

select cd.cfid,, cg.lvisit from
CDATA as cd join CGLOBAL as cg
on cd.cfid = cg.cfid
where cg.lvisit >= (your timeframe here )
and like 'formprogress%'

This should pull a result set with all the records of form data that has been saved. ie. abandoned.


With a little ColdFusion magic

<cfquery name="abandoned" datasource="#REQUEST.dsn#">
	select cd.cfid,, cg.lvisit from 
	CDATA as cd join CGLOBAL as cg
	on cd.cfid = cg.cfid
	where cg.lvisit >= GETDATE()-1
	and like 'formprogress%'  


<cfset variables.wddx2Convert =>
<cfset variables.wddxLen = len(variables.wddx2Convert)>
<cfset variables.wddx2Convert = right(variables.wddx2Convert,variables.wddxLen-13)>
<cfset variables.wddx2Convert = replacenocase("#variables.wddx2Convert#","##","","ALL")>
<cfdump var="#variables.wddx2Convert#">

<cfwddx action="wddx2cfml" input="#variables.wddx2Convert#" output="variables.form">

<cfset variables.formElementList = variables.form["fieldnames"]>
<cfset variables.formElementCount = listlen("#variables.formElementList#")>

<cfset variables.formList = "">
<cfloop list="#variables.formElementList#" index="formItem">
	<cfset variables.tempValue = variables.form["#formItem#"] >
	<cfset variables.valuePair = "#formItem#:#variables.tempValue#">
	<cfset variables.formList = ListAppend(variables.formList,"#variables.valuePair#","|")>

You end up with a variable string that you can then submit to Omniture using the Data Insertion API. See this post on details if the API.


As you can see from the image above, you now have the count of the form elements in the form along with the data values from the form elements that were filled out before the user abandoned the form. With this, you can choose what format would be the most useful for your needs to really dig into abandoned forms.