Skip navigation
All Places > Products > Blog
1 2 3 Previous Next

Products

316 posts

University Day.png

 

It's not too late to register for University Day!

 

Accelerate your Marketo learning at the Marketing Nation Summit 2018! Join us at University Day on April 29, 2018, where you can take your Marketo skills to the next level and build expertise will focused instruction, practical demonstrations, and inspiring presentations by our Marketo experts.

 

Register Now and add to your Summit registration!

 

In the Bay Area but can't make it to the full four days of Summit?

Check out our University Day Single Day Pass. Register Now

Little-publicized, to the point that even Support might not be in the loop: the Visibility Rule Contains operator does allow multiple values.

The Contains value is interpreted as a full-fledged regular expression, so use the pipe character | to separate sub-values:

ss

In fact, because of this unexpected/undocumented power, you must anchor an expression to avoid surprises:

^(TX|FL|PA)$ 

Otherwise, it's doing a partial match of the full value against each of your pipe-delimited alternatives. This might not be a problem on your forms right now, but if it becomes a problem, you wouldn't know about it immediately.

For example, if you were using uppercase state names, then

     Contains KANSAS|IDAHO

would match both ARKANSAS and KANSAS, and you should use

     Contains ^(KANSAS|IDAHO)$

instead.

You can also of course do more fancy matches with regexes if you want. And Not Contains is also a regex!

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 encourage 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

My recommendation: 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 });
            });
      });
   });
})();

Be sure you sign up for as many of these 18 (2X more than at Summit 2017!!!) fabulous Marketo Technical & Foundational Techniques track sessions from our very own amazing Marketo Champions and Champion Alumni as you can:

  1. Analytics That Matter: Reports For Every Stage of the Funnel -- Jessica Kao
  2. AWSome Sauce: 10 Marketo Life Lessons From An Enterprise Org -- Joe Reitz
  3. Beyond Channels: What Else To Use To Capture The Data You Really Need (Workshop) -- Emily Thornton, Jenny Robertson, & Taylor Enfinger
  4. Cut me some Slack! Leveraging The Slack API With Marketo Webhooks And Bots -- Erik Heldebro
  5. Don't Get Lost In The Upside Down Of Your Sales Funnel (Workshop) -- Chelsea Kiko & Chris Saporito
  6. Email Deliverability 101: Winning The Inbox Wars (Workshop) -- Carmi Lopez-Jones & Kiersti Esparza
  7. Fearless Marketing In A GDPR World: Tips To Thrive Amidst New Regulations -- Michelle Miles
  8. From Nurture To Negotiation: Intelligent ABM In 2018 (Workshop) -- Rachel Noble
  9. How To Build A Marketing Operations Center Of Excellence (Workshop) -- Andy Varshneya & Edward Unthank (ETU)
  10. Infrastructure Down & Dirty: Architecting Best Practices In Marketo -- Edward Unthank (ETU)
  11. Make The Most Out Of Your A/B Testing: What Every Data Driven Marketer Needs To Know (Workshop) -- Jessica Kao
  12. Master Engagement Marketing With Marketo Engagement Programs -- Josh Hill
  13. Passing The Baton: How to Track Sales Follow Up On Your Marketing Leads (Workshop) -- David Da Silva & Mark Farnell
  14. Rolebased Metrics: The Right Report For The Right Stakeholder At The Right Time -- Veronica Holmes
  15. Skinning Schrodinger’s Cat: Fearless Marketing When You Don’t Know What You Don’t Know -- Jenn DiMaria & Juli James
  16. Smash The Data Silos: Use Marketo To Create A Single Source Of Customer Truth -- Courtney Grimes, Eric Hollebone, & Gary DeAsi
  17. Strengthening Sales & Marketing Alignment: Developing Real-Time Alerts with Rich, Actionable Insights (Workshop) -- Dan Stevens
  18. Web Personalization & ContentAI In The Real World: A Marketer's Tale -- JD Nelson

 

