Overview
Signals Dashboard gives you a flexible way to measure how your signals are performing. You can define your own columns - trigger rate, reject count, fraud rate, or any metric you need - and see them calculated across every signal in. Aggregations are performed at a journey & step level.

Aggregates
Each aggregate becomes a column on the Signals Dashboard. To build one, you define:
- Column Name - unique column name
- Display Name - Name as will appear in signals dashboard column
- Variables - the underlying counts or values that should be computed to use in the aggregate template
- Template - a Jinja2 expression that combines those variables into the final displayed value. Jinja2 >=3.1.6
Example Aggregate
- Column Name: Reject
- Display Name: Reject
- Template:
{{ rejected_events }} - Variables:
- rejected_events: count distinct identifier per signal, with reject filter

- rejected_events: count distinct identifier per signal, with reject filter
Default aggregates
The following persist by default in the signals dashboard:
- Triggers (
triggers): Count distinct identifier, per signal - Total Events (
total_events): Count distinct identifier, overall - Trigger Rate (
trigger_rate) : triggers / total_events
Variables
Each variable (or 'inner aggregate') defines a single data point that is made available to the template. You configure:
| Field | Description |
|---|---|
| Variable Name | name you'll reference in the aggregate template (e.g. triggers) |
| Aggregate Function | Computation to perform. Tip: Count distinct identifier is common to count events. |
| Scope | Per Signal applies only to events where the signal fired. Overall applies across all events matching the journey and step. |
| Attribute | The attribute to compute on (e.g. identifier) |
| Filter (optional) | A condition to narrow which events are counted. It is the same expression language as Investigations view. |
Scope is what makes ratio-style metrics possible. For example, a trigger rate needs to know both how many events triggered a signal (Per Signal) and how many events occurred in total (Overall), so you can divide one by the other.
Filters let you count a specific subset of events — for example, only events where the decision outcome was "reject".
Template (Jinja Expression)
Templates use Jinja2 >=3.1.6 syntax to turn your variables into a formatted result. A few examples:
| Metric | Template | Result |
|---|---|---|
| Simple variable reference | {{ rejected_events }} |
42 |
| Ratio with formatting | {{ '%.1f' | format(fraud / triggers) }} |
0.3 |
| Percentage with div0 escape | {{ '%.2f' | format(((triggers / total_events) if total_events != 0.0 else 0.0) * 100) }}% |
14.23% |
Templates support the full Jinja2 expression language - arithmetic, conditionals, and filters like format - so you can handle edge cases (like dividing by zero) directly in the template. See: https://jinja.palletsprojects.com/en/stable/templates/
"Template" here means the Jinja expression template
Export and Import config
The aggregate and variables definitions can be exported and reimported as JSON.
Example:
reject_rate_signals_dashboard.json
Export from the configuration screen (cog top right) > Export config (bottom left)

Import from file by just dragging the JSON file into the config box

Example 1: Building a Reject Count Column
An aggregate that counts how many events led to a rejection:
- Create the aggregate with column name
Reject, display nameReject - Add a
rejected_eventsvariable — usecount_distinctonidentifier, scope Per Signal, with a filter:
This counts only events where the champion decision strategy resulted in a reject.outcome[CHAMPION].decision_strategy.result = "reject" - Write the template:
{{ rejected_events }} - Each signal now shows how many rejections it contributed to — helping you identify which signals are driving enforcement actions.
Example 2: Building a Reject Rate Column
Here's a step-by-step walkthrough for creating a "Reject Rate" aggregate. That is, when signal fired, how many % were overall reject?
- Create the aggregate and set the column name to
reject_rate, display name toReject Rate - Add a
rejectvariable- use
count_distincton theidentifierattribute - scope set to Per Signal. This counts distinct identifiers (e.g. events) where triggered each signal.
- Filter:
outcome[CHAMPION].decision_strategy.result = "reject". This means only count reject events
- use
- Add a
total_eventsvariable- use
count_distinctaggregation - on
identifier - with scope set to Overall. This counts all distinct identifiers across all events on that journey & step, regardless of whether a signal fired.
- use
- Write the template to render the percentages.
Explaining this template inside out:{{ '%.2f' | format(((triggers / total_events) if total_events != 0.0 else 0.0) * 100) }}%(triggers / total_events) if total_events != 0.0 else 0.0- divides triggers variable by total_events variable, but returns 0.0 if total_events is zero (avoids division by zero)* 100- converts the ratio to a percentage'%.2f' | format(...)- formats the number to 2 decimal places (e.g., 12.50){{ ... }}%- outputs the result with a % sign appended
Reject Rate: Full Template
{
"version": "1.0",
"timestamp": "2026-04-27T03:59:52.833Z",
"aggregates": [
{
"column_name": "reject_rate",
"display_name": "Reject Rate",
"aggregates": [
{
"aggregate_name": "reject",
"aggregate_function": "count_distinct",
"aggregate_subject": "identifier",
"aggregate_scope": "compute_per_signal",
"aggregate_filter": "outcome[CHAMPION].decision_strategy.result = 'reject'"
},
{
"aggregate_name": "total",
"aggregate_function": "count_distinct",
"aggregate_subject": "identifier",
"aggregate_scope": "compute_overall",
"aggregate_filter": ""
}
],
"render_template": "{{ '%.2f' | format(((reject / total) if total_events != 0.0 else 0.0) * 100) }}%"
}
]
}