Back to Blog

Uptime Kuma notifications on your phone: loud when it goes down, quiet when it comes back

Uptime Kuma notifications on your phone: loud when it goes down, quiet when it comes back

Uptime Kuma is good at noticing that something is down. Where the notice ends up is another matter. Most setups send it to a Telegram group, a Discord channel or an email folder, next to everything else that buzzes your phone during the day. And the "back up" message makes exactly the same noise as the "down" one, so after a few flapping nights people mute the channel and stop reading it.

This guide sends Uptime Kuma's alerts to Pocket Alert as push notifications with different priorities. A monitor going down arrives as high, which gets through Focus on iPhone. A recovery arrives as low: it is in the feed when you look, and it doesn't wake anyone. Everything uses Uptime Kuma's built-in Webhook notification type, so there is nothing to install next to it.

Everything below was tested on Uptime Kuma 2.5.8 running in Docker.

What you need

  • Uptime Kuma 2.x. Most of this also works on 1.23.x; the differences are noted at the end.
  • The Pocket Alert app on your phone and an account. Sign up if you don't have one; the Free plan is enough to start.
  • An API key from API Keys (route 1) or a webhook from Webhooks (route 2).

Two ways to connect them

Uptime Kuma's Webhook notification can post to any URL, with either its own JSON or a body you write. That gives two routes:

Route 1: Pocket Alert APIRoute 2: Pocket Alert webhook URL
Post URLhttps://api.pocketalert.app/v1/messageshttps://p4a.me/wh/<slug>
Push titleYours, e.g. Down: WebsiteAlways Webhook <name>
Down loud, Up quietYesYes, with a custom body; otherwise one level for everything
Secret kept in Uptime KumaAn API key with full access to your accountA URL that can only create pushes through that webhook
Request log in Pocket AlertNoYes, in webhook history

Pick route 1 if you want readable titles and the fewest moving parts. Pick route 2 if you'd rather not store a full API key in Uptime Kuma (it keeps notification settings, headers included, as plain JSON in its database), or if you want every request it sends logged on the Pocket Alert side for debugging.

Route 1: post straight to the Pocket Alert API

In Uptime Kuma, open Settings β†’ Notifications and click Set Up Notification. Fill it in like this:

  • Notification Type: Webhook
  • Friendly Name: Pocket Alert
  • Post URL: https://api.pocketalert.app/v1/messages
  • HTTP Method: POST
  • Request Body: Custom Body

Paste this into the body field, replacing kuma.example.com with the address of your Uptime Kuma:

{%- assign level = "default" -%}
{%- assign title = "Uptime Kuma" -%}
{%- assign text = msg -%}
{%- if heartbeatJSON -%}
  {%- assign text = heartbeatJSON.msg | default: msg -%}
  {%- if heartbeatJSON.status == 0 -%}
    {%- assign title = "Down: " | append: monitorJSON.name -%}
    {%- assign level = "high" -%}
    {%- for tag in monitorJSON.tags -%}
      {%- if tag.name == "critical" -%}{%- assign level = "critical" -%}{%- endif -%}
    {%- endfor -%}
  {%- else -%}
    {%- assign title = "Up: " | append: monitorJSON.name -%}
    {%- assign level = "low" -%}
  {%- endif -%}
{%- elsif msg contains "will expire" -%}
  {%- assign title = "Expiring soon" -%}
{%- endif -%}
{
  "title": {{ title | json }},
  "message": {{ text | json }},
  "level": "{{ level }}",
  "actions": [
    {
      "type": "view",
      "label": "Open in Uptime Kuma",
      "value": "https://kuma.example.com/dashboard/{{ monitorJSON.id }}"
    }
  ]
}

Then switch on Additional Headers and paste:

{
  "Token": "YOUR_API_KEY",
  "Content-Type": "application/json"
}

What the body does:

  • The body is a Liquid template. Uptime Kuma passes it msg (its ready-made text), monitorJSON (the monitor) and heartbeatJSON (the check that changed state). heartbeatJSON.status is 0 for down and 1 for up.
  • | json writes a complete JSON string, quotes included. Error messages and monitor names can contain quotes and backslashes; with the filter they can't break the request. A monitor called Bob's "main" site still produces valid JSON.
  • Down is high, Up is low. high is time-sensitive on iPhone and gets past Focus and the scheduled summary. low is delivered without interrupting you.
  • Tag a monitor critical to make it louder. Add a tag named critical in Uptime Kuma to the monitors that matter most, and their outages are sent as critical, which plays through the silent switch and Do Not Disturb. Critical alerts are a paid feature; on the Free plan they are delivered as high.
  • Certificate and test messages have no heartbeat. For those, the push uses Uptime Kuma's own text as the message. The same text is the fallback when a heartbeat message is empty, as on a ping monitor coming back up; the API rejects a push with an empty message.
  • The button opens the monitor. /dashboard/<id> is the monitor's page in Uptime Kuma. For a certificate warning there is no monitor ID, and the button opens the dashboard instead. Action buttons are a paid feature; on the Free plan the API drops them and the push is delivered without one. See action buttons for what else they can do.

