What you need
- A BBoxProbe account on any plan: every kind of alert channel, webhooks included, is on every plan. With no channel set up, alerts go to your account email; on Free, which has 1 channel, the ntfy channel takes it.
- The ntfy app on your phone (Android or iOS), or ntfy in your browser.
-
A topic on ntfy.sh, or on an ntfy server of your own. BBoxProbe posts only to
addresses that start with
https://and are public (not on a private or local network), so a server of your own has to be reachable from the internet over HTTPS.
Read this first: ntfy doesn't check the signature
BBoxProbe signs every webhook: the X-BBoxProbe-Signature
header holds sha256= and the HMAC-SHA256 of the body, keyed with the channel's signing secret, so
your own server can refuse a request that didn't come from us. ntfy ignores that header: it doesn't know your
secret, and it publishes whatever reaches the topic. So:
-
On an open topic, the name is the password. Anyone who knows or guesses it can send you a fake
alert, and can subscribe and read your real ones, with your monitors' names and addresses. Use a long random name,
such as
uptime-alerts-followed by 20 or more random letters and digits. A topic name may hold only letters, digits, underscores and dashes. - Better: a protected topic with an access token. With an ntfy.sh account, or access control on your own server, only holders of the token can publish. The token goes in the address (below).
- Treat the whole address as a secret. Anyone who has it can post to your topic. BBoxProbe shows only its host and last characters once it is saved.
- If you need the signature checked, put a small service of your own between the two that verifies it (code for Ruby, Node and Python) and passes the alert on to ntfy.
Step 1: pick a topic and subscribe
- Choose a topic name that is hard to guess, as above. Don't copy one from a page like this.
- In the ntfy app, add a subscription to that topic (and your server, if it is your own).
Step 2: build the address
ntfy's inline templates (tpl=yes in the address) read the JSON body a webhook posts and fill in the
notification's title, message and priority from Go templates in the address. These use the payload's
summary, details, target, status and alert
(every field):
| In ntfy | In the address | Template |
|---|---|---|
| Title | t | {{.summary}} |
| Message | m | {{.details}}{{if .target}}{{.target}}{{end}}, with a new line before {{.target}} |
| Priority | p | {{if eq .status "resolved"}}3{{else if eq .alert "MonitorDown" "MonitorFlapping" "AvailabilityBurnFast" "CertExpiringSoon"}}5{{else}}3{{end}} |
The title is the alert's own: "Website is down" while it lasts and
"Website is back up" when it ends. Priority 5, ntfy's highest, goes to the
alerts that need you now (MonitorDown, MonitorFlapping, AvailabilityBurnFast, CertExpiringSoon); the others, every closing notice and a test
get 3, ntfy's default. Change the list to taste. The alert names are
MonitorDown, MonitorFlapping, AvailabilityBurnFast, AvailabilityBurnSlow, LatencyDegraded, CertExpiring, CertExpiringSoon, and Test for a test.
The same templates, encoded into one address (put your topic in place of YOUR-TOPIC; for a server of your own, its address in place of https://ntfy.sh):
https://ntfy.sh/YOUR-TOPIC?tpl=yes&t=%7B%7B.summary%7D%7D&m=%7B%7B.details%7D%7D%7B%7Bif%20.target%7D%7D%0A%7B%7B.target%7D%7D%7B%7Bend%7D%7D&p=%7B%7Bif%20eq%20.status%20%22resolved%22%7D%7D3%7B%7Belse%20if%20eq%20.alert%20%22MonitorDown%22%20%22MonitorFlapping%22%20%22AvailabilityBurnFast%22%20%22CertExpiringSoon%22%7D%7D5%7B%7Belse%7D%7D3%7B%7Bend%7D%7D
With an access token, add &auth= and the value ntfy expects there: the words
Bearer and your token, encoded in base64 without the = at the end. In a terminal:
printf 'Bearer tk_YOURTOKEN' | base64 | tr -d '=\n'
A down alert then arrives like this (the sample alert from the webhooks page):
Title: Website is down
Message: Frankfurt and Virginia get 502 Bad Gateway.
Down since 10:32 UTC.
Another notice follows when it's back.
https://example.com/
Priority: 5
A test from Send a test has no monitor, so its message has no address line; its title is "Test from BBoxProbe: your webhook channel '<name>' works".
Step 3: add the channel
- In BBoxProbe, open Alert channels and, under Add an alert channel, pick Webhook as the kind.
- Give it a Name, such as "On-call", and paste the URL into Webhook URL (https://, a public address).
- Press Add channel, then Send a test on its card. The test arrives as "Test from BBoxProbe: your webhook channel 'On-call' works".
- Alerts now go there from every monitor that hasn't picked its own channels. To send only some monitors' alerts there, tick it under Alert channels in those monitors' settings.
The address is long, and that is fine: the field takes up to 2000 characters. If the test doesn't arrive, the channels page says why, in words such as "ntfy.sh didn't accept it (403)".
How delivery behaves
Each alert is posted as it happens, and its closing notice when it ends. When ntfy doesn't answer within 10 seconds or answers with an error, the alert is tried again 1, 5 and 15 minutes later. After the last try it goes to your account email instead, saying which channel couldn't take it and why. The channels page lists the last 50 alerts and tests sent, with each channel's result.
The number of alert channels depends on the plan: 1 on Free, 3 on Pro, and 10 on Max. Every kind of channel is on every plan.
Each notice is sent once per channel; in rare failures one can arrive twice, and ntfy shows both. Every alert has a closing notice, so you also get a push when it is over.
When it doesn't work
| What you see | Why, and what to do |
|---|---|
| Nothing arrives, and the channels page says the test went through | The topic in the app and in the address differ. They must match exactly. |
| ntfy didn't accept it (403) | The topic is protected and the address has no auth. |
| ntfy didn't accept it (401) | The auth value is wrong: check the token, and that it is encoded with Bearer in front. |
| ntfy didn't accept it (400) | A template doesn't parse, or tpl=yes is missing, which leaves the priority template as it is. Copy the address again, and encode any change you make to it. |
| The address of your server can't be found, or it isn't public | A server of your own must have a public address and answer over https://. |
How BBoxProbe fits
The channel is a plain webhook channel: the same alerts, at the same moments, as every other channel. A monitor's down alert fires only when enough of its cities agree it is down (see how it works), so a push on your phone means a real outage, not one city's bad minute.