Thanks to visit codestin.com
Credit goes to nightbell.app

Nightbell

Android · Apache 2.0 · v3.10.0

The uptime monitor that actually wakes you up.

An open-source Android app that runs every check from the phone in your pocket.

No server path
Phone → your service → phone
Tokens stay local
No account. Headers and history live on the device.
Alarm, not a ping
Full-screen page that loops until you acknowledge it

Android 8.0 and up On F-Droid, not on Play

Checkout API

https://api.example.com/health

Checkout API is down

Connection refused · down for 22m

Last
No response
Average
126 ms
Checks
60
Failed
5

Example readout, replayed 60 checks · 5 min cadence

Forty seconds. Watch it with the sound off if you like, the captions are on the CC button.
Read the video transcript
  1. Most uptime alerts are one more notification you swipe away.
  2. Nightbell runs entirely on your Android phone. No server, no account, no third party.
  3. Four steps to add a monitor. Point it at anything that answers over HTTP.
  4. Every check runs on the phone. Your tokens never touch a third party.
  5. When a check fails, Nightbell doesn’t send you something you can miss.
  6. It takes the whole screen, and the alarm loops until you acknowledge it.
  7. Nightbell. The uptime monitor that needs no server, no account, and actually wakes you up.

The problem

A notification you can swipe away is not an alert.

An ordinary alert

Monitoring service · 03:04

api.example.com is not responding

Tap to open the dashboard

One swipe, and there is no second one.

An urgent Nightbell monitor

Nightbell · ongoing

Checkout API is down

Connection refused · down for 22m

Marked ongoing, so the swipe does nothing. It comes straight back.

Checking a URL has been a solved problem for twenty years. The hard part is the last ten centimetres, between a server that knows and a person who is asleep.

Why I built it instead of paying for one

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.

Hosted monitoring, self-hosted monitoring and Nightbell compared across six aspects
Aspect Hosted service like UptimeRobot Self-hosted like Uptime Kuma Nightbell on your own phone
Infrastructure Theirs. Nothing to run. A box, a container, a certificate, and monitoring for the monitor. The phone you already carry.
Account Required. Usually required, at least locally. None. There is nothing to sign up to.
Where tokens sit On their servers. On your server. On the device, in one JSON document.
Paging you Usually the paid tier. Yours to build, on top of a push service. A local alarm, so there is nothing to bill for.
At 3am you get An email or a push notification. Whatever you wired up. A full-screen page and an alarm that loops until you acknowledge it.
It cannot Fail quietly. You will get a bill. Watch itself. Check while the phone is off, or beat Android's 15 minute background floor without a foreground service.

Scroll the table sideways for the Nightbell column

How a check runs

The check leaves your phone and goes to your service. That is the entire path.

Codestin Search App Your phone sends the check straight to your own service and gets the response back. A second path, from your phone to a monitoring company, is drawn crossed out: there is no such connection, because there is no account and no server in between. Your phone OkHttp, or an offscreen WebView Your service api.example.com A monitoring company no account, no server, no relay in between the check, and the response tokens, URLs, uptime history State stays here: one JSON document in DataStore, exported only when you export it.

Not in the path, and not in the dependency list

  • relay
  • queue
  • worker
  • backend
  • account
  • push service
  • analytics SDK
  • crash reporter
  • icon proxy

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.

Implementation details

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. 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.

What that does and does not buy you

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.

It does not buy you 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.

Three kinds of check

Point it at a status code, a response body, or one element on a rendered page.

Status check

The cheap one

Hit a URL, assert on the status code. Four modes, because "is it up" means different things to a health endpoint and to a page that is allowed to redirect.

exact code any 2xx a range any response at all

Cheapest check in the app. A connection refused has no status code and no round trip, so it reports no response and no latency rather than inventing a zero.

Request and response

The precise one

Choose the method, set headers, send a body with its content type, then assert on what comes back. Six body assertions, and JSON paths that understand nesting and array indices.

GET POST PUT PATCH DELETE HEAD
contains does not contain exactly equals matches regex JSON field equals JSON field exists
data.items[0].state

This is the one that catches a deploy that returns 200 and an empty payload, which is the outage a status check is blind to.

Page element

The expensive one

Loads the real page in an embedded WebView and watches DOM nodes you picked by tapping them. Each node carries its own expectation and an optional nickname, and the alert names the one that broke.

