Hyper-Personalization at Scale with Velocity Scripting
Creating deep, custom, data-driven personalization for customers at scale with Marketo Velocity Scripting.
Delivering an ultra personalized email with 5 account specific metrics per subscriber, and specific guidance tailored to that data required more than just variants or dynamic content. The combinations of data across a database are almost endless and too varied to account for in any finite set of pre-built emails.
Velocity scripting is Marketo's templating language for advanced personalization. Unlike the visual dynamic content editor, Velocity runs as server-side logic at send time, allowing conditional statements, data parsing, string manipulation, and custom functions, all within the email template itself.
To solve that, I built a Velocity scripting solution that pulls each subscriber's actual account data at send time and generates dynamic responses from the Productivity Lab based on healthy metric bands. Check out the interactive demo below to see how it worked.
Each of the five metrics required its own Velocity token, a self-contained script that parses the input, evaluates it against thresholds, and returns a block of HTML with the appropriate messaging, color coding, and status label. Those tokens are dropped into the email template as placeholders, populated at send time by the Marketo engine.
The first challenge was data parsing. The metric values come in as time strings like "4h 12m" or "44m", not as numbers. Velocity doesn't have native time parsing, so a custom parsing function extracts hours and minutes and converts them to a comparable unit before evaluation.
The collaboration time token shows the full pattern:
## Parse time string into minutes
#set($timeString = $lead.collaborationTime2025)
#if($timeString.contains("h"))
#set($parts = $timeString.split("h"))
#set($hours = $convert.toInteger($parts[0].trim()))
#set($minutes = 0)
#if($parts.size() > 1 && $parts[1].trim() != "")
#set($minutesPart = $parts[1].replace("m","").trim())
#set($minutes = $convert.toInteger($minutesPart))
#end
#set($value = ($hours * 60) + $minutes)
#else
#set($value = $convert.toInteger($timeString.replace("m","").trim()))
#end
## Evaluate and generate content
#if($value >= 30 && $value <= 60)
<p><strong style="color: #2ED4B5;">Congrats!</strong>
Your average of ${value}m closely matches the benchmark (44 minutes).</p>
#elseif($value > 60 && $value <= 90)
<p><strong style="color: #FBD13E;">Keep an eye on this.</strong>
Collaboration time is above benchmark.</p>
#else
<p><strong style="color: #FF864B;">This may call for action.</strong>
Collaboration time requires attention.</p>
#endFull scripts for all five metrics are on GitHub.