Implementing Marketo progressive profiling in Javascript
November 12, 2014
If you’ve used Marketo’s progressive profiling engine, you know it has a bunch of limitations. It:
Doesn’t work between different types of forms. So a user who tells you their job function on a webinar or event registration might not have that auto-filled on a Talk to Sales form.
Is inflexible; all you can do is specify a list of fields you’d like filled in, and how many blank spaces to present at once. That can be frustrating if you’re staging your leads such that you need different amounts of data at each stage, e.g. First, Last and email, then Company, Job Function, Job Title, and Revenue, then Interest.
Only works on Marketo’s hosted landing pages. Some users want more control over their landing pages, are using a CMS that allows for easy form management, or need to ensure proper integration with analytics services, which Marketo doesn’t support.
Fortunately, progressive profiling can be implemented much more flexibly with a bit of Javascript and the Forms 2.0 API.
The code below:
Saves the user’s information in a cookie, locally, and uses that to pre-populate any form on your site with matching field names. (This assumes you are not collecting sensitive information through Marketo, such as a personal mailing address. If so, you probably shouldn’t store this information locally.)
Hides any fields that are already filled in (reducing perceived workload), unless they are textareas, since textareas are also used for comments that should not persist from session to session.
Uses fieldsets, defined in Marketo’s form builder, to break the form up into sections that are displayed on separate visits. This means that if you want to collect information in three stages, for example, you can break your form fields up into three fieldsets, and the user will only see one at a time. If you want a field to show up all the time, don’t put it in a fieldset.
Some notes: The code relies on the extremely useful jQuery Cookie library by Klaus Hartl. This is only the first version, so there are probably bugs and cases I haven’t considered. You’ll need to assign values to marketo_instance_id and formid. On our site, we use CSS so that the fieldset itself doesn’t add additional styling.
The code
Start by loading the form using the typical MktoForms2 methods. Within the load function, define onSubmit so that it grabs all the form values using the .vals() method as soon as a form is submitted (but before success). Remove the formid and munchkinId properties so they don’t interfere with other forms, and store a stringified version of the returned object in a cookie.
MktoForms2.loadForm("//app-abk.marketo.com", marketo_instance_id, formid, function(form){
form.onSubmit(function(){
var vals = form.vals();
delete vals.formid; delete vals.munchkinId;
jQuery.cookie('formdata', JSON.stringify(vals), { expires: 30, path: '/' });
});
});
Next, add some work to happen on the whenReady event, which MktoForms2 fires when a form has been loaded from Marketo and fully rendered. First, check to see if the formdata
cookie exists. If it doesn’t, don’t do anything.
Then grab the formdata cookie, parse the contents into an object, delete the formid and munchkinId again as we did above, just in case, and populate the form using the Marketo vals() function.
MktoForms2.whenReady(function(f) {
if (typeof jQuery.cookie('formdata') == 'undefined') {}
else {
var formdata = jQuery.cookie('formdata');
formdata = JSON.parse(formdata);
delete formdata.formid; delete formdata.munchkinId;
f.vals(formdata);
}
Once the form has been populated with cookie data, hide all the fields that are already complete.
jQuery('fieldset input, fieldset select').each(function(){
if(jQuery(this).val() != '')
{
jQuery(this).closest('.mktoFormRow').hide();
}
});
Finally, look through all the fieldsets. Is any of them completely blank? (We test for this by concatenating the values of all the fields within the fieldset). If yes, remove all the following fieldsets.
for (i = 1; i < jQuery('fieldset').length; i++)
{
if (jQuery('fieldset').eq(i-1).find('input,select').val() == '')
{
jQuery('fieldset').eq(i).remove(); i = 0;
}
}
});
Note that this code doesn’t “count” fields of type textarea
for the calculations of what is blank or what to hide, though it does save the value.
It’s worth considering whether textareas should be treated as other fields are (which is easy to do, just add textarea
where you see input
together with select
, or whether data left in them should not be stored, since it’s usually things like comments which aren’t useful to save. The latter would be harder to do since .vals()
doesn’t give you a way to exclude fields based on type.