element exists element is gone text equals text contains text unchanged attribute equals

Every node resolves against one page load, so watching six costs about what watching one costs. The expensive part is booting the WebView, not the assertions. Selectors are re-resolved in a fixed order, id first, then a stable data attribute, then the shortest unique CSS path, then XPath, then a text fingerprint, so a cosmetic markup change degrades instead of paging you at 4am about a renamed class.

The Nightbell widget at its tall size, one column listing six monitors worst first: Marketing site down, Checkout API at 4100 ms, then four healthy services with their response times. The same widget dragged wider, the six monitors spilling into two columns with a checked just now line underneath. The same widget dragged flat into a single wide row, showing the three worst monitors and nothing else.
There is a widget too, worst monitor first. Monitors flow into columns rather than disappearing below the fold when you drag it flat, because a widget's height is whatever you dragged it to.

Adding a monitor

Four steps, and everything is changeable afterwards.

Step 1 of 4

What to watch

Status check, request and response, or page element. This is the only choice that changes the rest of the wizard.

What step 1 sets: status checkrequest and responsepage element

Step one of the new-monitor wizard: three kinds of check listed as rows, Status check selected with a tick, Request and response, and Page element.

Step 2 of 4

Target

The URL, and for a request monitor the method, headers and body. For a page monitor this is where the live preview opens and you tap the nodes you care about.

What step 2 sets: nameurlmethodheadersbodytest now

Step two: a name field reading Orders service, a URL field reading https://api.example.com/orders/health, a row of methods with GET selected, an empty headers section, and a Test now button.

Step 3 of 4

Expectations

What healthy means. A status mode, a body assertion, or one expectation per watched element. Test now runs the whole thing once, there and then, before you commit to it.

What step 3 sets: status modeexpected codebody assertiontest now

Step three: status code modes with Exact code selected, an expected code of 200 with a grid of common codes, six response body assertions with No body check selected, and a Test now button.

Step 4 of 4

Cadence and alerts

How often, how long to wait for an answer, and whether this monitor is urgent. Also the latency budget, above which a successful but slow answer counts as degraded rather than down.

What step 4 sets: intervaltimeoutfollow redirectslatency budgeturgent

Step four: check every 15 minutes with shortcuts from one minute to twelve hours, a 15 second timeout, follow redirects and active both switched on, a custom latency budget switched off, and a Create monitor button.

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 alerts

When it breaks, Nightbell wakes you up.

Urgent is a per-monitor switch for the things you cannot afford to sleep through. It is the only part of the app that is allowed to be loud, and it is deliberately hard to ignore.

  1. 01 The check fails

    The failure threshold is met, so this is an outage and not a blip. The card goes red, the banner at the top of the list counts it, and the sparkline keeps the wall of refused connections where you can see it.

  2. 02 The page arrives

    One notification, on a dedicated alarm channel that bypasses Do Not Disturb. It is marked ongoing, so there is no swipe that dismisses it, and if full-screen alerts are granted it wakes the screen rather than waiting politely on the lockscreen. It comes back every five minutes until you deal with it.

  3. 03 You decide one thing

    Ack silences this outage and nothing else. Re-check runs the check again right now. Mute buys an hour. The monitor stays red until it is not, and recovery re-arms the loop so the next outage shouts again.

The Nightbell monitor list with a red banner reading 1 of 5 is down, a Check all now button, a red Price watch card with a sparkline ending in a wall of failures, and an amber Asset CDN card marked degraded.
A phone home screen with the Nightbell urgent alert as a red heads-up card reading Checkout API is down, connection refused, down for 22m, with Ack, Re-check and mute buttons.
The Nightbell monitor detail screen for Price watch: a red dial reading 93 per cent over the past ten hours, a Down verdict, the element text that changed, and Check now, Pause and Mute 1h buttons above a response time chart that ends in red.
A screen recording off a real phone. No sound, and it loops.
Repeat
Every 5 min, until acknowledged
Channel
A dedicated alarm channel that bypasses Do Not Disturb
Swipe away
Not possible. The notification is ongoing
On the page
Acknowledge, Re-check now
On the card
Ack, Re-check, Mute 1h
Acknowledging
Stops this outage only. Recovery re-arms it
Exact acknowledgement behaviour

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".

