Chatbots are taking the internet by storm, but let's be honest, they're still not ready for primetime.  While AI based chatbots are impressive, they still have quirks which make them not great for customer facing services.

Still we really like the idea of conversations instead of filling out long, arduous forms.  It's just a more natural way of sharing information.

So we started thinking… what if we could turn our forms into conversations?  Then we could save time on phone calls, capture more leads, and sync everything to our CRM in one fell swoop.

So we created Chattable.

Available chat bot options

Turns out we're not the first developers to think of this…

There are some good options out there for creating non-AI chatbots.  There's even one for doing EXACTLY what we're talking about (turning forms into chatbots in case you haven't been reading).

React Simple Chatbot

This is a great little chatbot that uses JSON to determine steps.  Like the name implies it's simple.

Using this chatbot is definitely an option, but there's a lot of legwork involved in getting it fully parse forms and do what we need.  It's also a little on the heavy side at 171kb minified.

Space10 Conversational Form

This is an awesome plugin.  Download it, throw it in your page, and tell it which form to convert and you're done.

I wanted this one to work, but there were a few problems for our specific use case:

  • No way to customize form parsing, meaning all of our forms must fit their preset HTML layout
  • Using a data tag for the question means we'll have to modify our form's HTML manually every time after they're generated
  • Data tags won't allow us to easily pass HTML to the messages
  • No persisted state means we'll have to come with our own solution if we want forms to remember users

That said, there are a lot of great things about this plugin and it's very well documented.  If you're a developer, it might be worth the time to code up a persisted state option and custom form parser which would resolve the above issues.

The chatbot the internet needs, but not the one it deserves

So we decided to set out to build our own with the primary goals of:

  • JSON based steps
  • Form parsing for any form
  • Persisted state to remember users and user data

Creating a chatbot from a form is easy.  We just initialize and tell it which form to use.

var formSteps = chattable.getStepsFromForm('#my-form');
chattable.init({steps: formSteps});

But there's a whole lot more that goes on behind the scenes and tons of options.

Creating our step schema

We really liked what the React Simple Chatbot brought to the table in terms of simple step design.  A step can have a message, options, trigger another step, or allow for user input.

We can even delay the step from showing or show it as typing for a specific amount of time.

var steps = [
    id: 'first-step',
    message: 'I'm a message from the chattable chat bot.',
    id: 'second-step',
    message: 'This step allows user text input.',
    userInput: true,
    id: 'third-step',
    message: 'This step has selectable options.',
    options: [
        label: 'Option 1',
        value: 'option1'
        label: 'Option 2',
        value: 'option2'
    id: 'fourth-step',
    message: 'This step is delayed for 3 seconds and types for a duration of 2 seconds.',
    delay: 3000,
    duration: 2000

We added callbacks and validation along with easy error handling to make the experience feel more like a conversation.

    id: 'first-step',
    userInput: true,
    validate: function(userInput) {
      if (userInput.value.trim() === 'yes') {
        return true
    callback: function(step, userInput) {
      alert('You did it!')
    invalidMessage: 'Please type "yes" to continue.'

Now instead of validating at the input box, the user input is added like a normal message and validation appears as part of the conversation, making this a more fluid experience.

Parsing Forms

Now that have our basic functionality in place for steps, we just need a way to convert our forms into steps.  But some people use Bootstrap, WordPress users might use Contact Form 7, others might just hand-write their HTML forms.

Chattable's form parser handles this with minimal opinion on how your form is structured.  The only real requirements are that you wrap your inputs and messages in a group of some kind.

So here's our default layout for a form (very Bootstrap-esque):

    <form id="my-form">
      <div class="form-group">
        <div class="message">What's your name?</div>
        <input type="text" name="myInput" />
        <div class="error-message">I'm shown if validation fails</div>
      <div class="form-group">
        <div class="message">Here are some options:</div>
        <label><input type="radio" name="myRadio" value="option1" /> Option 1</label>
        <label><input type="radio" name="myRadio" value="option2" /> Option 2</label>

To parse into steps automatically, we just use Chattable's getStepsFromForm function and voila, we have steps.

var formSelector = '#my-form',
formGroupSelector = '.form-group',
formLabelSelector = '.message',
formInputSelector = 'input',
formInvalidMessageSelector = '.error-message',
formSubmitCallback = function() {
  // Called at the end of all form steps
  var form = document.querySelector(formSelector);
validateInput = function(input) {
  // The input node is passed here to perform custom validation
  return true;
var formSteps = chattable.getStepsFromForm(formSelector, formGroupSelector, formLabelSelector, formInputSelector, formInvalidMessageSelector, formSubmitCallback, validateInput);

But we actually use Mautic for our forms, which looks a little different.  Our form structure is more or less like this:

<form class="bot-form" autocomplete="false" role="form" method="post" id="mauticform_myform"  data-mautic-form="myform" enctype="multipart/form-data">
    <div class="mauticform-error" id="mauticform_myform_error"></div>
    <div class="mauticform-message" id="mauticform_myform_message"></div>
    <div class="mauticform-innerform">
    <div class="mauticform-page-wrapper mauticform-page-1" data-mautic-form-page="1">
        <div id="my-field1"  class="mauticform-row mauticform-radiogrp mauticform-field-1">
            <label  class="mauticform-label" for="mauticform_radiogrp_radio_candy_Sure1">Candy</label>
            <span class="mauticform-helpmessage">Do you like candy?</span>
            <div class="mauticform-radiogrp-row">
                <label id="mauticform_radiogrp_label_candy_yes0" for="mauticform_radiogrp_radio_candy_yes0"  class="mauticform-radiogrp-label">
                    <input  name="mauticform[candy]" class="mauticform-radiogrp-radio" name="mauticform[candy]" id="mauticform_radiogrp_radio_candy_yes0" type="radio" value="yes" data-trigger="mauticform_myform_name" />
                    Of course!
            <div class="mauticform-radiogrp-row">
                <label id="mauticform_radiogrp_label_candy_no1" for="mauticform_radiogrp_radio_candy_no1"  class="mauticform-radiogrp-label">
                    <input  name="mauticform[candy]" class="mauticform-radiogrp-radio" name="mauticform[candy]" id="mauticform_radiogrp_radio_candy_no1" type="radio" value="no" />
                    Hate it!
            <span class="mauticform-errormsg" style="display: none;"></span>
        <div id="mauticform_myform_name"  data-validate="name" data-validation-type="name" class="mauticform-row mauticform-name mauticform-field-2 mauticform-required">
            <label id="mauticform_label_myform_name" for="mauticform_input_myform_name" class="mauticform-label">Name</label>
            <span class="mauticform-helpmessage">What's your name?</span>
            <input id="mauticform_input_myform_name" name="mauticform[name]" value="" class="mauticform-input" type="name" />
            <span class="mauticform-errormsg" style="display: none;">You don't have a name?!</span>

A lot more complicated, right?

Luckily, our form parser can handle that too.  We just need to find the classes for our groups and messages and switch them out from above and we're done.

var formSelector = '.bot-form',
formGroupSelector = '.mauticform-row',
formLabelSelector = '.mauticform-helpmessage',
formInputSelector = 'input',
formInvalidMessageSelector = '.mauticform-errormsg',

Remembering users

Showing the same messages or steps repeatedly to users is annoying.  That's where state persistence comes in.  It let's us capture the exact state the chatbot was in when the user left the page.

This can carry across multiple pages:

  persistedState: 'my-key',
  steps: formSteps

Be specific to different forms:

form = document.querySelector('#bot-form-1')
  steps: formSteps

Or be turned off altogether:

  persistedState: false,
  steps: formSteps


Wrapping up

Forms suck.  Hopefully this is a step in the right direction for making the web a better place for customers and businesses, but time will tell.

My prediction is that machine learning AI will eventually catch up and become a mainstay for businesses.  In the meantime, we'll stick to our tried and trusted forms with a bit of a modern twist.

Give Chattable a shot if you like (it's completely open source and free :)).  Let us know what you think and what features you'd like to see.