Don't skip the Content-Type header. When Uptime Kuma posts a custom body, it labels it application/x-www-form-urlencoded unless you say otherwise. That is what it sent in my test. The Pocket Alert API only accepts JSON or multipart, and answers that request with 400.

Click Test. A push titled "Uptime Kuma" with the text "Pocket Alert Testing" should arrive within a few seconds. Save.

Here is what a real outage and recovery sent from Uptime Kuma 2.5.8:

{
  "title": "Down: Website",
  "message": "timeout of 4000ms exceeded",
  "level": "high",
  "actions": [
    { "type": "view", "label": "Open in Uptime Kuma", "value": "https://kuma.example.com/dashboard/1" }
  ]
}
{
  "title": "Up: Website",
  "message": "200 - OK",
  "level": "low",
  "actions": [
    { "type": "view", "label": "Open in Uptime Kuma", "value": "https://kuma.example.com/dashboard/1" }
  ]
}

Use a separate API key named after Uptime Kuma, so you can revoke it on its own if that server is ever compromised.

Route 2: a Pocket Alert webhook URL

Here Uptime Kuma posts its own JSON to a Pocket Alert webhook, and a template on the Pocket Alert side turns it into a push.

Create the webhook

The button template can only be set through the API, so the quickest way is one call. It creates a webhook named "Uptime Kuma" with a message template, a default level of high (1) and an "Open in Uptime Kuma" button, then prints the receive URL:

PA_KEY='your-api-key'
KUMA_URL='https://kuma.example.com'

jq -n --arg kuma "$KUMA_URL" '{
  name: "Uptime Kuma",
  message: "%msg%",
  default_level: 1,
  actions: ([{type: "view", label: "Open in Uptime Kuma", value: ($kuma + "/dashboard/%monitor.id%")}] | tojson)
}' |
curl -sS https://api.pocketalert.app/v1/webhooks \
  -H "Token: $PA_KEY" \
  -H 'Content-Type: application/json' \
  --data-binary @- |
jq -r '"Receive URL: https://p4a.me/wh/" + .url'

If you'd rather click, create it in the console at Webhooks: name Uptime Kuma, Default priority High, message %msg%. You get the same pushes without the button.

Point Uptime Kuma at it

Set up a new notification of type Webhook, paste the receive URL as Post URL, and set Request Body to Preset - application/json. No headers are needed: the URL is the secret, so treat it like a password. Don't pick the multipart preset; Pocket Alert webhooks only read JSON.

Uptime Kuma sent this from my test setup when a monitor went down (trimmed; the monitor object has around a hundred fields):

{
  "heartbeat": {
    "monitorID": 1,
    "status": 0,
    "time": "2026-10-31 16:09:56.331",
    "msg": "timeout of 4000ms exceeded",
    "important": true,
    "localDateTime": "2026-10-31 16:09:56"
  },
  "monitor": {
    "id": 1,
    "name": "Website",
    "url": "http://tls-target/",
    "type": "http",
    "tags": []
  },
  "msg": "[Website] [πŸ”΄ Down] timeout of 4000ms exceeded"
}

The template %msg% uses the top-level msg, because it is the one field present in every request. For certificate warnings and test messages, heartbeat and monitor are null and only msg is filled. The push arrives titled "Webhook Uptime Kuma" with "[Website] [πŸ”΄ Down] timeout of 4000ms exceeded" as the text. A placeholder whose path is missing renders as an empty string, so on a certificate warning the button points at /dashboard/ and still works.

Down loud, Up quiet on this route

With the JSON preset, every request gets the webhook's default level, so recoveries arrive as loud as outages. To fix that, switch Request Body to Custom Body and send a level field yourself. Pocket Alert webhooks read a top-level level from the payload before falling back to the default:

{
  "level": "{% if heartbeatJSON %}{% if heartbeatJSON.status == 0 %}high{% else %}low{% endif %}{% else %}default{% endif %}",
  "msg": {{ msg | json }},
  "monitor": { "id": "{{ monitorJSON.id }}" }
}