The number one thing we heard from you in your feedback from Summit 2017 was that you wanted more workshops! As you can see, we are offering eight of the above content sessions as workshops where you have the opportunity for a more intimate and interactive session with our most experienced speakers.

 

See you at the Marketing Nation Summit!

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 →

Summit is just a little over a month away (April 29th-May 2nd) and you don’t want to miss out! Make sure you have your pass so you can join us in San Francisco to learn from marketers like you who share similar goals and have fearlessly faced similar challenges:

  • Sendgrid’s Jacob Hansen sharing best practices for maximizing your email deliverability
  • SiriusDecision’s John Donlon on proven steps to a successful ABM implementation
  • Uber’s Wyatt Bales on building a next-gen Marketing Operations organization
  • Hands-on workshops on A/B testing and Advanced Reporting with Digital Pi’s Jessica Kao
  • CenturyLink’s Scott Berns on how they keep their robust database healthy
  • Meet ups for financial services, healthcare, manufacturing, higher ed marketers like you

 

This year we’ve doubled the amount of technical Marketo content! Check it out.

 

Who's going to be there? 

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

 

#* 
I'm being generous with whitespace here, 
but it's *still* hard to read/maintain! 
VTL is whitespace-preserving, so indents are true spaces.
*#
#if( $lead.installationEnvironment == "amphibious" )
 #if( $lead.typeOfEquipment == "radar" )
   #if( $lead.purpose == "receiving" )
   do something...
   #elseif( $lead.purpose == "detecting" )
   do something else...
   #elseif( $lead.purpose == "navigation-aid" )
   do something else entirely...
   #end
 #elseif ( $lead.typeOfEquipment == "sonar" )
   #if( $lead.purpose == "receiving" )
   do yet another thing...
   #elseif( $lead.purpose == "detecting" )
   do still another thing...
   #elseif( $lead.purpose == "navigation-aid" )
   ...
   #end
 #end
#elseif( $lead.installationEnvironment == "ground-mobile" )
 #if( $lead.typeOfEquipment == "radar" )
   #if( $lead.purpose == "receiving" )
   ...
   #elseif( $lead.purpose == "detecting" )
   ...
   #elseif( $lead.purpose == "navigation-aid" )
   ...
   #end
 #end
#end
## etc., etc.

 

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. I've provided a big leg up: a working CodePen you can spin off for your own site.

Most of the heavy lifting is done in CSS: overlaying the background, positioning the popup bar, changing the color of the Cancel/Go Back button. Aside from managing the visibility of the bar (display: block or display: none) there's not a huge amount happening in JavaScript.

 

 

Read the full post on TEKNKL :: Blog →

Welcome to 2018! We’re starting the new year out on a positive note by rolling out a new design and structure in the Marketing Nation Community with the goal of helping you be more successful with Marketo, more quickly. The new design and structure was reviewed and vetted by many Community members and we truly appreciated all their valuable feedback.

 

Starting next new week, you will see:

  1. A new home page experience – When you land on the home page, you’ll see a news feed of what’s new and exciting in the Marketing Nation Community. For those of you who have been part of Marketing Nation for several years, it will be like going back to the good ‘ol days. The Marketo banner has also been removed so you have immediate access to what you really care about, the exciting and helpful conversations happening among your fellow Community members.
  2. One place for discussions – You asked and we answered. No more decisions about where to look for answers to your questions. Product Discussions and Marketing Discussions have been merged into a single place to access the genius of your fellow marketers, simply called Discussions.
  3. A new Blog space – Read about best practices, tips and tricks, and more from peers, experts, and Marketo employees…all in one spot.
  4. An area for Release Info – Want to learn about what’s in the latest, greatest Marketo release? Look no further than our new Release Info space. 
  5. Mobile friendly – Guess what? The Marketing Nation is now mobile friendly so you can take it on the go with you. The genius of your peers is always at your fingertips.

 

I’m excited to roll out these changes to Marketing Nation. As always, if you have any additional ideas or feedback, please feel free to let me know.

 

You can expect the Marketing Nation Community to keep getting better and better throughout 2018!

