cheapest
Status check
Hit a URL, assert on the status code. A refused connection reports no response and no latency rather than inventing a zero.
exact codeany 2xxa rangeany response at all
200
up
An open-source Android app that runs every check from your phone. No server, no account.
0:40, captions on
Both of the usual answers are better at being a monitoring service. Nightbell is trying to be the thing that wakes you at 3am without a subscription, a server or an account.
like UptimeRobot
like Uptime Kuma
on your own phone
I kept missing outages because ordinary monitoring notifications behaved like everything else in the shade. The services I tried either wanted a subscription before they would text me, or sent something that looked exactly like a marketing email and got swiped away with one. By the time I noticed, the interesting part of the incident was over.
The hard part is alerting without crying wolf. An outage on an urgent monitor is not a line in the shade. It behaves like an incoming call, and everything else in the app exists to earn the right to do that.

Monitoring
company
not in the path
api.nightbell.app/health
200
Every one of these is something a monitoring app normally has. All of them can be checked against the repository, and none of them is there.
What it does not buy you is anonymity from the thing you are watching. Your service sees the request and the IP it came from, exactly as it would for any other client on your network. That is what a check is. Routing a monitor through your own proxy is the one thing that changes it, and only for that monitor.
A status or request monitor is an OkHttp call from your phone to the host you typed in. A page-element monitor loads the page in an offscreen WebView on the same phone and reads the DOM nodes you picked by tapping them. There is no relay, no queue and no worker somewhere else, because there is nowhere else. The one exception is a hop you set up yourself: a monitor can be routed through a SOCKS5 proxy running on your own device, which is how a Tor or I2P hidden service gets checked. It goes where you point it and nowhere else, and it is off until you turn it on.
Everything the app knows lives in one JSON document in DataStore: your monitors, their headers and bodies, their sample history and your settings. Sign-in secrets are the exception: they sit in a vault encrypted with a keystore key and never go into a backup. Backup and transfer writes that document through the Storage Access Framework, which is why Nightbell asks for no storage permission and why you choose where the file goes. Nothing is uploaded, and there is no import path that could reach anything you did not hand it.
It buys you this: an API token in a monitor's headers is on your phone and on your server, and nowhere in between. No third party can leak it, subpoena it, or change its terms of service. There is no analytics library and no crash reporter in the dependency list, and site icons are fetched from the monitored origin itself rather than through an icon proxy.
Two hosts get contacted that you did not choose. The connectivity reference, which you can repoint or switch off. And nightbell.app, every six hours, for the current version number: that one is counted, and what the count is allowed to know is a date, a status and which version asked. Not an address, not an identifier, not a hash standing in for one. It is the difference between knowing that four hundred copies of this are running and knowing anything at all about the four hundred people running them, and only the first of those is any of my business.
cheapest
Hit a URL, assert on the status code. A refused connection reports no response and no latency rather than inventing a zero.
exact codeany 2xxa rangeany response at all
200
upprecise
Method, headers and a body, then an assertion on what comes back. It catches the deploy that answers 200 with an empty payload.
GETPOSTPUTPATCHDELETEHEADcontainsdoes not containexactly equalsmatches regexJSON field equalsJSON field exists
{ "data": { "items": [{ "state": "ready" }] } } path data.items[0].state equals ready
heaviest
Loads the real page in a WebView and watches the nodes you tapped. Every node is read from the same page load, and the alert names the one that broke.
element existselement is gonetext equalstext containstext unchangedor an attribute instead of text
activity
Five tracks of what happens on one repository, each switched on separately. A rate limit is never an outage; a 404 or a dead network is.
starsissues and pull requestscommentsreleasesdownloads
metrics
A metrics endpoint, a PromQL query or an Alertmanager. One kind, because the three differ only in the URL and how the answer is read.
aboveat leastbelowat mostequalsnot equal
your rules
Reads a report your service writes about itself. The verdict pages; each part brings the rule that decided it, what it measured and what it saw. A part that is down on purpose can be marked expected, and pages again when it changes.
updegradeddownnoneheadersbasicsingle sign-on
1 down, 1 degraded, 1 up, 1 expected
Paymentsdown
Failed card payments, last 5m
the host
ICMP echo to an IPv4 or IPv6 address or a name, with no root. Some replies lost is degraded, none back is down, and it reports the fastest, average and slowest reply.
1 to 10 packetsIPv4IPv6eitherping 192.0.2.10
3 of 3 replies, none lostup
fastest 15.3, average 16.0, slowest 16.7
one port
Connects to one port and hangs up, nothing sent. Refused, timed out and no route each say so. Next to a ping on the same host, the app says whether the network or the service is down.
22 SSH443 HTTPS3306 MySQL5432 Postgresany portThe host answers ping, but port 5432 is down. The network is fine; look at the service.
one datagram
Sends the service a real request and checks the reply: a DNS answer, the time from NTP, an SNMP value. A closed port is down at once. Services that never reply get silent mode, which waits for a refusal and pings the host.
DNSNTPSTUNSNMPSIPHTTP/3game serversyour own bytessilentWireGuard never answers a stranger, so silent mode only knows the port was not refused and the host is there.
what arrived
Signs in to an IMAP folder and tells you what arrived, louder for the senders or subjects you name. Setup finds the server from the address and lists the folders to pick from. Nothing is ever marked read, and a mail server that stops answering is an outage.
TLSSTARTTLSevery messagesender hassubject hasskip read[email protected] on mx1.example.eu
Two notifications, one of them loud. The message read on the laptop first is listed and not announced.
Home-screen widget
Put Nightbell on your home screen and see every monitor without opening the app, the one in trouble at the top. Drag the widget flat and the list flows into columns instead of disappearing below the fold.




