Skip navigation
All Places > New York User Group > Blog
1 2 3 Previous Next

New York User Group

76 posts

Using the Lead ID from Velocity is trickier than you'd expect ($lead.Id is not set automatically, even though there's a {{lead.Id}} token outside VTL).

 

And there are other interesting fields that are handy to have at send time a couple of which aren't accessible any other way, giving Velocity a leg up.

 

Here's a quick snippet that creates a $marketoSend object with properties for Campaign ID, Campaign Run ID, and more:

 

#set( $marketoSend = {} )
#set( $delim = ":|-\d+$" )
#set( $values = $mktmail.xMarketoIdHdr.split($delim) )
## Campaign Run ID not relevant in Preview
#if( $values.size().equals(9) )
#set( $marketoIdKeys = "MunchkinId::CampaignId:StepId::AssetId::CampaignRunId:LeadId" )
#else
#set( $marketoIdKeys = "MunchkinId::CampaignId:StepId::AssetId::LeadId" )
#end
#set( $keys = $marketoIdKeys.split($delim) )
## loop interesting keys
#foreach( $key in $keys )
#if( !$key.isEmpty() )
#set( $marketoSend[$key] = $values[$foreach.index] )
#end
## append Program ID
#set( $marketoSend.ProgramId = $program.values().iterator().next() )
#end
Munchkin ID is ${marketoSend.MunchkinId}
Program ID is ${marketoSend.ProgramId}
Campaign ID is ${marketoSend.CampaignId}
Campaign Run ID is ${marketoSend.CampaignRunId}
Step ID is ${marketoSend.StepId}
Asset ID is ${marketoSend.AssetId}
Lead ID is ${marketoSend.LeadId}


You can then add the variables to a URL (also built in Velocity)

like so:

 

<a href="https://www.example.com/pagename.html?c=${marketoSend.CampaignId}&cr=${marketoSend.CampaignRunId}">Click me</a>

ss

ss

 

Make sense? I'm sure it does.

 

But you might wonder why you can't include the <style>, or a remote <link> for that matter[1] directly in the mktoText area, like so:

 

ss

 

Test and you'll see why Text {{my.tokens}} are necessary.

 

 

Another take

A twist on the same approach gives something superior, if a little strange(r).

 

Set up just 2 tokens, one for opening <style> and one for the closing </style>, at the top level of Marketing Activities. Then you can reuse those tokens everywhere and write CSS directly in the mktoText.

 

ss

ss

 

 

 

 

Notes

[1] You can include a <link> tag in the {{my.token}}, of course. I'm not saying you can't use external stylesheets, just that they need to be passed in via tokens.

Spinning this off the earlier Part I (on number types) because it's an equally important topic.

Not necessarily a rivetingly interesting topic, but since some of you are trying to move into more technical roles, these are good things to know to geek up your conversation. Knowing these things before I became a full-time developer, having learned them on the SQL database side, made coding more comfortable for me.

So: very bad things happen when number field types are used to store values that aren't truly numbers, but actually numeric strings.

What's a numeric string?

Numeric strings are sets of digit characters (0-9) that do not actually represent a single number, or perhaps we could say are not actually equal to their apparent number value.

Those seemed vague, I know. Examples are better teachers…

Credit card numbers are numeric strings

Credit card “numbers” (formally, payment card numbers) are numeric strings. They are a set of independent codes mashed together (MII digit + network number + your number + checksum digit), like:

4110144110144115 
│└───┘└───────┘│

But they do not represent a 16-digit integer: this is not the value 4,110,144,110,144,115 (4 quintillion something) and should never be thought of that way.

Yet some people still ***** up and store CCs as numbers, thinking it'll be more space efficient. It certainly would be — if it worked — since a char(16) takes 16 bytes while a 64-bit int takes only 8 bytes. The ability to reduce your storage requirements by 50% is really tempting. But it's wrong in more ways than one.

The most basic way it's wrong is if you don't actually have a big enough datatype everywhere this value will be used. In the previous post on number types, you saw that the maximum safe value of an SFDC Double is 9,007,199,254,740,991. OK, so 9 quintillion. The above credit card (mis)represented 4 quintillion will fit into that. But what about this card number:

9792004110144115 
│└───┘└───────┘│

Nope! That's outside the Double range. And that's not surprising, as card numbers are not in any way calibrated to fit in a certain data type.

