Overview
Placeholders let you inject dynamic data into your workflows. They use a Liquid-based templating syntax that can access data from multiple sources and handle both regular and sensitive information.
Placeholder Syntax
Standard Placeholders
Use double curly braces for regular variable interpolation:
1{{ variable_name }}
Example:
- Template:
"Hello {{ name }}" - Data:
{"name": "David"} - Result:
"Hello David"
Common examples:
{{ user.name }}{{ trigger.form_id }}{{ previous_action.response.id }}
Redacted Placeholders
Use the {% redact %} tag for sensitive values that should be masked in logs and audit trails:
1{% redact variable_name %}
Example:
- Template:
"Authorization: Bearer {% redact api_token %}" - Data:
{"api_token": "sk_live_abc123xyz"} - Actual API request:
"Authorization: Bearer sk_live_abc123xyz" - Logged/sanitized value:
"Authorization: Bearer <FILTERED>"
Redacted placeholders ensure sensitive values are used in your API requests but never appear in logs, execution history, or audit trails. The actual value is substituted at runtime, while any logged or displayed version shows <FILTERED> instead.
Use cases for redaction:
- API keys and tokens
- Passwords and secrets
- Personally identifiable information (PII)
- Credit card numbers or financial data
- Any sensitive data that should not appear in logs
Placeholder Features
Nested Object Access
Access nested properties using dot notation or bracket syntax:
1 2 3 4{{ user.email }} {{ user.address.city }} {{ items[0].name }} {{ response.data[0].id }}
Case-Insensitive Matching
Placeholder names are case-insensitive. These all resolve the same value:
1 2 3{{ Name }} {{ name }} {{ NAME }}
With data {"name": "David"}, all three produce "David".
Missing Placeholders
If a placeholder references a field that doesn't exist, it resolves to an empty string:
1{{ nonexistent_field }}
Result: "" (empty string)
Default Values
Provide fallback values for missing or empty fields using the default filter:
1 2{{ missing_var | default: 'fallback value' }} {{ user.nickname | default: user.name }}
Liquid Filters
Standard Liquid filters are supported for transforming values:
Text transformations:
1 2 3 4 5{{ name | upcase }} → "DAVID" {{ name | downcase }} → "david" {{ name | capitalize }} → "David" {{ text | strip }} → removes whitespace {{ text | truncate: 50 }} → limits to 50 characters
Date formatting:
1 2 3{{ date | date: "%Y-%m-%d" }} → "2024-01-15" {{ date | date: "%B %d, %Y" }} → "January 15, 2024" {{ created_at | date: "%H:%M:%S" }} → "14:30:00"
Array and object filters:
1 2 3 4{{ items | size }} → 3 {{ items | first }} → first item {{ items | last }} → last item {{ items | join: ", " }} → "a, b, c"
Nested Placeholder Resolution
Values containing placeholders are recursively resolved. This allows dynamic composition of templates:
Example:
- Data:
{"template": "Hello {{ name }}", "name": "David"} - Template:
{{ template }} - Pass 1:
"Hello {{ name }}" - Pass 2:
"Hello David"
Resolution continues up to 4 passes to handle deeply nested references.
Data Sources
Account Data
Data available across your application:
- Configuration values
- API credentials
- Global settings
User Data
User-specific information stored in user_data:
- Preferences
- Settings
- Custom fields
Execution Data
Data provided when the workflow starts:
- Event information
- Form submissions
- API payload
- Scheduled event data
Action Data
Data from previously executed actions:
- API responses
- Calculation results
- Transformed data
Node Data
Data configured in the action form by the workflow designer:
- Custom parameters
- Action settings
- Configured values
Data Precedence
When the same field exists in multiple sources, from lowest to highest precedence:
- Account Data (most general)
- User Data
- Execution Data (trigger data)
- Action Data
- Node Data (most specific)
Schema Definition
When creating triggers and actions, define their data schemas to:
- Show available placeholder fields
- Document data types
- Enable autocomplete in the builder
- Validate data usage