Status check, request and response, page element, GitHub repository, Prometheus, health endpoint, ping, TCP port, UDP port or mailbox. This is the only choice that changes the rest of the wizard.
status checkrequest and responsepage elementGitHub repositoryPrometheushealth endpointpingTCP portUDP portmailbox
Nothing here is locked in. Every field is editable from the monitor's detail screen afterwards, and Test now runs the whole check once before you commit to it.
Urgent is a per-monitor switch for the things you cannot sleep through. It is the one part of the app allowed to be loud.

3:14
A dedicated alarm channel that bypasses Do Not Disturb. The notification is ongoing, so there is no swipe that clears it.

3:14
With full-screen alerts allowed, the page takes the screen and the siren loops until you act. A phone on silent still vibrates.

+5 min
Posted again every five minutes until you acknowledge. Ack ends this outage only, and recovery re-arms it for the next one.
Acknowledging stops the repeats for that outage and nothing else. The monitor stays red, the ordinary down notification stays where it was, and recovery re-arms the loop so the next outage shouts again. Urgent overrides cooldown and the repeat toggle, because that is the point, but it still honours the master switch, the per-monitor switch, mute and the failure threshold. It means "do not let me miss this", not "ignore everything I configured".
Android will let an app believe it is alerting you while it delivers nothing. These four switches are what stop that.

Without it nothing is posted at all.
Checks keep their schedule, and an urgent page keeps repeating in your pocket.
An urgent page wakes the screen instead of waiting on the lockscreen.
Without it, Do Not Disturb and Bedtime silence urgent pages completely.
Allow is a dialog inside the app. Settings is a trip to Android's own screen, because Android gives apps no way to flip those two, and the list re-checks itself when you come back.
15 minutes, the shortest interval Android gives a background check. Strict mode goes lower.
CI runs the 1,237 JVM tests and a release build on every push. The 567 on-device tests are run by hand before every release.
Latest release
3.23.0
From a computer, once the APK above is downloaded:
$ adb install -r Nightbell-3.23.0-release.apkF-Droid rebuilds Nightbell from this source and publishes it only when their output matches the APK above byte for byte, so both downloads carry the same signature and either one updates the other.
F-Droid is the only store Nightbell is listed in. There is no Play listing and no other store anywhere. If you find one, it is not mine.
Signed with my key, not Google's, so Play Protect asks once. The certificate fingerprint is what says the next version came from the same person.
Android refuses an update signed by a different key, which is what makes the certificate fingerprint above worth checking before you trust an APK you did not get from the link on this page.
Anything from 3.0.1 onward updates in place and keeps your monitors. 3.0.0 and Pulse 2.x cannot be updated over, so the route across is the JSON export in Settings; the FAQ has the steps. Building it yourself needs JDK 17 and an Android SDK with API 36; the commands are in the README.
03:14
2.9 MB, Android 8.0 and up, no account to make. Add one monitor, mark it urgent, and the next outage is a phone call instead of a footnote.