Testing & Troubleshooting Velocity

Dynamic Content Preview

Before sending, preview how Velocity variables render with real data directly in the message editor.

Go to Messages → Messages, open the message, and click Additional settings → Configure dynamic content.

Enter parameter values in JSON format and click Preview message.

If there are errors in the Velocity code, the preview will show an error description instead of the rendered message.

Testing with Real Order Data

If the message is triggered by an event, you can copy real event parameters directly from the interface.

Go to Triggers → Event history, click an event, and copy its parameters.

Paste the copied parameters into the Configure dynamic content field and click Preview message.

This is the easiest way to verify field names, array paths, and conditions before sending.

Checking Available Variable Context

Before debugging an expression, check which data source is actually available in the current context.

SourceAvailable inTypical access pattern
Contact fieldsMessages, workflows, segments${firstName}, ${email}
Event parametersOnly inside the workflow triggered by that event$deliveryMethod, $items[0].name
External source dataMessages or workflows where that source is connectedDepends on the source
Webhook response dataAfter the Webhook block is called in a workflowDepends on the response structure

If a value is not being substituted — check whether the expected source is available in the current context.

Case Sensitivity Rules

Data typeCase sensitivity
Contact field namesCase-insensitive: ${firstName} = ${FIRSTNAME}
Event parameter namesCase-sensitive: $deliveryMethod$DeliveryMethod
External source field namesCase-sensitive: must match column headers or JSON keys exactly

Variable Not Substituted

Symptom: the message shows the literal text $firstName or $deliveryMethod instead of the actual value.

Causes and fixes:

CauseFix
Variable name doesn't match the field or parameter nameCheck spelling and case against the contact field list or event parameters
Value is missing and bare $var syntax is usedUse $!{var} or ${var|'fallback'}
Event parameter is not available in this contextVerify the message is sent through the correct workflow
External data source is not connected to the messageConnect the data source in the message settings

Directive Rendering Issues in Email

Symptom: #foreach or #if content renders as raw text, or the email layout breaks.

Cause: directives in email HTML must be wrapped in comments. Without the wrapper, the email client treats them as invalid markup.

Fix: wrap all directives in HTML comments:

<!--#foreach($item in $items)-->
  <tr>
    <td>$!item.name</td>
    <td>$!item.cost</td>
  </tr>
<!--#end-->

<!--#if($deliveryMethod == 'express')-->
  <p>Express delivery: 1–2 days.</p>
<!--#end-->

This rule applies only to email. In SMS, Mobile Push, Viber, Telegram, and App Inbox, directives are used without comments.

Common Mistakes with Arrays and Nested Objects

Index out of bounds

$items[3].name    ← error if the array has fewer than 4 elements

Use #foreach when the array size is not known in advance, or check the size first:

#if($items.size() > 3)
  $items[3].name
#end

Missing #end

Every #if and #foreach must be closed with #end. A missing #end breaks rendering for everything after it in the template.

<!--#if($deliveryMethod == 'express')-->
  <p>Express delivery.</p>
<!--#end-->    ← required

Wrong path to a nested value

$lastProductAdded.externalItemId    ← works if lastProductAdded is an object
$lastProductAdded[0].externalItemId ← use this if lastProductAdded is an array

If a nested value is not rendering, check whether the parent is an object or an array in the event payload.

Next Steps