Portal Community

Expression Context

All string fields in messaging node config are evaluated as expressions before sending. The expression context is identical to the rest of the Flow Studio expression engine:

VariableTypeDescription
$output.{nodeId}objectOutput of a completed upstream node
$jsonobjectTrigger payload / current loop item
$contextobjectExecution metadata (executionId, tenantId, actorId, appUrl, workDeskUrl)
$envobjectEnvironment variables exposed to the workflow
$nowDateCurrent UTC timestamp as JavaScript Date object

String Interpolation

For simple value injection, use the $variable.path prefix in a string field. The engine detects and substitutes single expressions:

{
  "text": "Invoice $output.createInvoice.invoiceNumber is ready for review.",
  "subject": "Action Required — $output.createInvoice.invoiceNumber ($output.fetchVendor.name)",
  "body": "Hi $output.fetchEmployee.firstName, your request for $output.createExpense.amount $output.createExpense.currency has been submitted."
}

Full Expression Mode

For computed values, concatenation, or conditional content, use a full JavaScript expression (the entire string is the expression):

// Conditional subject line
"subject": "$output.reviewDecision.approved ? 'Approved: ' + $output.createInvoice.invoiceNumber : 'Rejected: ' + $output.createInvoice.invoiceNumber"

// Formatted currency amount
"text": "'Total approved: ' + new Intl.NumberFormat('en-US', { style: 'currency', currency: $output.createInvoice.currency }).format($output.createInvoice.total)"

// Date formatting
"text": "'Submitted on ' + new Date($output.createExpense.submittedAt).toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' })"

HTML Body Templating

The bodyHtml field for email nodes supports {{expression}} interpolation inside a larger HTML string. This allows building rich HTML emails with inline data:

<!-- bodyHtml value -->
<h2>Hello {{$output.fetchEmployee.firstName}},</h2>
<p>Invoice <strong>{{$output.createInvoice.invoiceNumber}}</strong>
   for <strong>{{$output.fetchVendor.name}}</strong>
   totalling <strong>${{$output.createInvoice.total.toFixed(2)}}</strong>
   requires your approval.</p>
<table>
  {{$output.createInvoice.lineItems.map(item =>
    '<tr><td>' + item.description + '</td><td>$' + item.amount.toFixed(2) + '</td></tr>'
  ).join('')}}
</table>
<a href="{{$context.workDeskUrl}}/tasks/{{$context.executionId}}">Review Now</a>

Block Kit Expression Building

The Slack blocks field accepts a JavaScript expression that returns a Block Kit array. Use this to build dynamic blocks from workflow data:

// blocks field — full expression returning an array
`[
  {
    type: 'header',
    text: { type: 'plain_text', text: 'Expense Report: ' + $output.createExpense.reportName }
  },
  {
    type: 'section',
    fields: $output.createExpense.items.slice(0, 10).map(item => ({
      type: 'mrkdwn',
      text: '*' + item.category + '*\n$' + item.amount.toFixed(2)
    }))
  },
  {
    type: 'section',
    text: {
      type: 'mrkdwn',
      text: $output.reviewDecision.approved
        ? ':white_check_mark: *Approved* by ' + $output.reviewDecision.approverName
        : ':x: *Pending approval*'
    }
  }
]`

Null-Safe Access

Use null-coalescing and optional chaining to handle missing data gracefully:

// Null-safe with fallback
"text": "$output.fetchEmployee.displayName ?? $output.fetchEmployee.email ?? 'Unknown user'"

// Optional chaining
"text": "$output.createInvoice.vendor?.name ?? 'No vendor'"

// Conditional segment
"body": "'Hello ' + ($output.fetchEmployee.firstName ?? 'there') + ', your request has been received.'"
Preview in Flow Studio: The node inspector includes a template preview panel. After configuring a message node, click "Preview" to see the evaluated output using sample data from the most recent test execution. This catches template errors before going live.