Uptimeify Docs
Incident managementAlert sources

Beszel

Send Beszel server alerts to Uptimeify Incident Management through a Shoutrrr generic webhook, with host, link, severity and automatic recovery for every Beszel alert type.

Beszel notifies through Shoutrrr URLs. Its generic webhook sends only a title and a message, with no status field and no alert id. The Beszel preset reads everything it needs from the title: whether the alert fires or recovers, which system it is about, and which earlier alert a recovery closes. Checked against the alert texts of Beszel 0.21.

1. Create the alert source in Uptimeify

Go to Incident Management → Alert Sources → New, pick the Beszel preset, name it, and create it. The success screen shows a ready-made notification URL for Beszel:

generic://<your-domain>/api/im/ingest/<token>?template=json

It is shown once and never displayed again in cleartext. If you lose it, rotate the token from the source's Settings tab and build the URL again from the new ingest URL: replace https:// with generic:// and append ?template=json.

template=json is required. Without it Beszel sends plain text instead of { "title", "message" }, and the preset has nothing to read.

2. Add the URL in Beszel

  1. In Beszel, open Settings → Notifications.
  2. Under Webhook / Push notifications, add the URL from step 1 and save. Test URL sends a test notification. It arrives as an open alert titled Test Alert; resolve it by hand.
  3. In the systems table, open the bell icon of each system and enable the alerts you want (status, CPU, memory, disk, and so on).

Beszel sends one notification when an alert fires and one when it recovers. Both reach the same Uptimeify alert, so the recovery resolves it.

Supported alert types

Beszel alertFiring titleRecovery title
CPU, memory, disk, bandwidth, temperature, load, GPUweb-01 CPU above thresholdweb-01 CPU below threshold
Battery (fires when low)web-01 battery below thresholdweb-01 battery above threshold
Status (connection)Connection to web-01 is down 🔴Connection to web-01 is up ✅
Container healthUnhealthy container db on web-01 🔴 or 3 unhealthy containers on web-01 🔴web-01 containers are healthy ✅
systemd servicesFailed services on web-01 🔴Services recovered on web-01 ✅
Network monitor (packet loss)Network monitor loss on web-01: 1.1.1.1:53Network monitor recovered on web-01: 1.1.1.1:53
SMARTSMART failure on web-01: /dev/sda 🔴none
ZFS poolStorage pool DEGRADED on web-01: tanknone

Beszel sends no recovery for SMART and ZFS. Those alerts stay open until you resolve them in Uptimeify. Several unhealthy containers on one system share one alert, because Beszel's recovery also covers the whole system.

Default field mapping

Beszel fieldNormalized field
titleTitle, verbatim
titleStatus: below threshold (battery: above threshold), is up, recovered and containers are healthy resolve the alert, everything else keeps it open
titleHost: the Beszel system name, also when it contains spaces
titleDedup key: system plus alert type, the same for the firing and the recovery notification
messageLink back to the system in Beszel (the URL Beszel appends to every message)
messageCustom field details, the message without the link (for example CPU averaged 91.20% for the previous 10 minutes.)

Severity map

Beszel alertUptimeify severity
SMART failure, ZFS pool FAULTED, OFFLINE, UNAVAIL, REMOVED or SUSPENDEDsev1
Connection down, failed services, ZFS pool DEGRADEDsev2
SMART warningsev3
Everything elseThe source's default severity

Sample payload

{
  "title": "backend1 CPU above threshold",
  "message": "CPU averaged 91.20% for the previous 10 minutes.\n\nhttps://beszel.example.com/system/x8k2m4p9q1w7e3r"
}

You can send this exact payload against your source's mapping from the Payload Mapping tab in the dashboard to verify the setup before enabling alerts in Beszel.

Beszel by email instead

If Beszel can only reach you by email (SMTP under Settings → Notifications), use an Email source instead. Beszel's email subject is the same title, and the body is the message followed by the link. Set these emailSelectors through the Alert Sources API to get the same behavior as the webhook preset:

{
  "emailSelectors": {
    "title": "subject",
    "severity": "subject =~ /^SMART (failure) on / || subject =~ /^Storage pool (FAULTED|OFFLINE|UNAVAIL|REMOVED|SUSPENDED) on / || subject =~ /^Connection to .+ is (down)\\b/ || subject =~ /^(Failed) services on / || subject =~ /^Storage pool (DEGRADED) on / || subject =~ /^SMART (warning) on /",
    "status": "subject =~ / (battery (?:above|below)) threshold/ || subject =~ / (above|below) threshold/ || subject =~ /^Connection to .+ is (down|up)\\b/ || subject =~ /^Network monitor (loss|recovered) on / || subject =~ /^Services (recovered) on / || subject =~ /containers are (healthy)\\b/",
    "host": "subject =~ /^(.+?) (?:\\d+m load|\\S+) (?:above|below) threshold/ || subject =~ /^Connection to (.+) is (?:down|up)\\b/ || subject =~ /^Network monitor (?:loss|recovered) on (.+?): / || subject =~ /^(?:Failed services|Services recovered) on (.+) \\S+$/ || subject =~ /^(?:Unhealthy container \\S+|\\d+ unhealthy containers) on (.+) \\S+$/ || subject =~ /^(.+) containers are healthy\\b/ || subject =~ /^SMART \\S+ on (.+?): / || subject =~ /^Storage pool \\S+ on (.+?): /",
    "dedupKey": "subject =~ /^(.+) (?:above|below) threshold/ || subject =~ /^(Connection to .+) is (?:down|up)\\b/ || subject =~ /^Network monitor (?:loss|recovered) (on .+)$/ || subject =~ /^(?:Failed services|Services recovered) (on .+) \\S+$/ || subject =~ /^(?:Unhealthy container \\S+|\\d+ unhealthy containers) on (.+) \\S+$/ || subject =~ /^(.+) containers are healthy\\b/ || subject =~ /^(SMART \\S+ on .+?) \\S+$/ || subject =~ /^(Storage pool .+)$/",
    "severityMap": { "failure": "sev1", "FAULTED": "sev1", "OFFLINE": "sev1", "UNAVAIL": "sev1", "REMOVED": "sev1", "SUSPENDED": "sev1", "down": "sev2", "Failed": "sev2", "DEGRADED": "sev2", "warning": "sev3" },
    "resolveValues": ["below", "battery above", "up", "recovered", "healthy"],
    "custom": { "details": "body =~ /^(.*?)\\s*https?:\\/\\/\\S+\\s*$/s || body" }
  }
}

The webhook preset is the better choice where it works: it also stores the Beszel link as the incident's link.

On this page