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

New York User Group

78 posts

This article outlines the setup options and the expected behavior for Partitions. Please reference the official product docs for step by step instructions on how to set partitions and workspaces up.


Partition Assignment Options


  1. Partition Settings in Admin Interface:
    • Applies to:

      All NEWLY created records EXCEPT those created via CRM sync or SOAP API.

    • Where to access setting:

      Navigate to “Admin” > “Workspaces and Partitions” > you can update the settings via either the “Workspace” or the “Partitions” tab. “Workspace” tab allows you to pick primary partition and this is where you initially assign a partition to a newly created workspace.

    • How it works:

      Create all potential partitions within the “Partitions” tab. In the “Workspace” Tab, create a workspace. Enter the workspace name and description. The rest of the fields (below) define partition assignment rules.

      • All Person Partitions: clicking this allows this specific workspace to access ALL partitions that exist within your instance (even if you have new partitions coming in in the future). A good use case for this is to reference all partitions in the “Operational” workspace.
      • Person Partition Checkbox (Required): this consists of all available partitions. The partitions that you select will be accessible via the selected workspace. Note that if only one partition is selected it automatically becomes the “primary partition”. You must select at least one partition per workspace.
      • Primary Partition (Required): This specifies which primary partition a record will be associated with if the person is introduced to Marketo via an asset within this workspace. (e.g. if a record is created via form fill out, and the form lives within workspace A, the contact will be created under the partition set as “PRIMARY” for “workspace A” unless there is a smart campaign rule specifying otherwise).Note: In the workspace tab, if a workspace has access to multiple partitions, the default partition is denoted with an asterisk (*). If the workspace only has access to one partition you don’t see the asterisk.
    • How are duplicates handled?

      Consider this scenario: Record X exists in Partition A only. If you attempt to add the same email address to Partition B, the following behavior should be expected (by the source of lead creation):

      • Creation via Manual Input: A new record Y with a duplicate email will be created in Partition B. Record Y will be available for reference in all workspaces that have access to Partition B.
      • Creation via List Import: The list import will NOT create a new record with a duplicate email in Partition B UNLESS you create custom duplication rules with Marketo support.
        • Creation via Form Fill Out: If Record X fills out a form that exists within Partition B, a new Record Y with a duplicate email will NOT be created in Partition B UNLESS you create custom duplication rules for form fill outs with Marketo Support. Any smart campaign associated to the form will not run in Partition B (because the record lives in Partition A). The form fill activity will be logged for the record in Partition A.
      • Creation via REST API: If the partition name is defined within the REST API request, a new record with the same email will be created within Partition B.
      • Notes:
        • All of these scenarios do not account for any smart campaigns updating partitions (only referring to default settings) and all of the scenarios mentioned rely on the creation activity occurring in a workspace with Partition B set at Primary Partition.
        • Custom duplication rules can be requested for each source of lead creation (e.g. I can set up a rule that uses email address AND primary partition as the duplication rule for list imports only. This will allow me to create a new record Y with duplicate email in Partition B via list upload even though Record X already exists within Partition A.
          I recommend that you thoroughly vet out and understand the use case, functionality, and activity tracking for various scenarios prior to requesting a custom duplicate rule (esp. for Form Fill Outs). Remember, since this creates a NEW record with a duplicate email address, all activity associated with this record will be specific to only activity within the workspaces where the partition is made available. In the instance where both records are accessible in one workspace (e.g. operational), you have to understand and consider who the activity (emails, web, etc.) in the shared workspace is attributed.                     
  2. Assignment Rules in Admin Interface:
    • Applies to:

      ALL NEWLY created contacts or leads via CRM sync OR SOAP API.

    • Where to access setting:

      Navigate to “Admin” -> “Workspaces and Partitions” -> “Person Partitions” Tab -> Click “Assignment Rules”

    • How it works:

      The default value will be the initial partition the contact is assigned to if being synced from the CRM.

      You have the ability to add basic logic (example below) - if the add choice functionality is not sufficient for your business use case (e.g. you wish to use a combination of filters to assign to each partition) you can assign a partition via a smart campaign.

  3. Smart Campaign:
    • Applies to:

      Newly created OR existing records. (e.g. If the partition assignment logic for the CRM sync is too complex and requires a combination of filters, use this feature to update the partition from the default partition).

      Note: Smart Campaigns partition rules have the ability to overwrite rules assigned via partition settings in the admin tab. Ensure that the smart campaign logic is thoroughly tested and is required for your use case prior to setup.

    • Where to access setting:

      Set up a campaign within Operational workspace (has access to all partitions). Create a smart campaign within Marketing Activities > Within the flow, select the “Change Person Partition” flow step.

    • How it works:

      The conditional logic can be applied within the smart list of the smart campaign (you will need multiple campaigns) OR you can create bucketed smart list assets that can be referenced within the "add choice" flow step of a single smart campaign. The campaign can be triggered or set as a batch based on your business use case.


Still have questions? Email your questions (for quicker response) or respond in the thread below (for community assistance).

You might not have noticed that {{lead.token}} values are HTML-encoded in Landing Pages. (Upfront note: this is A Good Thing, since it’s the secure-by-default approach.)


So if you have a Text Area field (same goes for String):



And you just drop that into an LP:



You’ll see the exact textual representation in the approved page — that is, in this case, you will not have a clickable link:



Of course, this is because the underlying HTML source is a “dead” text representation of the value, not a “live” <a>:



There isn’t anything wrong with this default behavior and it’s far less dangerous than rendering HTML by default.


But if you need to “resuscitate” such tokens — only if they’re from a trusted source — first make sure they’re placed inside easily identifiable HTML containers. In this case I’m taking a page from the Marketo Email Editor and setting the data-allowhtml attribute on a surrounding <span>:



Then add the related JS to the <head> of the LP:


var arrayify =[].slice);
htmlable.innerHTML = htmlable.textContent;


