---
title: Template System - Dynamic Notification Content
sidebarTitle: Templates
description: Build dynamic notification templates with variables, expressions, and system values - plus best practices for clear alert messages.
---

# Templates in Echobell

Templates in Echobell allow you to create dynamic, context-rich notifications by incorporating variables into your notification titles and bodies. This powerful feature enables personalized and informative alerts that adapt based on the trigger data, transforming generic notifications into actionable intelligence.

Instead of receiving a generic "Alert triggered" message, templates let you create specific notifications like "Production server CPU at 95%" or "Build #142 failed in deploy stage" - providing immediate context without requiring additional investigation.

## Basic Template Syntax

In Echobell templates, you can use variables by wrapping them in double curly braces:

```
{{variableName}}
```

When a channel is triggered, these variables are replaced with actual values passed through the trigger. For example, if your title template is `You have received ${{amount}}` and you trigger the channel with an `amount` value of 100, the resulting notification will display as `You have received $100`.

## Advanced Template Expressions

Echobell templates support a variety of expressions for more complex scenarios:

- Accessing Object Properties

```
{{user.name}}
{{data["value"]}}
```

- Accessing Array Elements

```
{{items[0]}}
```

- Using Comparison Operators

```
{{status == "active"}}
{{age > 18}}
```

- Logical Operators

```
{{isSubscribed && !isPaused}}
{{isUrgent || isHighPriority}}
```

All standard operators are supported: `==`, `!=`, `<`, `>`, `<=`, `>=`, `&&`, `||`, and `!`.

## Template Variables from Different Triggers

### Webhook Triggers

When triggering via webhook, you can provide variables through:

1. **Query string parameters**:

   ```http
   GET https://hook.echobell.one/t/<channel-token>?amount=100&status=complete
   ```

2. **JSON body** (for POST requests):

   ```http
   POST https://hook.echobell.one/t/<channel-token>
   Content-Type: application/json

   {
     "amount": 100,
     "status": "complete",
     "user": {
       "name": "John",
       "id": 12345
     }
   }
   ```

3. **Special variables**:
   - `externalLink`: Provides a clickable link in notification records
   - `bodyAsText`: The plain text content of the request body if `Content-Type` is `text/plain`
   - `header`: Gives access to HTTP request headers (e.g., `{{header["content-type"]}}`)

### Email Triggers

When a channel is triggered via email, the following variables are automatically available:

- `from`: The sender's email address
- `to`: The recipient's email address
- `subject`: The email subject line
- `text`: The plain text content of the email
- `html`: The HTML content of the email

## Template Use Cases

### Comparisons and Booleans

Expressions that use comparison or logical operators render their boolean result as the text `true` or `false`:

```
Payment over $1000: {{amount > 1000}}
High priority: {{isUrgent || isImportant}}
```

Echobell templates do **not** support inline if/else (ternary) logic. To send different content in different situations, use channel [Conditions](/docs/conditions) to route triggers, or interpolate the raw values directly.

### Channel Conditions

In addition to using templates in notification content, you can set **Conditions** in channel advanced settings that determine whether notifications should be sent at all. These conditions use the same expression syntax (without the curly braces).

For example, to only send notifications for amounts greater than a threshold:

```
amount > 100
```

## Link Templates

Configure a custom link template in channel advanced settings to create clickable links in notification records:

```
https://dashboard.example.com/orders/{{orderId}}
```

If no link template is set, the value of the `externalLink` variable will be used by default.

## System Time Variables (UTC)

These variables are always available to templates (and conditions) and are computed in UTC.

The following values are injected directly (flat) and can be used by name:

- `year`, `month` (1–12)
- `dayOfMonth`, `dayOfWeek` (0–6, Sunday = 0)
- `hour` (0–23), `minute`, `second`
- `date` (`YYYY-MM-DD`), `time` (`HH:mm:ss`)
- `iso`: ISO‑8601 timestamp (e.g., `2025-05-06T12:34:56.789Z`)

Other values are available **only** under the `sys.` namespace (they are not injected as flat names):

- `sys.timezone`: Always `"UTC"`
- `sys.now`: ISO‑8601 timestamp (same value as `iso`)
- `sys.epochMs`, `sys.epochSeconds`: Current time since Unix epoch (number)
- `sys.monthName`: Month name (`January`–`December`)
- `sys.dayOfWeekName`: Day name (`Sunday`–`Saturday`)

The `sys.` namespace also mirrors every flat value (e.g. `sys.year`, `sys.hour`).

Examples:

```
Sent at {{date}} {{time}} {{sys.timezone}}
Today is {{sys.dayOfWeekName}}, {{sys.monthName}} {{dayOfMonth}}, {{year}}
Epoch: {{sys.epochSeconds}}
```

## Best Practices

### Handle Missing Variables
Echobell has **no default-value operator**. The `||` operator is purely logical — it evaluates both sides as booleans and renders `true` or `false`. So `{{username || "Anonymous User"}}` renders the literal text `true` or `false`, never the username or the fallback string.

When a variable is missing, `{{variable}}` simply renders as an empty string. Design your labels so an empty value still reads clearly:

```
User: {{username}}
Server: {{serverName}}
Errors detected: {{errorCount}}
```

If you need a guaranteed value, send it explicitly in the trigger payload rather than relying on a template fallback.

### Informative Templates
Include key information in your templates to make notifications actionable without requiring additional context:

**Good Examples:**
```
Title: {{service}} {{status}} on {{environment}}
Body: {{errorMessage}} at {{timestamp}}
Action required: {{recommendedAction}}
```

**Avoid:**
```
Title: Alert
Body: Check logs
```

### Keep Templates Concise
Notifications display best when titles and bodies are clear and to the point:

- **Titles**: 3-8 words ideal, max 20 words
- **Bodies**: 1-3 sentences ideal, avoid walls of text
- **Priority**: Put most important information first

iOS notification constraints:
- Title: ~40 characters visible in collapsed view
- Body: ~60 characters in collapsed view, more when expanded

### Use Consistent Naming
Maintain consistent variable naming across your channels:

- Use clear, descriptive names: `server_name` not `sn`
- Follow a convention: snake_case, camelCase, or kebab-case
- Be consistent across related channels
- Document expected variables for team members

### Test Thoroughly
Test your templates with different variable combinations to ensure they render as expected:

1. Test with all variables present
2. Test with optional variables missing
3. Test with special characters and Unicode
4. Test with very long values
5. Test with empty strings
6. Test with numbers, booleans, arrays, and objects

### Structure for Readability
Use formatting to make notification content easy to scan:

```
🚨 Alert: {{alertName}}
━━━━━━━━━━━━━━━
Server: {{server}}
Metric: {{metric}}  
Value: {{value}}
Time: {{time}}
━━━━━━━━━━━━━━━
Details: {{message}}
```

Or use simple labels:

```
Server: {{server}}
CPU Usage: {{cpu}}%
Memory: {{memory}}%
Status: {{status}}
```

### Leverage Expressions
Use expressions to surface computed values and comparison results:

```
Title: {{service}} alert — critical: {{severity == "critical"}}
Body: {{metric}} is {{value}} (over threshold: {{value > threshold}})
```

Comparison and logical expressions render as `true` or `false`; pair them with static label text to convey meaning.

### Consider Time Zones
Remember that system time variables are in UTC. Document this or convert in your templates:

```
Alert triggered at {{time}} UTC
Triggered: {{date}} {{time}} (UTC)
```

## Common Patterns and Examples

### Server Monitoring
```
Title: {{hostname}} - {{metric}} Alert
Body: {{metric}} on {{hostname}} is at {{value}}{{unit}}
Threshold: {{threshold}}{{unit}}
Time: {{date}} {{time}}
```

### CI/CD Pipelines
```
Title: {{repository}} - Build {{status}}
Body: Build #{{buildNumber}} {{status}} in {{duration}}s
Branch: {{branch}}
Commit: {{commit_message}}
Author: {{author}}
```

### E-commerce
```
Title: New Order #{{orderNumber}}
Body: Customer: {{customerName}}
Items: {{itemCount}} items
Total: ${{totalAmount}}
Shipping: {{shippingAddress}}
```

### Error Tracking
```
Title: {{errorType}} in {{service}}
Body: {{errorMessage}}
File: {{filename}}:{{lineNumber}}
User: {{userId}}
Environment: {{environment}}
```

## Advanced Features

### Link Templates
Configure a custom **link template** in channel advanced settings to create clickable links in notification records:

```
https://dashboard.example.com/orders/{{orderId}}
https://grafana.example.com/d/{{dashboardId}}
https://github.com/{{repo}}/actions/runs/{{runId}}
```

If no link template is set, the value of the `externalLink` variable will be used by default. This is useful for providing quick access to relevant dashboards, logs, or documentation directly from the notification.

### Showing Computed Values
Templates cannot branch with ternary (`? :`) logic, and there is no string concatenation operator (`+`). Instead, interpolate values and comparison results directly, using static text for labels:

```
Online: {{isOnline}}
High severity: {{severity > 5}}
Errors detected: {{count}}
```

Comparison expressions render as `true` or `false`. To send genuinely different messages per situation, route triggers with channel [Conditions](/docs/conditions) instead of branching inside a single template.

### Channel Conditions
In addition to using templates in notification content, you can set **[Conditions](/docs/conditions)** in channel advanced settings that determine whether notifications should be sent at all. These conditions use the same expression syntax (without the curly braces).

For example, to only send notifications for amounts greater than a threshold:

```
amount > 100
status == "critical"
temperature > 30 && location == "datacenter"
```

This prevents alert fatigue by filtering out non-critical events before notifications are sent. Learn more in our [Conditions guide](/docs/conditions).

## Related Documentation

- **[Webhook Integration](/docs/webhook)** - Learn how to pass variables via webhooks
- **[Email Triggers](/docs/email-trigger)** - Variables available from email triggers
- **[Conditions](/docs/conditions)** - Filter notifications with conditional expressions
- **[Getting Started](/docs)** - Set up your first channel with templates

## Troubleshooting

**Template not rendering variables:**
- Check variable names match exactly (case-sensitive)
- Verify variables are being passed in webhook/email trigger
- Test with simple variables first, then add complexity

**Variables showing as empty:**
- Confirm the variable exists in the trigger data
- Check for typos in variable names
- Verify JSON structure for nested properties

**Expression errors:**
- Validate syntax with simple expressions first
- Ensure operators are properly spaced
- Check that property access uses correct syntax

Need help? Visit our [Support Center](/docs/support) or contact echobell@weelone.com.

---

Templates are a powerful way to create dynamic, informative notifications that give users exactly the information they need, when they need it. Start with simple variable substitution, then gradually add expressions and conditional logic to create sophisticated notification systems.