What Android allows

Four grants, and the limits that stay after them.

Android will happily let an app think it is alerting you while delivering nothing. This is the part most phone monitoring apps skip, so it is worth being specific about.

Notifications
Without it nothing is posted at all. Dialog, in the app
Unrestricted battery
Lets checks keep their schedule, and lets an urgent page keep repeating while the screen is off. Dialog, in the app
Full-screen alerts
Lets an urgent page wake the screen instead of waiting on the lockscreen. Android settings, deep-linked
Do Not Disturb access
Without it, Do Not Disturb and Bedtime mode silence urgent pages completely, which is exactly when you want one. Android settings, deep-linked
The Nightbell first-launch setup screen listing four requirements: notifications, unrestricted battery, full-screen alerts, and Do Not Disturb access, with three granted and one outstanding.
The first-launch screen counts what is ready, deep-links to the two toggles Android has no API for, and re-checks itself when you come back.

Things the platform will not do

  • Sub-15-minute background intervals are impossible, not unreliable. WorkManager's periodic minimum is 15 minutes and there is no supported way around it. Strict mode is the only way to get the interval you asked for.
  • Doze can delay even a 15 minute interval. Exempting Nightbell from battery optimisation helps and is not a guarantee. Delay is reported in Settings and never notified about, because it is not an outage.
  • Strict mode costs a permanent notification and real battery. That is Android's price for a real cadence, not a design choice.
  • Element checks need a renderable page. Heavy single-page apps are polled for about five seconds after load; anything slower to hydrate may report element not found.
  • Quiet hours still suppress urgent pages unless you turn on the bypass. That default is wrong. It is the next thing I want to fix properly, with a migration rather than a flipped constant.
  • There is no CI. The 359 JVM and 173 on-device tests are run by hand.

Getting it

One APK, 2.36 MB, signed with a key you can check.

File
Nightbell-3.10.0-release.apk
Needs
Android 8.0+
Licence
Apache 2.0
Store listing
F-Droid
  • F-Droid Updates itself, and it serves my APK rather than a rebuild of it. Recommended Open
  • GitHub Releases The APK, from the tag it was built at. Available now Open
  • Obtainium Paste the repository URL for updates without a store. Works today Copy the URL
  • IzzyOnDroid Not submitted. It was meant to be the fast route and F-Droid proper landed first. Not yet

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.

F-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.

# download the APK from the release above, then
adb install -r Nightbell-3.10.0-release.apk

Check what you downloaded

APK SHA-256
d5368c5518bf9024e50b050a33ba036deac253eeb918dfb4007b2da1be7040c4
Signing certificate SHA-256
20d8abdaa8416a9a751e3ea144ef1523d7ddbaaeee9ec6be01d63a65574a70de
Certificate subject
CN=Nightbell, OU=river, O=river, L=Prague, C=CZ

Signed with my key, not Google's, so Play Protect asks once. The certificate number is what says the next version came from the same person.

Upgrading, and building it yourself

Android refuses an update signed by a different key, which is what makes the certificate number above worth checking before you trust an APK you did not get from the link on this page.

Anything from 2.0.0 onward updates in place and keeps your monitors. 1.x used a different application id, so the only route across is the JSON export in Settings. Building it yourself needs JDK 17 and an Android SDK with API 36; the commands are in the README.

Answers

The questions worth asking before you install it.

Does it keep checking when my phone is off?

No. The checks run on the phone, so a phone that is off, out of signal or in flight mode is a monitor that is not checking. That is the honest cost of having no server. If you need something watching while the phone is in a drawer, you need a machine that stays awake, and Nightbell is the wrong tool.

Can it check more often than every 15 minutes?

Only in strict mode. Android’s PeriodicWorkRequest has a hard 15 minute minimum and WorkManager silently clamps anything shorter, so Nightbell clamps it visibly instead and says so in Settings under Checker health. Turning on strict foreground monitoring runs a foreground service that keeps your interval exactly, down to about 15 seconds. It costs a permanent notification and real battery, which is Android’s price for a real cadence and not a design choice.

Is it on F-Droid?