Update: Thanks to everyone who completed the survey! We'll be sharing the results in the New Year.

 

***

Take this one-minute survey to help Marketo define where the Marketing Nation is today and where it's going in 2018. We'll share the results with you in the next few weeks!

 

The survey is now closed.

As part of our drive to understand and discover the best thinking from across the marketing world, we have been lucky enough to engage in conversations with senior marketing leaders from a broad range of industries. Through all our discussions, it is clear that certain themes are top-of-mind for many marketers, so we’ve distilled key insights to share with you here.

Last month, we focused on what it takes to succeed. In this post, we'll hone in on how brands can use social media to engage their customers. We'll hear from top CMOs about their social strategies, what they’ve been able to learn from their customers by being engaged, and how social media can create opportunities to get to know your customers better.

Read the full post: Voices of the Engagement Economy: Engaging Customers on Social – CMO Nation

Sanford Whiteman

Fixing Marketo pURLs

Posted by Sanford Whiteman Nov 30, 2017

It's well-known that Marketo's pURL feature, out-of-the-box, has a fatal (and kinda fascinating) shortcoming. If someone has visited your site before — meaning either an anonymous or associated Munchkin session— then pURL-enabled pages aren't functional.

When there's an existing anonymous session, the server ignores the personalized part of the URL (the Marketo Unique Name /JillSmith02 or Unique Code /XYZPDQ) and serves up default/empty content.

On the other hand, if the person has never been to your site on their current device, pURLs work fine.

Unfortunately, then, pURLs work only for people who either [a] just got a new PC or phone or [b] have been living under a relative rock. Not exactly the widest audience!

Luckily, it's always been possible to fix the strange session behavior with a little JavaScript.

 

 

Read the full post on TEKNKL :: Blog →

     With an assist from Velocity, your emails can have time-responsive content.  (And I don't just mean Happy ${day_of_week}, ${first_name}!)

  • When the same email is resent with different primary content (e.g. a weekly newsletter) Velocity can customize secondary content based on the day: like reader PW, you can show a special promo only in the first send of the month, every month.
  • Like user GM, you can pre-create a series of different content blocks, in effect creating a drip campaign from just one asset.
  • If a triggered email is sent off-hours, you can notify the recipient that they'll hear from Sales on the next business day.
  • Or lots of other adventures!

     To run the snippets below, set common variables at the top of the script (or in a global script) like so:

#set( $defaultTimeZone = $date.getTimeZone().getTimeZone("America/New_York") )
#set( $defaultLocale = $date.getLocale() )
#set( $calNow = $date.getCalendar() )
#set( $ret = $calNow.setTimeZone($defaultTimeZone) )
#set( $calConst = $field.in($calNow) )
#set( $ISO8601 = "yyyy-MM-dd'T'HH:mm:ss" )

 

 

Read the full post on TEKNKL :: Blog →

Twilio offers a pretty awesome Lookup API to enrich phone numbers with metadata: it can distinguish mobile and landline numbers (Sales will thank you!), determine carrier (which has demographic significance, like it or not), and even do reverse Caller ID lookup.

It's reasonably priced, and if anyone knows this stuff, it's Twilio.

The weird thing is that even though the Lookup API is 100% webhook-compatible, their docs don't show it being called as a simple webhook request. They only show it in the context of Java, PHP, or other code.

Anyway, here's what's needed to call it as a webhook.

Lookup requests are authenticated using HTTP Basic Auth. Your Twilio Account SID is the username; your Account Token is the password.

     So you just need to create an HTTP Authorization header and then add it to the webhook definition in Marketo. (Marketo supports Basic Auth just fine, but it doesn't present you with distinct username and password boxes.)

     An Authorization header for Basic auth looks like

Authorization: Basic <base64(<username>:<password>)>

where <base64(<username>:<password>)> means simply

  • concatenate the username and the password with a colon : in-between
  • Base64-encode the concatenated string

 

 

Read the full post on TEKNKL :: Blog →

Filter Blog

By date: By tag: