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.
- Capture data by users from abandoned forms
- Push that data into Omniture SiteCatalyst
- Create a report with real, actionable data on form abandonment
- ColdFusion 8
- Client Variables stored in a database (SQL)
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:
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
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, cd.data, cg.lvisit from CDATA as cd join CGLOBAL as cg on cd.cfid = cg.cfid where cg.lvisit >= (your timeframe here ) and cd.data 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, cd.data, cg.lvisit from CDATA as cd join CGLOBAL as cg on cd.cfid = cg.cfid where cg.lvisit >= GETDATE()-1 and cd.data like 'formprogress%' </cfquery> <cfset variables.wddx2Convert = abandoned.data> <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#","|")> </cfloop>
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.