Variable Expressions
Use variables and expression blocks to personalise messages in Dalil workflows and sequences, format text, do math, work with dates, phone numbers, and more.
Variables let you personalise messages in your sequences and workflows using real data from your CRM. Instead of writing the same message for everyone, a variable inserts each contact's own details, such as their first name or company name, automatically.
Expression blocks go a step further. They let you transform or combine variables using logic, so you can format text, do math, work with dates, parse phone numbers, and more before the value appears in your message.
Everything is built from two pieces: variables and expression blocks.
The two building blocks
Variables
A variable pulls in a value directly from your data using double curly braces.
{{currentPerson.firstName}}
{{currentPerson.company.name}}
{{currentSender.email.firstName}}
Expression blocks
An expression block lets you transform or combine variables using logic. It is wrapped in a {%Β %} block, and any variables inside it still use the same {{Β }} syntax:
{% ... your logic here ... %}
For example, this makes a contact's first name uppercase:
{% {{currentPerson.firstName}}.toUpperCase() %}
Text manipulation
Text expressions let you reshape a value before it appears in your message, such as changing capitalisation, trimming spaces, or pulling out part of a string.
| What you want | Expression |
|---|---|
| First name only (from full name) | {% {{currentPerson.name}}.split(' ')[0] %} |
| All caps | {% {{currentPerson.firstName}}.toUpperCase() %} |
| All lowercase | {% {{currentPerson.firstName}}.toLowerCase() %} |
| Remove extra spaces | {% {{currentPerson.firstName}}.trim() %} |
| First N characters | {% {{currentPerson.firstName}}.slice(0, 3) %} |
| Combine first and last name | {% {{currentPerson.firstName}} + ' ' + {{currentPerson.lastName}} %} |
| Email domain only | {% {{currentPerson.email}}.split('@')[1] %} |
| Replace a word | {% {{currentPerson.bio}}.replace('Manager', 'Leader') %} |
Numbers and math
Math expressions let you calculate values as the message is built, which is useful for converting stored amounts, applying multipliers, or rounding figures for display.
| What you want | Expression |
|---|---|
| Divide (e.g. convert micros to dollars) | {% {{deal.amountMicros}} / 1000000 %} |
| Multiply | {% {{deal.amount}} * 1.2 %} |
| Round to nearest whole number | {% Math.round({{deal.amount}}) %} |
| Round down | {% Math.floor({{deal.amount}}) %} |
| Round up | {% Math.ceil({{deal.amount}}) %} |
| Show 2 decimal places | {% {{deal.amount}}.toFixed(2) %} |
| Larger of two values | {% Math.max({{deal.amount}}, {{deal.minAmount}}) %} |
Conditional logic
Conditional expressions let a message change depending on the data. They use a ternary, which reads as condition ? value if true : value if false.
| What you want | Expression |
|---|---|
| Fallback if empty | {% {{currentPerson.phone}} || 'N/A' %} |
| Label based on a value | {% {{currentPerson.age}} >= 18 ? 'Adult' : 'Minor' %} |
| Multiple conditions | {% {{deal.stage}} === 'Won' ? 'Closed' : {{deal.stage}} === 'Lost' ? 'Dead' : 'Active' %} |
| Use another variable as fallback | {% {{currentPerson.nickname}} || {{currentPerson.firstName}} %} |
Dates
Date expressions let you insert the current date, read the year or month, or format a date stored on a record.
| What you want | Expression |
|---|---|
| Today's date (ISO format) | {% new Date().toISOString().slice(0, 10) %} |
| Current year | {% new Date().getFullYear() %} |
| Current month (1 to 12) | {% new Date().getMonth() + 1 %} |
| Format a stored date field | {% new Date({{deal.closedAt}}).toLocaleDateString() %} |
| Days since a date | {% Math.floor((Date.now() - new Date({{person.createdAt}})) / 86400000) %} |
| Check if a date is in the past | {% new Date({{deal.dueAt}}) < new Date() ? 'Overdue' : 'On track' %} |
Arrays
Some fields, such as webhook payloads, contain a list of items rather than a single value. Array expressions let you pull out a specific item or combine several of them. You can use dot notation or bracket notation to access array elements.
| What you want | Expression |
|---|---|
| First item in an array | {{trigger.payload.attendees.0.name}} |
| Second item | {{trigger.payload.attendees.1.email}} |
| First item via bracket notation | {{trigger.payload.attendees[0].name}} |
| Last item (dynamic) | {% {{trigger.payload.attendees}}[{{trigger.payload.attendees}}.length - 1].name %} |
| All names joined | {% {{trigger.payload.attendees}}.map(a => a.name).join(', ') %} |
| Find item by condition | {% {{trigger.payload.attendees}}.find(a => a.noShow)?.email %} |
Phone numbers
Phone expressions let you break a phone number into its separate parts. Use parsePhoneNumber(value), which returns null when the number is invalid, so pair it with ?. to avoid errors.
| What you want | Expression |
|---|---|
Calling code only (e.g. 91) | {% parsePhoneNumber({{person.phone}})?.countryCallingCode %} |
| National number only (no code) | {% parsePhoneNumber({{person.phone}})?.nationalNumber %} |
| Full international format | {% parsePhoneNumber({{person.phone}})?.formatInternational() %} |
Calling code with + prefix | {% '+' + parsePhoneNumber({{person.phone}})?.countryCallingCode %} |
| Check if number is valid | {% parsePhoneNumber({{person.phone}})?.isValid() ? 'Valid' : 'Invalid' %} |
| Fallback if unparseable | {% parsePhoneNumber({{person.phone}})?.nationalNumber || {{person.phone}} %} |
Regular expressions
Regular expressions let you match or extract a pattern inside a value, such as the text before the @ in an email address.
| What you want | Expression |
|---|---|
Extract text before @ in an email | {% {{currentPerson.email}}.match(/(.+)@/)[1] %} |
| Remove all spaces | {% {{currentPerson.phone}}.replace(/\s+/g, '') %} |
| Check if value matches a pattern | {% /^\+\d+/.test({{currentPerson.phone}}) ? 'International' : 'Local' %} |
Using expressions inside a message
Expression blocks can be placed anywhere in your message body or subject line, alongside regular text and variables. Dalil evaluates each block when the message is sent and replaces it with the result.
Hi {% {{currentPerson.firstName}}.split(' ')[0] %},
I noticed {{currentPerson.company.name}} has been growing fast.
Your deal value is ${% {{deal.amountMicros}} / 1000000 %}.
Looking forward to connecting!
What is not allowed
To keep your workspace secure, the following are blocked inside an expression:
- Running system commands or accessing files
- Making network requests
- Accessing internal server or environment data
If an expression is blocked or contains an error, the block is left blank rather than sending incorrect data, so a broken expression never sends bad information to your contact.
Was this article helpful?
Your feedback helps us improve our documentation.