Yes, since 13 August 2026, and that is the install worth taking because it is the only one that updates itself. It is also a reproducible build: F-Droid compiles Nightbell from this source on their own machines, compares the result against the APK attached to the GitHub release, and publishes mine only because the two match byte for byte. So the F-Droid download and the direct download carry the same signature, which means either one updates the other and you can move between them without uninstalling and losing your monitors. IzzyOnDroid is a separate repository and Nightbell is not in it.

Why is it not on the Play Store?

There is no Play listing, and F-Droid covers the reason most people want one: a store client that installs it and keeps it updated. What keeps it off Play is the foreground service, which declares specialUse rather than dataSync, because dataSync is capped at six hours a day from API 34 and that cap would quietly break the one guarantee strict mode exists to make. Shipping it through Play review would mean justifying the subtype. Neither F-Droid nor a direct APK is affected, and both are signed with my own key, so a direct install makes Play Protect ask you to confirm the first time.

Does anything leave my phone?

Three things, and this answer used to say two, which was wrong for as long as the app has had an update check. First, the check itself, to the service you pointed it at. Second, a connectivity probe to a reference endpoint, so losing signal in a car park is not reported as every service going down at once: an empty 204 carrying nothing about you, pointed at GrapheneOS rather than an advertising company by default, repointable at your own always-up host, and switchable off in Settings under Checks. Third, once every six hours, the version check. It reads a small file from nightbell.app and says which version it is running, and I count those requests, because it is the only way to find out how many copies of this app exist. The log line holds a timestamp, a status and that version string. It holds no address, no identifier and no hash of either, so nothing in it can be tied to a phone or joined up across two days, and there is no per install id anywhere in the app to log even if I wanted one. Turn it off with "Tell me about new versions" in Settings, or leave it on and point it at GitHub if you would rather a stranger got the request. Beyond those three, nothing: no analytics library and no crash reporter in the dependency list, a permission list short enough to read in one go, and site icons fetched from the monitored origin rather than through an icon proxy. Your service sees the request and your IP, the same as any other client on your network would. What never happens is anybody seeing your tokens, your URLs or your uptime history.

Can I watch something on my home network, or over plain HTTP?

Yes. Cleartext traffic is allowed on purpose, so a box on your LAN answering on http:// is a valid target. The catch is the same one everywhere else: the check comes from the phone, so the phone has to be able to reach the host. A monitor on a LAN address stops passing the moment you leave the house, which is a true fact about your network rather than a bug.

What happens to my monitors when I update?

Anything from 3.0.1 onward installs over the top and keeps your monitors, history and settings. 3.0.0 is the exception: 3.0.1 is signed with a new key, because the old certificate’s subject still carried the previous name and a subject cannot be edited, so a 3.0.0 install has to be uninstalled rather than updated. Coming from Pulse 2.x is different again: 3.0.0 renamed the app and moved its application id, which Android treats as a different app entirely, so it installs beside the old one with an empty data directory rather than upgrading it. The route across is Settings, Backup and transfer in 2.4.3, then import on the new install. Export before uninstalling anything, because once the old app is gone so is its data. Placed widgets and your notification channel settings do not come across either.

How is this different from UptimeRobot or Uptime Kuma?

Both are better than Nightbell at being a monitoring service: they keep watching when your phone is in a drawer, they hold years of history, they have status pages. Nightbell is not trying to win that. It is trying to be the thing that wakes you at 3am without a subscription, a server or an account, by running on hardware you already carry and paging you with a local alarm instead of a push notification. If you already run Uptime Kuma, Nightbell is a reasonable pager to put in front of it.

Will the alarm really get through Do Not Disturb?

Once you grant Do Not Disturb access, yes: urgent alerts go to a dedicated DND bypassing alarm channel. One thing to know first, because it is the current known bug rather than a feature: quiet hours still suppress urgent pages unless you turn on the bypass. That default is wrong and is the next thing on my list, with a migration rather than a flipped constant.

What does it do to my battery?

With the default WorkManager scheduling, close to nothing. Strict foreground monitoring costs real battery, because it wakes for every due check instead of letting Android batch them, and it holds a permanent notification while it does. An unacknowledged urgent outage starts that same service on its own regardless of the setting, and stops it the moment you acknowledge or the monitor recovers.

Is it actually free?

Apache 2.0, the whole thing, source included. No paid tier, no account, no upsell, nothing to cancel. Same licence as everything it depends on, so forking it or lifting a piece of it is straightforward. Keep the notice and say what you changed.