Filtering Rules
Filter and route notifications per webhook and channel by priority, tags, title, message, or JSON payload fields - operators, AND/OR groups, regex, and testing filters.
Filtering rules let you control which notifications reach which channels. Instead of sending everything everywhere, route messages based on priority, tags, or payload content.
How Filtering Works
Filters are attached to the link between a webhook and a channel. The same channel can have a filter on one webhook and none on another.
When a notification arrives, Alphorn evaluates the filter of each channel linked to the webhook:
- Match - The notification is delivered to that channel
- No match - The notification is skipped for that channel
- No filter - All notifications are delivered (default behavior)
Filters are evaluated once, when the notification arrives. Changing a filter does not affect notifications that were already received.
Setting Up a Filter
- Create a webhook, or open an existing one and click Edit on the Output Channels card
- Select a channel, expand it, and click Add filter
- Pick a field, an operator, and a value
- Use Add condition to add more conditions to the group, and Add OR group for alternatives
- Save - Save channels on the webhook page, or Save changes in the edit form
The Clear filter button removes the filter, so the channel receives everything again.
Combining Conditions
Conditions are organized in groups:
- All conditions within a group must match (AND)
- Any group matching is enough (OR)
For example, "deliver urgent production alerts, or anything tagged security" is two groups:
| Group | Conditions |
|---|---|
| 1 | Priority greater than 4 AND Tags has any of production |
| 2 | Tags has any of security |
Fields and Operators
Priority
Priority uses the 1-5 scale (1 = Min, 2 = Low, 3 = Default, 4 = High, 5 = Urgent).
| Operator | Matches when |
|---|---|
| equals | Priority is exactly the value |
| does not equal | Priority is not the value |
| greater than | Priority is strictly greater than the value |
| less than | Priority is strictly less than the value |
| between | Priority is within the range, including both ends |
A notification without a priority only matches does not equal.
Tags
| Operator | Matches when |
|---|---|
| has any of | At least one of the listed tags is present |
| has all of | Every listed tag is present |
| has none of | None of the listed tags are present |
Tag matching is case-insensitive.
Title, Message & Payload
| Operator | Matches when |
|---|---|
| equals | The text is exactly the value |
| does not equal | The text is not the value |
| contains | The text includes the value |
| does not contain | The text does not include the value |
| starts with | The text begins with the value |
| matches regex | The value, as a regular expression, matches the text |
- All comparisons are case-insensitive, including regex.
- A missing title, or a payload path that doesn't exist, is treated as empty text. So does not equal and does not contain match, and the other operators don't.
- Regular expressions that could be very slow (catastrophic backtracking) are rejected at evaluation time and never match. Invalid regexes never match either.
- Values are limited to 1,000 characters.
Payload paths
Payload conditions take a dot-separated path into the JSON request body. The path is resolved against the whole body, not only a payload key:
| Request body | Path | Value |
|---|---|---|
{"environment": "production"} | environment | production |
{"payload": {"environment": "production"}} | payload.environment | production |
{"alerts": [{"status": "firing"}]} | alerts.0.status | firing |
Payload values are compared as text - there is no numeric comparison on payload fields. Non-text values are converted first: 42 becomes "42", true becomes "true", null becomes "null", arrays become comma-separated values ("a,b"), and objects become "[object Object]" - so point the path at a single value. To route by severity, map it to the notification priority with a priority template and use a priority filter.
Plain-text notifications have no JSON payload, so payload conditions treat every path as missing (only does not equal and does not contain match).
Testing a Filter
Each filtered channel has a test panel - click Test filter to open it. Enter a sample title, message, priority, tags, and JSON payload, then click Run test to see whether the notification would be delivered and which conditions matched. Invalid JSON in the payload field is treated as an empty object.
Example Setup
Scenario: Critical notifications (priority 4+) go to Email and Telegram so you never miss them. Everything goes to Slack for team visibility.
| Channel | Filter | What it receives |
|---|---|---|
| Slack (#alerts) | No filter | All notifications |
| Priority greater than 3 | Only priority 4 and 5 | |
| Telegram | Priority greater than 3 | Only priority 4 and 5 |
A notification with priority: 2 goes to Slack only. A notification with priority: 5 goes to Slack, Email, and Telegram. A notification without a priority goes to Slack only.
Channels
Supported notification channels (Slack, Discord, Teams, Telegram, email, SMS, push, PagerDuty, Opsgenie, webhooks, SSE), their configuration, message length limits, and priority mapping.
Retries
Automatic delivery retries with exponential backoff, per-channel throttling, delivery statuses, the 24-hour delivery window, and failure notifications for failed deliveries.