And now it’s a true-and-living <a>!



You might want to hide (display: none) the elements until they’re resuscitated but I leave that to you.


Only Built for Trusted Linx

Be careful with this workaround, though: only use it if you’re 100% sure the data and the output context can be trusted. If the value was populated via form fillout and never sanitized, it is definitely not trusted! While if it was synced over via a managed integration, it might be trusted.

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 = ":|-" )
#set( $values = $mktmail.xMarketoIdHdr.split($delim) )
#set( $numParts = $values.size() )
## Campaign Run ID not relevant in Preview, Test Variant not always present, etc.
#set( $keyTemplatesBySize = {
   13 : "MunchkinId-+MunchkinId-+MunchkinId::CampaignId:StepId::AssetId::CampaignRunId:LeadId--TestVariantId",
   12 : "MunchkinId-+MunchkinId-+MunchkinId::CampaignId:StepId::AssetId::CampaignRunId:LeadId-",
   11 : "MunchkinId-+MunchkinId-+MunchkinId::CampaignId:StepId::AssetId::CampaignRunId:LeadId",
  "*" : "MunchkinId-+MunchkinId-+MunchkinId::CampaignId:StepId::AssetId::LeadId"
} )
#set( $marketoIdKeys = $display.alt($keyTemplatesBySize[$numParts],$keyTemplatesBySize["*"]) )
#set( $keys = $marketoIdKeys.split($delim) )
## loop interesting keys
#foreach( $key in $keys )
#if( !$key.isEmpty() )
#if( $key.startsWith("+") )
#set( $finalKey = $key.substring(1) )
#set( $marketoSend[$finalKey] = $marketoSend[$finalKey] + "-" + $values[$foreach.index] )
#set( $finalKey = $key )
#set( $marketoSend[$finalKey] = $values[$foreach.index] )
## append Program ID
#set( $marketoSend.ProgramId = $program.values().iterator().next() )
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}
Test Variant ID is ${marketoSend.TestVariantId}

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


<a href="${marketoSend.CampaignId}&cr=${marketoSend.CampaignRunId}">Click me</a>




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:




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.









[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:


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:


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:


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.




.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

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 then you'll need to have (or newly create) a Marketo domain like Those share the private parent

Such a domain is usually already available. A domain like doesn't share a common parent with so you can't use that. You can either use an existing domain or create an alias for this specific task, so is fine to use instead of your primary

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:


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:

    var originalThankYouDoc = document.createElement("a");
    originalThankYouDoc.href = tyURLFromFormEditor;
    var dynamicThankYouURL = "" +;
    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 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!


[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:


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):


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 $:




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




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 ${}:



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.


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.


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?).


When you select the a shortcut in the Form Editor…


… 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'. -].


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.


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 ]"

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

            .map(function(field) {
               field.el$ = form
                  .find("[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
Field is false

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 )
#set( $lead.someBooleanField == false )

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 = "" )
#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="">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:


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

#set( $trackingLink = "${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 →