Imarc

Some handy tricks for Marketo Forms JavaScript API

Tristan Norton, Front-end Engineer
Posted on Sep 28, 2020

Here’s how to extend Marketo forms beyond their native functionality using the Forms API.

If you’re reading this, chances are you’re pretty familiar with Marketo. If not, here are the basics: Marketo is a marketing (go figure) service that provides tools for businesses to nurture their leads and build marketing campaigns. One of the tools they provide allows businesses to build forms that they can apply to their website and direct leads right to Marketo. For those who like to get a bit deeper under the hood, there are ways to extend these forms to adhere to particular site requirements.

When to use the JavaScript API

Before I get into the cool things you can do with the Marketo Forms API, it should be noted that you should first try to utilize native Marketo functionality. Marketo embed forms are highly configurable from the design studio. This includes lead recognition, redirect URLs, and form layout.

Even with how configurable Marketo is, its out-of-the-box functionality may not satisfy the needs you have. This is where Marketo’s JavaScript API comes in handy. Using a series of lifecycle callbacks, we can hook on to a form, access its various properties/methods, and even do some fancy DOM manipulation.

In the following examples, I’ll walk through a few tricks I’ve personally used to help adapt Marketo embed forms to a website’s requirements. The forms API uses jQuery, so we will use jQuery on the rest of our code for consistency. There are situations where it might not be advisable to use jQuery, for example, if you’re using another framework like Vue.

In the following code samples, you’ll see places where I’ve indicated values with double curly braces. In your code, you’ll need to fill these in with the appropriate account and form IDs either programmatically or manually.

Lazyload the Marketo Form API

Marketo’s form embeds require their JavaScript API. Requesting and subsequently having the browser run this JavaScript can affect page load times. There are many instances where we may not need that resource right away and we can request that JavaScript at a later point, only when we need it.

Example: A contact form at the bottom of a page

An element of the embed code Marketo provides is the JavaScript file that houses its forms API. It usually looks like this:

// File containing Forms API
<script src="//app-ab24.marketo.com/js/forms2/js/forms2.min.js"></script>


<form id="mktoForm_{{ fromID }}"></form>
<script>MktoForms2.loadForm("//app-ab24.marketo.com", {{ munchkinId }}, {{ formId }});</script>

Let’s take away both script tags and add the form element to our footer.

<footer class="js-footerForm">
    <div class="container">
        <form action="" id="mktoForm__{{ formId }}"></form>
    </div>
</footer>

Now for some custom JavaScript. For our example, we’ll be using a popular library called Waypoints which will handle all our in-scroll events.

const waypoint = $('.js-footerForm').waypoint({
    handler() {
        /* Let's load a form! */
    }
})

Next, let’s create a function to load our form once the Forms API has been loaded. Notice how we’re calling Waypoints’ destroy method so that the handler only fires once to load the form.

const loadForm = () => {
    MktoForms2.loadForm('//app-ab24.marketo.com', {{ munchkinId }}, {{ formId }})
    this.destroy()
}

const waypoint = $('.js-footerForm').waypoint({
    handler() {
        /* Let's load a form! */
    }
})

Finally, let’s request the JavaScript containing the Forms API and load our form. Here, I’m taking special care to check if the forms API already exists, so we can avoid reloading assets the browser already has.

const loadForm = () => {
    MktoForms2.loadForm('//app-ab24.marketo.com', {{ munchkinId }}, {{ formId }})
    this.destroy()
}

const waypoint = $('.js-footerForm').waypoint({
    handler() {
        if (typeof MktoForms2 === 'undefined') {
          $.getScript('https://app-ab24.marketo.com/js/forms2/js/forms2.min.js')
                .done(loadForm)
        } else {
            loadForm()
        }
    }
})

Field-specific container modifiers

It’s almost required at this point to have a wrapping element around a form field to style it in a modern way. Marketo has a wrapping element with a class of “mktoFieldWrap”, but nothing specific about what kind of form element is inside it. Having input element-specific classes on wrapping elements allows more freedom in how we style inputs, especially elements like selects or radios that require a little more complexity outside of the input itself to customize.

I’ve used this snippet which I include in any site that uses Marketo.

const applyCustomModifiers = form => {
    const $form = form.getFormElem()
    const $fieldWrappers = $form.find('.mktoFieldWrap')

    $fieldWrappers.each((index, element) => {
        const $fieldWrapper = $(element);
        const $input = $fieldWrapper.find('input')
        const $select = $fieldWrapper.find('select')

        if ($select.length) {
            $fieldWrapper.addClass('-select')
        }

        if ($input.length) {
            const inputType = $input.attr('type')

            $fieldWrapper.addClass(`-${inputType}`)
        }
    })
}
  
if (typeof MktoForms2 !== 'undefined') {
    MktoForms2.whenReady(applyCustomModifiers)
}

Now, all Marketo field wrappers will have their specific input types applied as modifiers.

Example:

<div class="mktoFieldWrap mktoRequiredField -checkbox">
    <label class="mktoLabel mktoHasWidth">
        Agree
    </label>
    <div class="mktoGutter mktoHasWidth"></div>
    <div class="mktoLogicalField mktoCheckboxList">
        <input type="checkbox">
    </div>
</div>

NOTE: If you’re lazyloading the form assets like in the previous tip, you’ll need to use the fourth callback argument in the “loadForm” method (see our post on lazyloading third party scripts):

MktoForms2.loadForm("//app-ab24.marketo.com", {{ munchkinId }}, {{ formId}}, applyCustomModifiers)

Personalized success messaging

There are times when we don’t want the user to go to a new page when successfully submitting a form. Instead, we display an in-line success message, personalize it, and let the user continue browsing the remainder of the page.

To start, let’s hook on to the success handler of the form object, grab the form element that’s wrapped in a jQuery object, and have it return false in the callback. This prevents the default submission follow-up handling and allows us to create some custom behavior instead.

if (typeof MktoForms2 !== 'undefined') {
    MktoForms2.whenReady(function (form) {
        form.onSuccess(values => {
            const $formElement = form.getFormElem() // jQuery form element

            return false
        })
    })
}

Now, let’s assume this was a basic form where one of the fields is the first name. The form object’s onSuccess handler passes the submitted values object as an argument in its callback.

We can use this object to display a personalized success message.

if (typeof MktoForms2 !== 'undefined') {
    MktoForms2.whenReady(function (form) {
        const $form = form.getFormElem()

        form.onSuccess(values => {
            const { FirstName } = values
            const $successMessage = $(`
                <div class="successMessage">
                    <p>Thank you ${FirstName}!</p>
                    <p>We will be in touch shortly to talk to you about our product.<p>
                </div>
            `);

            return false
        })
    })
}

Finally, let’s populate the message and hide the form.

if (typeof MktoForms2 !== 'undefined') {
    MktoForms2.whenReady(function (form) {
        const $form = form.getFormElem()

        form.onSuccess(values => {
            const { FirstName } = values
            const $successMessage = $(`
                <div class="successMessage">
                    <p>Thank you ${FirstName}!</p>
                    <p>We will be in touch shortly to talk to you about our product.<p>
                </div>
            `);
            
            $form.after($successMessage)
            $form.hide()

            return false
        })
    })
}

Make form embeds work for you

This barely scratches the surface of what you can do. You could write your own custom form validation, or perhaps you could be as bold as to wrap all your custom handling in a neat and tidy React or Vue component. You can find out about everything that’s available in the Forms API here.

As I mentioned from the start, try to use native functionality that Marketo offers. If it’s only getting you so far, the Forms API can help fill the gap.

Do you have a form question, or are you wondering how your site can optimize forms? Let’s talk!