NotificationsNotification Templates

Creating Notification Templates

Template System: RunReveal uses Handlebars-style templating (via Raymond) to create dynamic notifications that adapt to your detection data.

Notification Template Example

Template Syntax Guide

Basic Fields

Use fieldName syntax to insert dynamic values. Most fields are under detection for both scheduled and streaming detections.

detection.name
detection.severity
detection.resultCount
Advanced Components
๐Ÿ”„
Loops: Repeat content for each item in a list
๐Ÿ“Š
Tables: Display data in a structured table format
๐Ÿ”€
Conditionals: Show content based on conditions
Formatting

Full markdown support including:

bolditaliclistslinksimagescode blocks

Overview

Notification templates allow you to customize how alerts are formatted and delivered across different channels. Templates support conditional logic, data iteration, markdown rendering, and channel-specific formatting.

๐Ÿ”€
Conditional Logic
Show/hide content based on detection properties
๐Ÿ”„
Data Iteration
Loop through detection results and arrays
๐Ÿ“Š
Table Generation
Automatically format query results as tables
๐Ÿ“
Markdown Support
Rich formatting with markdown rendering

Using the Template Builder

RunReveal provides a visual template builder in the dashboard to create and manage your notification templates.

๐Ÿ› ๏ธ Quick Start: Creating Your First Template

1
Navigate
Go to Notification Channels โ†’ Templates
2
Create
Click โ€œCreate Templateโ€ button
3
Configure
Add title & body templates
4
Save
Save and assign to detections

Step-by-Step Guide

1
Access the Template Builder

Navigate to Notification Channels in the RunReveal dashboard, then click on the Templates tab.

Path: Dashboard โ†’ Notification Channels โ†’ Templates

2
Create a New Template

Click the Create Template button. Give your template a descriptive name that reflects its purpose (e.g., โ€œCritical Security Alertโ€, โ€œDaily Digest Summaryโ€).

critical-alertsdaily-summaryslack-security
3
Configure the Title Template

Enter your title template in the Title field. This appears as the email subject line or message header. Keep it concise and include key information like severity and detection name.

[{{detection.severity}}] {{detection.displayName}} - {{detection.resultCount}} results

4
Configure the Body Template

Enter your body template in the Body field. This is the main content of your notification. Use Handlebars syntax for dynamic content, markdown for formatting, and helpers for advanced features.