The body keeps the field names msg and monitor.id, so the webhook's message and button templates work unchanged. Pocket Alert webhooks read the body as JSON whatever its Content-Type, so this route needs no extra header.

Turn it on for every monitor

A notification does nothing until a monitor uses it. At the bottom of the notification form there are two switches:

  • Default enabled ticks this notification on every monitor you create from now on.
  • Apply on all existing monitors adds it to all the monitors you already have. It runs once when you save and isn't remembered.

Turn on both the first time you save. To keep a monitor out, open it and untick the notification in its edit form.

Certificate expiry warnings

Uptime Kuma can warn you before a TLS certificate runs out. Open an HTTP(s) monitor (Keyword and JSON Query monitors have it too) and tick Certificate Expiry Notification under Advanced. The box is greyed out while Ignore TLS/SSL errors for HTTPS websites is on.

The thresholds are global, under Settings β†’ Notifications β†’ TLS Certificate Expiry, and default to 7, 14 and 21 days. The warning goes to the same notifications as the monitor's outages, with text like:

[TLS site][https://tls-target/] server certificate tls-target will expire in 4 days

The route 1 body catches it with msg contains "will expire" and titles it "Expiring soon" at default level. Uptime Kuma sends it once per threshold, not on every check: in my test the monitor was checked 119 times with a certificate four days from expiry, and exactly one warning went out.

Keep a flapping monitor from flooding your phone

Three monitor settings decide how much noise an unstable service makes:

SettingWhat it doesSuggested
RetriesFailed checks marked Pending before the monitor counts as down. Pending checks don't notify.2 or 3
Heartbeat Retry IntervalSeconds between checks while pending.20 to 60
Resend Notification if Down X times consecutivelyRepeats the down alert after this many more failed checks. 0 sends it once.0, or a value that works out to 30 to 60 minutes

With Retries set to 2 in my test, the first two failed checks were marked pending and only the third sent "Down". With Resend set to 3, the down alert repeated after every three more failed checks until the service came back. The resend count is in checks, not minutes. With a 60-second interval, 30 means a reminder every half hour.

Every down, every up and every resend is one message. The Free plan allows 50 a day, so one flapping monitor with no retries can use it up in an afternoon. Retries are the cheapest fix.

If nothing arrives

  • The test fails with HTTP 400. On route 1, check that Additional Headers includes "Content-Type": "application/json". Without it the request goes out as form data.
  • HTTP 401. The Token header is missing or the key was revoked. Create a new one under API Keys.
  • The test arrives but outages don't. Open the monitor and check that the notification is ticked. Also, Uptime Kuma doesn't notify on a monitor's first check if it is up, so a new monitor stays quiet until something changes.
  • Route 2 shows nothing. Open the webhook's history in the console. If the request is there with an error, it says why: invalid JSON, or a template that produced an empty message. If nothing is recorded at all, Uptime Kuma never reached p4a.me. You can also send requests to the webhook tester to see exactly what Uptime Kuma posts.
  • A recovery seems missing. low pushes are silent. Check the feed in the app.

FAQ

Which Uptime Kuma version does this need?

It was tested on 2.5.8, the latest release at the time of writing. Version 1.23.x also has the Webhook type with Custom Body and Additional Headers, and its template gets the same msg, monitorJSON and heartbeatJSON variables. I rendered the route 1 body with the template engine that ships in 1.23.16 and got the same JSON, but the full end-to-end run was on 2.5.8 only.

What if the server running Uptime Kuma goes down?

Then nothing sends the alert. Uptime Kuma can't report its own outage, so run something outside it that notices, like a check from a different machine or a hosted monitor. The uptime monitoring page lists hosted monitors that work with Pocket Alert webhooks.

Can I send different monitors to different phones?

Yes, on a paid plan. Create a notification per group with a different device_id in the body (route 1) or a different webhook with its own device (route 2), and tick the right one on each monitor. The Free plan has one device and one webhook, so there is only one phone to send to.

Does this work for ping, port and DNS monitors?

Yes. The body only uses the monitor's name and ID and the heartbeat's status and message, which every monitor type has. Some types, ping among them, leave the message empty when the check succeeds; the body then falls back to Uptime Kuma's own text. The button links to the monitor's page in Uptime Kuma rather than the checked address, so it works even when the address isn't a URL.

I already use this for Proxmox. Can it share an API key?

It can, but give Uptime Kuma its own key so revoking one doesn't break the other. The Proxmox guide covers backup and disk alerts from the same homelab.

Create a free account, paste the body into a Webhook notification, and let the next outage reach your phone while the recovery waits quietly in the feed.

Share this article