Marketo recently added a bunch of new {{trigger.tokens}}
that can help reduce the number of nearly-redundant trigger campaigns, always a good thing.
Some of the tokens are relatively “raw,” though: they output unique IDs, not friendly names. Massaging those into values suitable for people like sales owners takes a little work.
Going global to avoid local bloat
We had a request the other day for alerts on Program Status is Changed, where the New Status is in a list of interesting statuses and the program is any program in the instance. The alert email also has to include the new status.
Such a campaign can of course be added at the program level:
- trigger on Program Status is Changed
- constrain on Program [is] <this program>, New Status [is] <list>
- include
{{member.status}}
in the email
The problem is you’d have to do this for every program, forever. Nobody wants that.
Instead, we wanted a single global campaign triggering on Program Status is Changed, Program [is any]:

The goal, then, is to figure out how to get the equivalent of {{member.status}}
, since our campaign lives outside the triggering program(s).
Aha! One new token is {{trigger.New Status ID}}
, a token that’s available in a Program Status is Changed flow. Sounds perfect, right? But the catch is {{trigger.New Status ID}}
returns the unique numeric identifier of the status, not its name. And sales doesn’t understand Program Status 113 or Program Status 221!
Start thinking about Velocity maps
One ultra-powerful use for Velocity is to map unfriendly names/IDs to friendly names, like so:
#set( $statusNameMap = {
10 : "Advertising > Filled Form",
56 : "Advertising > Downloaded",
224 : "Advertising > Downloaded High-Value Asset",
168 : "Content > Downloaded",
221 : "Content > Downloaded High-Value Asset",
90 : "Content Syndication (PPL) > Downloaded",
225 : "Content Syndication (PPL) > Downloaded High-Value Asset",
226 : "Content Syndication (PPL) > Filled Form",
4 : "Webinar > Registered",
6 : "Webinar > Attended",
7 : "Webinar > On-Demand",
210 : "Website > Filled Form",
211 : "Website > Downloaded",
231 : "Website > Downloaded High-Value Content"
} )
(Some call these as “lookup tables” but I prefer to call them “maps,” since they’re literally Java LinkedHashMaps.)
If we had such a map, we could grab the friendly name with $statusNameMap.get($programStatusId)
.
There’s no official way to get the Program Status ID that currently[1] corresponds to a given Program Status Name. You can’t get it via the REST API and there isn’t a formal export feature. But you can use Dev Tools to get it from the Marketo UI.[2] Right-click and inspect the <input>
for the Program Status Name:

Then look in the HTML for the adjacent <input type="hidden">
. Its value
attribute is the Program Status ID.

OK, great! Now we can build that ID ⮕ Name map in a Velocity token {{my.Program Status Name Map}}
. But there’s one more hurdle.
{{trigger.tokens}}
aren’t automatically accessible in Velocity
So we have $statusNameMap
ready to go. But how do we look up our {{trigger.New Status ID}}
in the map, since {{trigger.tokens}}
aren’t present in the Velocity context?
Well, they’re actually present, but they’re tricky to get to. Each one is a property of the Velocity $trigger
object, but:
- it’s converted to upper case
- spaces are converted to underscores
- it’s prefixed with
v
- it’s suffixed with
_
and an unpredictable number
For example, {{trigger.New Status ID}}
can be $trigger.vNEW_STATUS_ID_99
in Velocity. But the 99
can’t be known in advance.
Not to worry. We can’t directly get("vNEW_STATUS_ID_<nnnn>")
because we don’t know the suffix, but we can loop over $trigger
until a key matches our prefix.
That happens in the Velocity token {{my.Get Program Status Name}}
:
#foreach( $entry in $trigger.entrySet() )
#set( $key = $entry.getKey() )
#set( $value = $entry.getValue() )
#if( $key.startsWith("vNEW_STATUS_ID_") && !$display.alt($value,"").isEmpty() )
#set( $newProgramStatusId = $convert.toInteger($value) )
#break
#end
#end
#set( $newProgramStatusName = $statusNameMap.get($newProgramStatusId) )
The final piece is the one-line Velocity token {{my.New Program Status Name}}
to output the value (remember, best practice is separate “calculating” and “output” tokens):
${newProgramStatusName}
Wait, one more thing
The {{trigger.token}}
must be used in the email to be accessible in Velocity. Sounds like a Catch-22, but you can drop it inside an HTML comment![3]
Sample alert email
Subject: One of your contacts just had an interesting Program Status Change!
{{my.Program Status Name Map}}{{my.Get Program Status Name}}
Name: {{lead.Full Name}}
Email: {{lead.Email Address}}
Company: {{company.Company Name}}
Title: {{lead.Job Title}}
Phone: {{lead.Phone Number}}
Program Name: {{trigger.name}}
New Program Status: {{my.New Program Status Name}} ({{trigger.New Status ID}})
Salesforce Record Link: https://exampleco.my.salesforce.com/{{lead.SFDC Id}}
The “map” token {{my.Program Status Name Map}}
and “calculate” token {{my.Get Program Status Name}}
must be included somewhere before the “output” token {{my.New Program Status Name}}
.
Notes
[1] Yes, it’s technically possible for the name to change (that’s why the Program Status ID exists). And of course new statuses may be added. You’ll have to modify the $statusNameMap
if there’s a relevant change to Admin » Tags » Channels.
[2] Alternately, look at the POST response for https://app-<nnnn>.marketo.com/marketingEvent/getDescriptorValue
. This is left as an exercise for the reader.
[3] Or between two partial Velocity tokens (#*
and *#
) to wrap it in a block comment. This has the advantage of removing it completely from the rendered email, both HTML and Text versions.