Variables
{{detection.name}}
Conditionals
{{#ifEqualsโ€ฆ}}
Tables
{{table results}}
5
Preview and Test the Template

The template editor shows a Preview of how your markdown and formatting will render. Note that the preview displays your template structure with placeholder valuesโ€”it does not use real detection data.

๐Ÿ’ก

Testing with Real Data: To see your template with actual detection data, use the Send Test button on your notification channel after saving the template. This sends a test notification using sample detection data to your configured destination (Slack, email, etc.).

Preview Shows
  • โœ“ Markdown rendering
  • โœ“ Template structure
  • โœ“ Formatting validation
Send Test Shows
  • โœ“ Real variable substitution
  • โœ“ Conditional logic evaluation
  • โœ“ Channel-specific formatting
6
Save and Assign to Detections

Click Save Template to create your template. Then assign it to detections by editing the detection and selecting your template from the Notification Template dropdown.

๐Ÿ’ก Tip: You can also specify templates in Detection-as-Code using the notificationTemplate field.

Assigning Templates to Detections

๐Ÿ–ฑ๏ธ
Via Dashboard UI
  1. Go to Detections โ†’ Detection Queries
  2. Edit the detection you want to customize
  3. Find the โ€œNotification Templateโ€ dropdown
  4. Select your custom template
  5. Save the detection
๐Ÿ’ป
Via Detection-as-Code
Add the template name to your detection YAML:
notificationNames:
- slack-security
# Override default template
notificationTemplate: critical-alerts

Template Structure

Templates consist of two parts:

๐Ÿ“Œ Title Template

Purpose: Short summary text
Used in email subject lines, Slack message titles, and notification headers
Keep it concise (50-100 characters)

๐Ÿ“„ Body Template

Purpose: Full notification content
Used in email bodies, Slack message content, and detailed notifications
Can include rich formatting, tables, and links

Core Concepts

Inserting Dynamic Values

Access detection properties using dot notation. Variables are wrapped in double curly braces.

Basic Syntax

1
detection.displayName
Display name of the detection
2
detection.severity
Severity level (Critical, High, Medium, Low)
3
detection.riskScore
Risk score value (0-100)
4
detection.resultLink
URL to view full results in RunReveal

2. Conditional Logic

Conditional helpers allow you to show or hide content based on detection properties.

Comparison Helpers

Equality Checks
  • ifEquals - Check if values are equal
  • ifNotEquals - Check if values differ
Numeric Comparisons
  • ifGreaterThan - Greater than
  • ifLessThan - Less than
  • ifGreaterThanOrEqual - Greater or equal
String Operations
  • ifContains - String contains
  • ifStartsWith - String starts with
  • ifEndsWith - String ends with
Empty Checks
  • ifNotEmpty - Value exists
  • ifEmpty - Value is empty

๐Ÿ’ก Example Use Cases

  • โ€ข Show critical alert banner only when severity equals โ€œCriticalโ€
  • โ€ข Display high-risk warning when risk score is greater than 80
  • โ€ข Show error message only when detection.error is not empty
  • โ€ข Customize content based on channel type (email vs Slack)

3. Data Iteration

Loop through detection results and arrays to display multiple items.

Loop Helper

Basic Loop Structure
loop- Iterate through detection.results array
item- Current item in the loop
index- Current index (0-based)
first- True if first item
last- True if last item
Common Patterns
  • โ€ข Loop through detection results
  • โ€ข Iterate over categories array
  • โ€ข Process MITRE techniques
  • โ€ข Display extracted fields
Best Practices
  • โ€ข Always check ifNotEmpty before looping
  • โ€ข Use index for numbering items
  • โ€ข Use first/last for special formatting
  • โ€ข Limit display to first N items if needed

4. Table Generation

Automatically format detection results as tables for better readability.

๐Ÿ”

Auto-Detect Columns

The table helper automatically detects columns from your result data.
table detection.results
Use when you want all columns displayed
๐ŸŽฏ

Specify Columns

Control exactly which columns appear in your table.
tableWithColumns detection.results โ€œcol1โ€ โ€œcol2โ€
Use when you need specific columns only

5. Markdown Rendering

Convert markdown content to HTML for rich formatting in your notifications.

๐Ÿ“ Markdown Support

Use the markdownToHTML helper to render formatted content:
Supported Markdown Features
โœ“Bold & Italic
โœ“Headers
โœ“Lists
โœ“Links
โœ“Code blocks
โœ“Tables
โœ“Blockquotes
โœ“Horizontal rules

Template Organization Patterns

Pattern 1: Severity-Based Styling

Organize content based on detection severity levels.

Critical
Immediate action required
High
Review within 1 hour
Medium
Review within 24 hours
Low
Review when convenient
Use conditional logic to apply different styling and messaging based on severity level.

Pattern 2: Risk Score Visualization

Display risk scores with visual indicators.

Risk Score Ranges

80-100: Very High Risk
60-79: High Risk
40-59: Medium Risk
0-39: Low Risk
Use ifGreaterThan helpers to conditionally display risk indicators.

Pattern 3: Result Organization

Structure detection results for clarity.

Recommended Structure

  1. 1
    Summary Section
    Detection name, severity, risk score, result count
  2. 2
    Results Table
    Formatted table of detection results
  3. 3
    Detailed Analysis
    Loop through results for detailed view
  4. 4
    Action Items
    Investigation steps and quick links

Template Variables Reference

Detection Object Properties

PropertyTypeDescription
detection.idstringUnique execution ID
detection.displayNamestringHuman-readable detection name
detection.severitystringSeverity level (Critical, High, Medium, Low)
detection.riskScorenumberRisk score (0-100)
detection.resultCountnumberNumber of results found
detection.resultsarrayQuery results (array of objects)
detection.resultLinkstringURL to view full results
detection.categoriesarrayCategory tags
detection.errorstringError message if execution failed

Channel Variable

channel - The notification channel type (email, slack, discord, webhook, jira, pagerduty, linear, google-chat)

Use this variable to customize formatting for different channels.

Best Practices

โœ… Do

  • โ€ข Keep titles concise (50-100 characters)
  • โ€ข Always check ifNotEmpty before iterating
  • โ€ข Include error handling sections
  • โ€ข Provide investigation steps
  • โ€ข Link to full results
  • โ€ข Test with empty results
  • โ€ข Use markdown for rich formatting

โŒ Donโ€™t

  • โ€ข Assume results always exist
  • โ€ข Create overly long titles
  • โ€ข Skip error handling
  • โ€ข Hard-code values that should be dynamic
  • โ€ข Forget to test edge cases
  • โ€ข Use complex nested conditionals unnecessarily
  • โ€ข Ignore channel-specific formatting needs

Ready-to-Use Templates

๐Ÿ“‹

Copy & Paste Ready: Each template below can be copied directly into RunRevealโ€™s notification template editor. Templates demonstrate different features of the Handlebars templating system.

๐Ÿ“
Basic Alert Template
Variable interpolation basics
BEGINNER
VariablesMarkdown

A simple template demonstrating basic variable substitution. Use double curly braces to insert detection properties like name, severity, and risk score.

Title Template
[{{detection.severity}}] {{detection.displayName}}
Key Features
  • โœ“ Simple variable syntax
  • โœ“ Dot notation for nested properties
  • โœ“ Markdown formatting support

Title:

[{{detection.severity}}] {{detection.displayName}} - {{detection.resultCount}} results

Body:

## {{detection.displayName}}
 
**Severity:** {{detection.severity}}
**Risk Score:** {{detection.riskScore}}
**Results Found:** {{detection.resultCount}}
 
[View Full Results]({{detection.resultLink}})

๐Ÿ”€
Severity-Based Conditionals
Dynamic content with ifEquals
INTERMEDIATE
ifEqualsConditionalsEmoji

Use ifEquals to show different content based on severity level. Great for adding visual indicators and urgency messaging.

Output Preview
๐Ÿšจ Critical
โš ๏ธ High
๐Ÿ“‹ Medium
โ„น๏ธ Low

Title:

{{#ifEquals detection.severity "Critical"}}๐Ÿšจ CRITICAL: {{/ifEquals}}{{#ifEquals detection.severity "High"}}โš ๏ธ HIGH: {{/ifEquals}}{{#ifEquals detection.severity "Medium"}}๐Ÿ“‹ MEDIUM: {{/ifEquals}}{{#ifEquals detection.severity "Low"}}โ„น๏ธ LOW: {{/ifEquals}}{{detection.displayName}}

Body:

# {{detection.displayName}}
 
{{#ifEquals detection.severity "Critical"}}
> ๐Ÿšจ **CRITICAL ALERT** - Immediate action required!
{{/ifEquals}}
{{#ifEquals detection.severity "High"}}
> โš ๏ธ **High Priority** - Review within 1 hour
{{/ifEquals}}
{{#ifEquals detection.severity "Medium"}}
> ๐Ÿ“‹ **Medium Priority** - Review within 24 hours
{{/ifEquals}}
{{#ifEquals detection.severity "Low"}}
> โ„น๏ธ **Low Priority** - Review when convenient
{{/ifEquals}}
 
| Property | Value |
|----------|-------|
| Severity | {{detection.severity}} |
| Risk Score | {{detection.riskScore}} |
| Results | {{detection.resultCount}} |
 
[View Details]({{detection.resultLink}})

๐Ÿ“Š
Auto-Generated Tables
Display results as formatted tables
INTERMEDIATE
tabletableWithColumnsifNotEmpty

The table helper automatically formats detection results as a markdown table. Use tableWithColumns to specify which columns to display.

Auto-detect columns
table detection.results
Specific columns
tableWithColumns detection.results โ€œuserโ€ โ€œactionโ€

Title:

{{detection.displayName}} ({{detection.resultCount}} matches)

Body:

## {{detection.displayName}}
 
**{{detection.resultCount}}** results found | **Risk Score:** {{detection.riskScore}}
 
{{#ifNotEmpty detection.results}}
### Detection Results
 
{{table detection.results}}
{{/ifNotEmpty}}
 
{{#ifEmpty detection.results}}
_No results to display._
{{/ifEmpty}}
 
[Open in RunReveal]({{detection.resultLink}})

๐Ÿ”„
Loop Through Results
Iterate with each helper
ADVANCED
each@index@keythis

Use #each to iterate through arrays. Access the current item with this, index with @index, and object keys with @key.

Loop Variables
this
Current item
@index
Position (0-based)
@first
Is first item
@last
Is last item

Title:

{{detection.displayName}} - {{detection.resultCount}} events detected

Body:

# {{detection.displayName}}
 
{{detection.resultCount}} events require your attention.
 
{{#ifNotEmpty detection.results}}
## Event Details
 
{{#each detection.results}}
### Event {{@index}}
{{#each this}}
- **{{@key}}**: {{this}}
{{/each}}
 
---
{{/each}}
{{/ifNotEmpty}}
 
{{#ifEmpty detection.results}}
_No events to display._
{{/ifEmpty}}
 
[View Full Analysis]({{detection.resultLink}})

๐Ÿ“ˆ
Risk Score Thresholds
Numeric comparisons with ifGreaterThan
ADVANCED
ifGreaterThanifLessThanNested Conditionals

Use numeric comparison helpers to create threshold-based messaging. Combine ifGreaterThan and ifLessThan for range checks.

0-60
Low Risk
61-80
Elevated
81-100
High Risk

Title:

{{#ifGreaterThan detection.riskScore 80}}๐Ÿ”ด{{/ifGreaterThan}}{{#ifGreaterThan detection.riskScore 60}}{{#ifLessThan detection.riskScore 81}}๐ŸŸ {{/ifLessThan}}{{/ifGreaterThan}}{{#ifLessThan detection.riskScore 61}}๐ŸŸข{{/ifLessThan}} {{detection.displayName}}

Body:

## {{detection.displayName}}
 
{{#ifGreaterThan detection.riskScore 80}}
### ๐Ÿ”ด Very High Risk ({{detection.riskScore}}/100)
This detection requires immediate attention.
{{/ifGreaterThan}}
 
{{#ifGreaterThan detection.riskScore 60}}
{{#ifLessThan detection.riskScore 81}}
### ๐ŸŸ  Elevated Risk ({{detection.riskScore}}/100)
This detection should be reviewed soon.
{{/ifLessThan}}
{{/ifGreaterThan}}
 
{{#ifLessThan detection.riskScore 61}}
### ๐ŸŸข Normal Risk ({{detection.riskScore}}/100)
This detection has a normal risk level.
{{/ifLessThan}}
 
**Results Found:** {{detection.resultCount}}
 
[Investigate Now]({{detection.resultLink}})

๐Ÿ“ฑ
Channel-Specific Formatting
Customize output per notification channel
ADVANCED
channelifEquals

The channel variable indicates the notification destination. Use it to format messages appropriately for each platform.

๐Ÿ’ฌ
slack
๐Ÿ“ง
email
๐ŸŽฎ
discord
๐Ÿ”—
webhook

Title:

{{detection.displayName}}

Body:

{{#ifEquals channel "slack"}}
*{{detection.displayName}}*
Severity: `{{detection.severity}}` | Risk: `{{detection.riskScore}}`
Results: {{detection.resultCount}}
<{{detection.resultLink}}|View in RunReveal>
{{/ifEquals}}
 
{{#ifEquals channel "email"}}
# {{detection.displayName}}
 
| Property | Value |
|----------|-------|
| Severity | {{detection.severity}} |
| Risk Score | {{detection.riskScore}} |
| Results | {{detection.resultCount}} |
 
[View Full Results]({{detection.resultLink}})
{{/ifEquals}}
 
{{#ifEquals channel "discord"}}
**{{detection.displayName}}**
> Severity: {{detection.severity}}
> Risk Score: {{detection.riskScore}}
> Results: {{detection.resultCount}}
 
{{detection.resultLink}}
{{/ifEquals}}
 
{{#ifEquals channel "webhook"}}
Detection: {{detection.displayName}}
Severity: {{detection.severity}}
Risk: {{detection.riskScore}}
Count: {{detection.resultCount}}
Link: {{detection.resultLink}}
{{/ifEquals}}

๐Ÿ›ก๏ธ
Error Handling
Gracefully handle detection failures
BEST PRACTICE
ifNotEmptyifEmptydetection.error

Always check for errors using ifNotEmpty detection.error. This ensures users are notified when detections fail and provides clear troubleshooting guidance.

โŒError State
Shows error message and troubleshooting steps
โœ…Success State
Shows normal detection results

Title:

{{#ifNotEmpty detection.error}}โŒ Error: {{/ifNotEmpty}}{{detection.displayName}}

Body:

## {{detection.displayName}}
 
{{#ifNotEmpty detection.error}}
### โŒ Detection Error
 
An error occurred while running this detection:
 
> {{detection.error}}
 
Please review the detection configuration and try again.
{{/ifNotEmpty}}
 
{{#ifEmpty detection.error}}
### โœ… Detection Successful
 
**Severity:** {{detection.severity}}
**Risk Score:** {{detection.riskScore}}
**Results Found:** {{detection.resultCount}}
 
{{#ifNotEmpty detection.results}}
{{table detection.results}}
{{/ifNotEmpty}}
 
[View Results]({{detection.resultLink}})
{{/ifEmpty}}

Testing Your Templates

Test Scenarios

Data Variations
  • โ€ข Empty results (resultCount = 0)
  • โ€ข Single result
  • โ€ข Multiple results (10+)
  • โ€ข Missing optional fields
Severity & Risk
  • โ€ข High risk scores (above 80)
  • โ€ข Low risk scores (below 20)
  • โ€ข Different severity levels
  • โ€ข Error conditions