Note I chose a 16-digit credit card number above. In fact, a Visa number, among others, can be 19 digits. So that blows a Double out of the water completely and might make you contemplate a 64-bit Integer (as long as you have end-to-end support for that type). Sorry, won't work either:

9792004110144111248 
│└───┘└──────────┘│

That value, if you attempt to store it as a gigantic integer, won't even fit in a 64-bit int, which has a max value of 9,223,372,036,854,775,807.

James Bond's agent number is an alphanumeric string

While daydreaming about, er, “real-world” examples, 007 came to mind.

 

Read the full post on

I have a need to add disclosures to my forms to be compliant with GDPR in providing information on the use of the data being collected. And going through a developer isn't always ideal as Marketing team and legal may need to update more than once. Also, would prefer to insert on one form used in multiple pages instead of each page. The way I solved it was using a combination of display, :nth-of-type, and order, all CSS that can be done in Marketo.

 

Edit Form > Form Fields > Click Next > Form Themes > Edit Custom CSS

Screen Shot 2018-05-28 at 12.04.28 AM.png

 

1) First, I made all my div rows, columns, and wraps as display: flex so I can use the order attribute later below.

 

.mktoFormRow,

.mktoFormCol,

.mktoFieldWrap {

display: -webkit-flex;

display: -ms-flexbox;

display: flex;

}

 

I need to locate the correct row(that holds the disclosures text) that I'll be using. I placed it above the the button originally but when using progressive profiling it doesn't allow rich text above the button and trying to select the correct row isn't great when a number of fields can show up in progressive profiling depending on the individual, form fields, and setup.

 

Edit Form > Form Fields

 

1.5) So to fix this setback, I just kept the disclosure rich text as the first row on the form. This allows me to know exactly where it is so I can select it.

 

Screen Shot 2018-05-27 at 11.24.31 PM.png

 

2) Second, I give the button row an order.

 

.mktoButtonRow {

  order: 10;

  -webkit-order: 10;

}

 

3) Lastly, I search for my disclosures row with nth-of-type, I know it'll always be the first row(based on step 1.5) and can make the order 11. This will place it below the button(which is 10 from step 2). This should work if you are using progressive profiling or not.

 

form .mktoFormRow:nth-of-type(1) {

order: 11 !important;

-webkit-order: 11 !important;

}

 

Hope the above made sense. You can also use tokens and add them to your program or folder if you'd like to easily make edits through there instead of always needing to go inside the form. The tokens will only work on Marketo landing pages though. You'll have to edit the rich text manually on any form hosted outside of Marketo.

 

Final Result Preview

 

Screen Shot 2018-05-27 at 11.35.16 PM.png

Abacus is a NYC Fintech Startup and we're looking to hire our first Demand Generation Marketing Manager to build out our strategy! If you're interested or know anyone who might be, please apply here: Abacus - Demand Generation Manager

 

About the Role

The Demand Generation Manager is responsible for Abacus’ customer acquisition strategy. You will develop a strategy that focuses on crafting and executing campaigns with the objective of generating high quality sales pipeline that will ultimately contribute to revenue growth for Abacus.

 

The ideal candidate will be a blend of creative and analytical, working alongside our content and business development teams to create attention-grabbing ads, emails and landing pages. Working with marketing and sales operations to track and measure success and ROI. This is a great role for someone looking to hone their strategic skills by developing a fresh demand generation strategy.

 

 

Who is Abacus?

Abacus is reimagining the way businesses move money, starting with the first real time employee expense system. We’re excited about building a solution that is not only effective but enjoyable for everyone to use. Creating the best customer experience drives us - we love hearing everyday how what we're working on is saving our customers time and headaches. Making expense reports obsolete is only the beginning - join a team that is leading the charge in how businesses manage their cash flow. Check us out at abacus.com

After keeping this code close to the vest since 2015 (!), it's time to share the knowledge.

On the Community, I periodically refer to “my method” and to how other all other approaches are horribly hacker-friendly (true!). But I realize it's been a ludicrously slow reveal.

I'm still keeping my advanced method (for those who can't meet the below prerequisites) closed-source, but the simple method here will work for the vast majority of users.

The prerequisites

Here are the prereqs to use the open-source code:

❶ Your external site must share a private parent domain with one of your Marketo instance's LP domains or domain aliases. That is, if your external site is http://www.example.com then you'll need to have (or newly create) a Marketo domain like http://pages.example.com. Those share the private parent example.com.

