As I described in my previous post ‘Landing Pages and Forms: Definition and Requirements‘ the forms feature of Emarsys is not perfect. I also highlighted that many customers have their own content management system they want to use for landing pages and just need a simple way of embedding forms.
In this article I describe how this could be achieved (including progressive profiling) with some custom code using node.js, javascript and CSS.
As a starting point I accepted the fact that customers will use their CMS of choice. With this in mind I needed to find an easy way for campaign or content managers to embed a form on any page. Since most CMS offer a way to include a custom HTML block I had the idea to offer a simple snippet with a minimum set of parameters:
<div id="ems-form" fields="1,2,3*" button="Register Now!" eventID="24606"></div>
A javascript program which has to be installed somewhere in the CMS then would find the snippet with the ID “ems-form” and evaluates the rest of the parameters:
The form code is then generated at the same location as the snippet. If the page is called with the URL parameter ‘UID’ and the UID value of an existing contact then all fields are pre-filled with existing values where possible by calling the Emarsys API. Upon press of the button the contact is updated or created in Emarsys and an external event ist created for that contact via API.
There is also a CSS file which is installed on the CMS which contains the basic styling. If you need to adapt some styling specifically to your page you can just append it at the end of your snippet. For example to change the button color:
<div id="ems-form" fields="1,2,3*" button="Register Now!" eventID="24606"></div>
<style>
#ems-form button {background-color: darkcyan;}
</style>
There are 2 issues when you want to call the Emarsys API from Javascript code within any web page:
The solution for this is a proxy server where you set the response headers so that the CORS issue is resolved. Additionally you specify certain endpoints including authorization that are needed for the form communication (and only those). Additionally some way of rate-limiting should be implemented against denial of service attacks.
While the basic setup of the snippet already facilitates a lot of simple use cases like for example newsletter subscriptions or download requests I found a lot of more complex use cases for which I added additional optional features. In many cases there are already default parameter values in the javascript coding which can be adapted centrally so that the end user only has to provide them if needed.
While many fields already have a good text returned from the API some label text might not be sufficient. For example, the text for the email opt-in is just ‘Opt-In‘. Usually you want to give the visitor of the landing page a better description of what that flag means like: ‘Please send me regular product information via email.‘
So I added a generic parameter with the prefix ‘label_‘ followed by the ID of the field. This will overwrite the default label text. In my example this looks like:
<div id="ems-form"
fields="3*,31"
label_31="Please send me regular product information via email."
button="Register Now!"
eventID="24606"
></div>
Additional parameters to control the button and submit behavior:
<div id="ems-form"
fields="1,2,3*"
button="Register Now!"
keepButtonAfterSubmit
success="Thank you!"
error="Oh, very sorry - something went wrong!"
eventID="24606"
></div>
This is a method to continuously increase the information you have for an any given contact but not overloading the forms with a high number of fields which usually leads to a low submit rate. The concept here is to define a list of wanted fields in a ranked order. After loading the landing page and before displaying the form the system checks on the first field and if that field is not known for that contact the field is added to the form. Then it continues with the next fields in line until a maximum number of progressive fields is reached. These are the new or enhanced parameters:
<div id="ems-form"
fields="?,31"
progressive="3*,1,2,46,14,5,37,10,11"
progressive-max="2"
button="Register Now!"
eventID="24606"
></div>
Since you probably already use personalization tokens in your emails which include a link to your landing pages it would be good to have those inside your landing page as well. That way you can continue your personalized conversation with your contact on the landing page.
I decided to build a simplified but similar version of the ESL which you already know from the Emarsys email content.
Examples:
{{Dear contact.1|Invitation}}
{{A confirmation will be sent to contact.3 after your registration}}
success="Thank you{{, contact.1}}!"
Sometimes you’ll want to have a lot of fields on your form, for example if you use the form as a profile page (See respective use case in the demo section). For such cases I added the snippet parameter ‘flex‘ which will result in a 2-column layout of the fields with the following exceptions:
Of course this can be adjusted by editing the CSS file for the forms.
I encountered 2 use cases which I could enable by introducing custom form templates:
To enable these templates you need to include another DIV element inside the snippet DIV with the ID ’ems-form-templates’ and the style ‘display:none’. Then you can add any number of HTML elements below with a unique ID like ‘t1’ or ‘e1’. Additionally you need to embed these IDs inside the fields parameter. If you want to add a field for the data section of the external event then you need to give it an ID and name starting with ‘event_’.
The example below first adds a sub-title ‘Personal Data’ followed by a maximum of 2 progressive fields. Then it adds another sub-title ‘Additional Data’ followed by a field labeled ‘Additional Field 1’:
<div id="ems-form"
fields="t1,?,t2,e1"
progressive-max="2"
button="Register Now!"
eventID="29670" >
<!-- Form Templates -->
<div id="ems-form-templates" style="display: none">
<h3 id="t1">Personal Data</h3>
<h3 id="t2">Additional Data</h3>
<div id="e1" class="form-input">
<label for="event_field1">Additional Field 1</label>
<input id="event_field1" name="event_field1">
</div>
</div>
</div>
After submitting the form the external event will have the following data section:
"data": {"field1": "YOUR-INPUT-IN-THE-FORM"}
Here are the main components:
To create my PoC I chose WordPress as a CMS system with some plugins (No endorsement intended):
Just to show the bare minimum scenario here is a very simple snippet for a form aimed at new customer acquisition:
<div id="ems-form"
fields="1,2,3*"
button="Register Now!"
eventID="24606"
></div>
Below you see the content in editor mode with the snippet section active (purple frame on the right side). To the left you see the editor with the form snippet. Note that there is also a visual indication of a form in the content area.
This is what an anonymous visitor will see:
In a more useful variant you would also include progressive profiling and page personalization. The snippet looks like this:
<div id="ems-form"
fields="?"
progressive-max="2"
button="Register Now!"
eventID="24606"
></div>
And here is the page editor:
This is what an anonymous visitor will see:
And here you see an example of a known visitor. The default progressive field list is ‘3*,1,2,46,14,5,37,10,11’. Since the email address, first and last name are already known the system chooses the salutation (ID=46) and country/region (ID=14). Also please note the personalized text on the left side of the page:
In this example of a profile page you see several other parameters in action: The flex-based multi-column layout, the label overwrite and changes on button behavior:
<div id="ems-form"
flex
fields="3*,46,1,2,14,4,37,90090,10,31,4529"
label_31="Email Opt-In"
Button="Save your data"
keepButtonAfterSubmit
success="Thank you{{ contact.1}}, your changes have been saved."
error="Sorry{{ contact.1}}, something went wrong - please try again later.">
</div>
Here is the page editor again:
And this is the page after a successful submit:
This is a more complex scenario which also includes an automation program on Emarsys side to react on the external event created by the form including decisions based on data of the external event. I will not describe the whole process in detail but to give you more context I give you a short outline:
Below you see the form snippet which includes several additional form templates:
<div id="ems-form"
eventID="29670"
fields="t1,?,t2,e1,90090,e2,t3,31,4529"
progressive-max="2"
label_31="Please send me regular product information via email."
label_4529="Please notify me via SMS on important product updates."
button="Register Now!"
keepButtonAfterSubmit
success="Thank you{{ contact.1}}!"
>
<div id="ems-form-templates" style="display: none">
<h3 id="t1">Personal Data</h3>
<h3 id="t2">Event Data</h3>
<h3 id="t3">Permissions</h3>
<div id="e1" class="form-input">
<label for="event_conference">
Conference Location and Date
</label>
<select id="event_conference" name="event_conference" required>
<option></option>
<option value="2023-05-04_SFR">
🇺🇸 San Francisco (May 4, 2023)
</option>
<option value="2023-06-08_LON">
🇬🇧 London (June 8, 2023)
</option>
<option value="2023-07-11_SIN">
🇸🇬 Singapore (July 11, 2023)
</option>
<option style="background: #c9c9c9; font-size: 0.1px;" disabled>
----------------------------
</option>
<option value="CANCEL">
⛔ Cancel all Registrations
</option>
</select>
</div>
<div id="e2" class="form-input" style="margin-top: 10px">
<table class="checkboxTable">
<tbody>
<tr>
<td class="checkboxColumn">
<input type="checkbox" id="event_conferenceAppointment" name="event_conferenceAppointment">
</td>
<td>
<label for="event_conferenceAppointment">I would like to schedule an expert appointment.</label>
</td>
</tr>
</tbody>
</table>
</div>
</div>
Here you see the page editor
And this is the page for a known visitor:
And to complete the story here you see examples of the emails. I used the following elements to personalize based on the event payload:
{% if event.conference == "2023-05-04_SFR" %}
in San Franzisko on May 4, 2023
{% elseif event.conference == "2023-06-08_LON" %}
in London on June 8, 2023
{% elseif event.conference == "2023-07-11_SIN" %}
in Singapore on July 11, 2023
{% endif %}
<!-- {% if event.conferenceAppointment == "true" %} -->
<tr e-repeatable-item>
...
</tr>
<!-- {% endif %} -->
Note that I also used on-behalf personalization with data from the sales rep responsible for Jenny’s company (See SAP Emarsys Account Engagement Add-On).Here you see the tasks in SAP Sales Cloud:
And finally a glimpse of the automation program involved:
So, where is the code? I was thinking to provide my current code here as well but it is not yet in the state in which I can present it. I would need to do some clean up and insert a lot more comments. So I rather wait for some feedback and decide later if I will put something out for the community.
If I will post something like that it would of course come with a BIG disclaimer 😉
After reading this post you should be able to understand my concept of a snippet-based form for Emarsys and hopefully provide feedback on it.
I am aware that the coding might be intimidating for an end user, especially for the more complex use cases. But an administrator could provide some predefined snippets just for copy and paste to make it easier. Maybe some CMS might also have the option to prepare specific building blocks which could be used to hide the code from the user.