Such a domain is usually already available. A domain like http://pages.example.info doesn't share a common parent with http://www.example.com so you can't use that. You can either use an existing domain or create an alias for this specific task, so http://special-forms-stuff.example.com is fine to use instead of your primary http://pages.example.com.

If and only if your external site runs over SSL (https://) then the Marketo LP domain must also run over SSL. But there's no requirement in reverse: it's fine if your LP domain runs over SSL but the external site doesn't. And it's also fine if both of them are still plain http://.

❸ Almost not worth mentioning: you need to have a server that can host a single JS file. You can't upload JS to your Marketo file library, because Marketo still (!!!) doesn't serve the .js extension correctly for all browsers. But, pretty much by definition of needing external site pre-fill, you must have another server, right?

 

Read the full post on

When choosing a Thank You/Follow Up URL (wish there were only one term in use!) Form Editor presents 3 largely self-explanatory options:

ss

Choosing Landing Page will give you a nice dropdown of all your approved Marketo LPs.

Choosing External URL and entering the full URL of a Marketo LP seems to work, too — but it's a bad move. Form Editor won't tell you why, but I will.

The problem

If you choose Landing Page or Stay on Page, Marketo uses a special read-your-write feature to ensure Pre-Fill on the next pageview.[1]

If you choose External URL, Marketo looks up the URL in your known LPs but it doesn't look in your Redirect Rules.  If the URL is not seen as a core LP URL, even if it does lead to a Marketo LP in reality, then the read-your-write Pre-Fill cache is not enabled.

What is “read-your-write” and why should I care?

“Read-your-write” or RYW is a desirable, but not always supported, feature of distributed systems. (A distributed system is any system that processes data at multiple tiers, like we all know Marketo does.)

RYW, in a nutshell, means:

If a user thinks they've made a change to the back end, then show them the new data as if it's been fully saved, regardless of whether system(s) may be still filtering and processing — or even discarding! — the data in the background.

It doesn't mean anybody else sees uncommitted data (there are some cases in which it won't be saved, so you don't want to propagate bad info more widely than necessary).

It means that for a less confusing user experience, you let a user see their own requested update immediately, instead of forcing them to see older saved data for a few seconds/minutes (even though showing saved data would technically be more accurate end-to-end).

Marketo implements read-your-write via the special query parameter aliId. It's a numeric identifier for a set of submitted form values, and it's usable regardless of whether the values are actually saved. When a page has an aliId in the URL, it's capable of (for the most potent example) filling a second form using the data from a first form, even if it was submitted mere milliseconds before.

Back to Form Editor

When you choose External URL in Form Editor, Marketo tries to append the aliId intelligently, but it can't know about your redirects (especially 3rd-party redirects) or anything that might disguise the Marketo-ness of the destination URL.  As a result, the next LP someone views may show their session's old data (maybe including someone else's email) or no data at all (the session still being effectively anonymous). You don't want that! So choose Landing Page if it's indeed a Marketo LP.

Other complications

When you use the Forms JS API onSuccess method to choose a Thank You URL dynamically (a very powerful option) set the form to Stay on Page in Form Editor, as this will ensure the aliId is appended.

Then clip out and append the original query string, which will include the aliId, to the dynamic URL.

A quick-and-dirty way to append the original query is like so:

MktoForms2.whenReady(function(form){
  form.onSuccess(function(vals,tyURLFromFormEditor){
    var originalThankYouDoc = document.createElement("a");
    originalThankYouDoc.href = tyURLFromFormEditor;
    
    var dynamicThankYouURL = "https://pages.example.com/other-marketo-lp.html" + 
      originalThankYouDoc.search;
    
    document.location.href = dynamicThankYouURL;
    return false;
  });
});

If you're using a fuller-featured URI parser/builder already, like uri.js, use that instead of the Link/Location method (though the location.search breakdown works perfectly, since it's a key browser function).

Just don't write your own parser… I don't want to have to holler at you again!


NOTES

[1] When you use Stay on Page the aliId is attached even if you're using the form embed and the page is a non-Marketo page. It's not fully honored in this case (since Pre-Fill isn't supported with the embed) but it's better to have it there than not.

You should already know that variables don't work in the Text version of Marketo emails. And you've likely dismissed this as a head-shakingly short-sighted mostly harmless detail.

But it has one wider consequence, as user JK noticed in this Community thread, that's firmly a bug — and one which impacts the email as a whole.

The documented (if suboptimal) behavior

Variables on the Text side are typically replaced with blank output. This can either:

(a) mangle the Text version, if variables happen to contain critical content, or
(b) be fine and dandy, if variables hold colors or other styles that pertain only to the HTML side anyway

Outcome (a) is not great, but at least you know to plan for it.

The undocumented (and bad) behavior

But when a ${variable} is used as a link, like…

<a href="${link}">Click for fun in the sun</a> 

and uses one of the 20 or so Velocity reserved words, ya got problems. Because of the additional layer of processing for links (to be rewritten to the branding/tracking domain) you get everybody's favorite WTF:

ss

And this happens regardless of whether you used any Velocity tokens!

(Of course I mean any userland {{my.tokens}} because Velocity is always used to assemble Marketo emails, even if you don't write any code yourself. Didja know that? Or maybe suspect it?)

Anyway, the solution is to not use any of these words as${variable} names (and tell your template designer, too):

alternator 
class
context
convert
cookies
date
display
esc
field
import
include
link
loop
math
mktEncrypt
my
number
pager
params
render
sorter
text
xml
GENERIC_TOOLS_AVAILABLE
STRUTS_TOOLS_AVAILABLE
TOOLS_VERSION
VIEW_TOOLS_AVAILABLE

And that's about all I have to say about that.

There are 2 ways to access references (i.e. variables) in Velocity.

 

(1) Simple/shorthand notation, prefixed with a $:

 

$variableName
$variable.property
$variable.method()
$variable.property.method()

 

(2) Formal/longhand notation, prefixed with $ and wrapped in {} (curly braces):

 

${variableName}
${variable.property}
${variable.method()}
${variable.property.method()}

 

Simple notation should be your default. Formal notation should only be used when there's no alternative. As the Velocity docs say:

 

In almost all cases you will use the shorthand notation for references, but in some cases the formal notation is required for correct processing.

 

I'd go further: when used unnecessarily, formal notation can make your code confusing and fragile. Unfortunately, Marketo's script editor doesn't help you learn best practices, because when you drag a field from the field tree to the editor canvas, it's automatically  wrapped in ${}:

 

5acbd8e898b1d0002262929b_vtl_formal_scripted.png

You should remove the curly braces right away, and only restore them if it proves necessary during development.

 

What can go wrong?

A recent Community post shows how confusing things can get when you use formal notation unnecessarily (note how the poster titled it "... tokens behave unexpectedly" when it's actually established behavior, if not well-circulated).

 

The catch: a reference enclosed in ${formal.notation} cannot be chained with a method/property outside the curly braces.

 

OK, that probably didn't make sense unless you're fluent in OO-speak! Let's look at some examples.

 

This does work with simple notation:

 

#if( $lead.FirstName.isEmpty() )

 

It doesn't work if you only enclose part of the expression in formal notation:

 

#if( ${lead.FirstName}.isEmpty() )

 

Sure, it would work if you happened to enclose the entire expression in curlies

 

#if( ${lead.FirstName.isEmpty()} )

 

but you should just use simple notation instead, because it's harder to mess up during refactoring.

 

Don't believe me? (You probably do, or I'd like to hear who's more authoritative about Velocity.) Consider what happens when you move from a not-best-practice, but syntax-error-free, comparison using double-equals ==:

 

#(if ${lead.numberOfProducts} == 0 )

 

to a more forward-looking equals():

 

#if( ${lead.numberOfProducts}.equals(0) )

 

Suddenly, your Velocity token stops working because you can't have a . after a }. It may be clear, to you as a human, what you meant, but VTL doesn't allow it. If you'd used simple notation from the start you wouldn't have to make such adjustments.

 

When do you need to go formal?

Formal notation should only be considered inside strings or output, and only used when the separation between variables and static text would otherwise be unclear.

 

If you're in a line of code starting with #if or #set chances are very slim that you should be using formal notation.

 

Here's one case where it is necessary...

 

Read the full post on

You've seen before that the Forms 2.0 input mask plugin can be tweaked to do some more elegant stuff.

Here are a few more things you might want to do. I only recommend masks for things that have an explicit standard (like phone numbers, credit cards, etc.). But if you're going to use them for more than that, use them wisely!

The code is bundled at the bottom of the post.

SUPPRESS THE UNDERSCORE AS THE PLACEHOLDER

By default, the mask shows a _ character in every empty position up to the max length.

This can look ugly, especially if there's already a hint in the field telling people it's limited to N characters.

ss

You can remove the placeholder character entirely or replace it with something else (though I'm not sure anything is better than underscore or blank in this case, maybe a cursor block like ░ if you want to be retro-cool?).

ACCEPT ANY LATIN-1 LETTER, NOT JUST A-Z AND a-z

When you select the a shortcut in the Form Editor…

ss

… you're actually blocking all but the slimmest subset of alphanumeric characters.Even the e-with-acute-accent in Grégoire is blocked! That's not good when words contain these slightly out-of-the-American-ordinary characters.

It works this way because, under the hood, input masks use the regex character class [A-Za-z] to implement a. And that's ASCII unaccented letters only.

The better move is to use a class like [A-Za-z\u00C0-\u024F] which includes Latin accented letters, i.e. those from Romance languages. (You'll still be blocking people who spell their names using other glyphs, but that's another matter.)

Better still, if you're in the world of names, allow hyphens, apostrophes, periods, and spaces: [A-Za-z\u00C0-\u024F'. -].

ALLOW SPACES, NOT JUST CHARACTERS

When you set a mask to **********, even if you don't want non-ASCII, non-accented characters, do you really mean that spaces aren't allowed? Sometimes yes, sometimes no.

In the case of ISBN-10s, for example, no spaces are allowed per the international standard, and you might want to block spaces in the Phone field for standardization.

But in the case of First or Last Name, Company, or tons of other cases, you certainly don't want to block spaces.

MAKE IT HAPPEN

All of the above functions can be enabled with the helper JS below.

First, in Form Editor, give each field you want to re-mask an initial mask (any mask pattern will do). (If it isn't masked to begin with, we can't tweak the mask setup.)

Then add your custom patterns to the inputMasks array as below: the name property is the Marketo form field name and the rest is explained in the comments.

 

(function() {
   MktoForms2.$("body").on("mkto_inputmask_polyfilled", function(e) {
      var inputMasks = [
         {
            name: "Title",
            maskPattern: "ssssssssss", // 10 [A-Za-z ] letters or spaces
            maskCharPlaceholder: "" // no placeholder char
         },
         {
            name: "Nickname",
            maskPattern: "nnnnnnnnn", // 10 [A-Za-z0-9 ] chars or spaces
            maskCharPlaceholder: "" // no placeholder char
         },
         {
            name: "Interest",
            maskPattern: "cccccccccc", // 10 Latin letters or (some) Latin puncuation marks
            maskCharPlaceholder: "░" // alternate placeholder char to show how it's done
         }
      ];

      /* --- NO NEED TO TOUCH BELOW THIS LINE! --- */

      MktoForms2.whenReady(function(form) {
         var maskCharExtensions = {
            c: "[A-Za-z\u00C0-\u024F'. -]",
            s: "[A-Za-z ]",
            n: "[A-Za-z0-9 ]"
         };

         Object.keys(maskCharExtensions)
            .forEach(function(char) {
              MktoForms2.$.mask.definitions[char] = this[char];
         }, maskCharExtensions);

         inputMasks
            .map(function(field) {
               field.el$ = form
                  .getFormElem()
                  .find("[name='" + field.name + "']");
               return field;
            })
            .forEach(function(field) {
               var mask =
                     typeof field.maskPattern != "undefined"
                        ? field.maskPattern
                        : field.el$.data("mktoInputMask"),
                  placeholder =
                     typeof field.maskCharPlaceholder != "undefined"
                        ? field.maskCharPlaceholder
                        : MktoForms2.$.mask.placeholder;

               field.el$.mask(mask, { placeholder: placeholder });
            });
      });
   });
})();

Boolean type fields enjoy a strange place in Marketo's Velocity implementation.

On the Marketo UI side and via most Marketo APIs, Booleans hold consistent true/false values (presumably using SQL bit type fields under the hood).

But in Velocity, as I've explored before, a Boolean field is presented as one of two Strings:

  • "1" for Boolean true
  • "" (empty string) for Boolean false

That conversion is actually really confusing.

See, Velocity inherits a lot of things (variable handling things) from Java.

In Java, a non-null String object, on its own, is always evaluated as Boolean true. Regardless of whether it has any characters in it (that is, regardless of whether it's empty).

So if you do:

#if( $lead.someBooleanField )
Field is true
#else
Field is false
#end

You will always get “Field is true” even if you've unchecked the corresponding checkbox in the Marketo UI.

If Marketo Booleans were Velocity/Java Booleans, on the other hand, this would've worked fine. But alas.

So the question is what to do with these sort-of-Boolean-like-Strings (whose meaning we understand, but the VTL language doesn't). What do we convert them to to make them more usable?

You can do a step-by-step conversion to Boolean by doing a String comparison:

#if(  $lead.someBooleanField.equals("1") )
#set( $lead.someBooleanField == true )
#else
#set( $lead.someBooleanField == false )
#end

After that conversion, #if($field) will work as expected.

But I've been thinking lately that maybe converting those Strings to Numbers — 0for false and 1 for true, as the standard goes — gives us more juice within Velocity than if we were to go with true Booleans.

 

 

Read the full post on TEKNKL :: Blog →

GDPR and related regulations call for some fancy footwork with activity tracking.

 

Leads may be members of the same program, set to receive the same email but many have opted-out of tracking, while the rest agreed to be tracked for the greater good.

So you need a single email to go out, but some get the tracked version of links (bounced off your branding domain) while others get the raw links (straight to the URL). Same for the <img> that tracks opens: some get the pixel, others don't.

The solution, as for so many things, is Velocity.

If canBeTracked is your Boolean lead field, first convert it to a number:

#set( $link = "https://info.example.com/somepage.html" )
#set( $canBeTracked = $convert.toNumber("0${lead.canBeTracked}") )

Then you can use this VTL logic to selectively track links:

#set( $trackingClass = "{0,choice,0#mktNoTrack|1#}" )
<a class="${display.message($trackingClass, $canBeTracked)}" 
   href="http://www.example.com/page.html">Le Click, C'est Chic</a>

That'll output a tracked link for those that opted in, an untracked link for everyone else.

To selectively track opens, first disable open tracking in Email Settings:

5abc6e1a73da1100229befee_vtl_trackswitch_disableopen.png

Then manually include the open-tracking pixel in the template:

#set( $trackingLink = "http://click.example.com/trk?t=1&mid=${mktmail.QpMarketoId}" )
<img src="${display.message("{0,choice,0#|1#${trackingLink}}", $canBeTracked)}">

 

What's that $display.message() thing?

I've explained the code internals in a separate post to keep this one short!

     Velocity is the only language where Brevity for Brevity's Sake is OK.

     In other languages, reducing total lines of code (LOC) with show-offy shortcuts just means your code will make no sense (to you or anyone else) after a few months away.

     But in Velocity, the shortest possible implementation is a smart move, since:

    • VTL is verbose (only one major operation permitted per line, temp variables required even for void methods)
    • it offers limited reusability (especially Marketo's flavor of Velocity, where #macro and reused $references don't work consistently)
    • it's completely whitespace-preserving (indenting would help readability, but messes up output — so the fewer lines, the less to mess up)
    • the more lines of code in your template, the more distraction from the “meat,” which is the output

     Imagine you had a few Lead fields using the JETDS naming system: installationEnvironment, typeOfEquipment, and purpose.

     There are 10-20 options for each of these fields, so the number of total combinations is huge. Even if you're only interested in a subset, the conditions get loooooong...

 

 

Read the full post on TEKNKL :: Blog →

     This is more like a pre-Velocity tip, since you need to make this decision while setting up your Marketo and/or SFDC Custom Objects, before you even try to read them using Velocity.

     Neither SFDC nor Marketo will stop you from creating such COs, and Marketo will even show them in the script editor:

ss

     But your Velocity scripts will always error out if you use those objects (with the unhelpful error message String index out of range -1).

     The reason?

 

 

Read the full post on TEKNKL :: Blog →

Y'all have seen this type of double-confirmation popup, I'm sure:

ss

It's helpful if you want to give end users a little additional nudge, for example to use their legal name, a working email address, and so on — stuff that you can't force them to do but maybe can guilt them into.

No one but me would claim it's “easy” to add this functionality to a Marketo form. It only took an hour to whip it up, but as you know, I waste spend more time in Forms 2.0 API-land than anybody else. Lucky for you, I've provided a big leg up by linking to a working CodePen that you can spin off for your own site.

 

 

Read the full post on TEKNKL :: Blog →