ntfy.sh | simple HTTP-based pub-sub
Ntfy (pronounce: notify) is a simple HTTP-based pub-sub notification service. It allows you to send notifications to your phone or desktop via scripts from any computer, entirely without signup or cost. It's also open source if you want to run your own.
There are many ways to use Ntfy. You can send yourself messages for all sorts of things: When a long process finishes or fails, or to notify yourself when somebody logs into your server(s). Or you may want to use it in your own app to distribute messages to subscribed clients. Endless possibilities 😀. Be sure to check out the examples below.
Publishing messages
Publishing messages can be done via PUT or POST. Topics are created on the fly by subscribing or publishing to them. Because there is no sign-up, the topic is essentially a password, so pick something that's not easily guessable.
Here's an example showing how to publish a message using curl (via POST):
curl -d "Backup successful 😀" ntfy.sh/mytopic
And another one using PUT:
echo -en "\u26A0\uFE0F Unauthorized login" | curl -sT- ntfy.sh/mytopic
Here's an example in JS with fetch() (see full example):
fetch('https://ntfy.sh/mytopic', {
method: 'POST', // PUT works too
body: 'Hello from the other side.'
})
Subscribe to a topic
You can create and subscribe to a topic either in this web UI, or in your own app by subscribing to an EventSource, a JSON feed, or raw feed.
Subscribe in this Web UI
Subscribe to topics here and receive messages as desktop notification. Topics are not password-protected, so choose a name that's not easy to guess. Once subscribed, you can publish messages via PUT/POST.
Subscribe from your phone
You can use the Ntfy Android App to receive notifications directly on your phone. Just like the server, this app is also open source. Since I don't have an iPhone or a Mac, I didn't make an iOS app yet. I'd be awesome if someone else could help out.
Subscribe via your app, or via the CLI
Using EventSource in JS, you can consume notifications like this (see live example):
const eventSource = new EventSource('https://ntfy.sh/mytopic/sse');
eventSource.onmessage = (e) => {
// Do something with e.data
};
You can also use the same /sse endpoint via curl or any other HTTP library:
$ curl -s ntfy.sh/mytopic/sse
event: open
data: {"id":"weSj9RtNkj","time":1635528898,"event":"open","topic":"mytopic"}
data: {"id":"p0M5y6gcCY","time":1635528909,"event":"message","topic":"mytopic","message":"Hi!"}
event: keepalive
data: {"id":"VNxNIg5fpt","time":1635528928,"event":"keepalive","topic":"test"}
To consume JSON instead, use the /json endpoint, which prints one message per line:
$ curl -s ntfy.sh/mytopic/json
{"id":"SLiKI64DOt","time":1635528757,"event":"open","topic":"mytopic"}
{"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Hi!"}
{"id":"DGUDShMCsc","time":1635528787,"event":"keepalive","topic":"mytopic"}
Or use the /raw endpoint if you need something super simple (empty lines are keepalive messages):
$ curl -s ntfy.sh/mytopic/raw
This is a notification
And another one with a smiley face 😀
Other features
Fetching cached messages (since=)
Messages are cached on disk for {{.CacheDuration}} to account for network interruptions of subscribers. You can read back what you missed by using the since= query parameter. It takes either a duration (e.g. 10m or 30s), a Unix timestamp (e.g. 1635528757) or all (all cached messages).
curl -s "ntfy.sh/mytopic/json?since=10m"
Polling (poll=1)
You can also just poll for messages if you don't like the long-standing connection using the poll=1 query parameter. The connection will end after all available messages have been read. This parameter can be combined with since= (defaults to since=all).
curl -s "ntfy.sh/mytopic/json?poll=1"
Subscribing to multiple topics (topic1,topic2,...)
It's possible to subscribe to multiple topics in one HTTP call by providing a comma-separated list of topics in the URL. This allows you to reduce the number of connections you have to maintain:
$ curl -s ntfy.sh/mytopic1,mytopic2/json
{"id":"0OkXIryH3H","time":1637182619,"event":"open","topic":"mytopic1,mytopic2,mytopic3"}
{"id":"dzJJm7BCWs","time":1637182634,"event":"message","topic":"mytopic1","message":"for topic 1"}
{"id":"Cm02DsxUHb","time":1637182643,"event":"message","topic":"mytopic2","message":"for topic 2"}
Examples
There are a million ways to use Ntfy, but here are some inspirations. I try to collect examples on GitHub, so be sure to check those out, too.
Example: A long process is done: backups, copying data, pipelines, ...
I started adding notifications pretty much all of my scripts. Typically, I just chain the curl call directly to the command I'm running. The following example will either send Laptop backup succeeded or ⚠️ Laptop backup failed directly to my phone:
rsync -a root@laptop /backups/laptop \
&& zfs snapshot ... \
&& curl -d "Laptop backup succeeded" ntfy.sh/backups \
|| echo -en "\u26A0\uFE0F Laptop backup failed" | curl -sT- ntfy.sh/backups
Example: Server-sent messages in your web app
Just as you can subscribe to topics in this Web UI, you can use Ntfy in your own web application. Check out the live example or just look the source of this page.
Example: Notify on SSH login
Years ago my home server was broken into. That shook me hard, so every time someone logs into any machine that I own, I now message myself. Here's an example of how to use PAM to notify yourself on SSH login.
/etc/pam.d/sshd (at the end of the file):
session optional pam_exec.so /usr/local/bin/ntfy-ssh-login.sh
/usr/local/bin/ntfy-ssh-login.sh:
#!/bin/bash
if [ "${PAM_TYPE}" = "open_session" ]; then
echo -en "\u26A0\uFE0F SSH login: ${PAM_USER} from ${PAM_RHOST}" | curl -T- ntfy.sh/alerts
fi
Example: Collect data from multiple machines
The other day I was running tasks on 20 servers and I wanted to collect the interim results as a CSV in one place. Here's the script I wrote:
while read result; do
[ -n "$result" ] && echo "$result" >> results.csv
done < <(stdbuf -i0 -o0 curl -s ntfy.sh/results/raw)
FAQ
Isn't this like ...?
Who knows. I didn't do a lot of research before making this. It was fun making it.
Can I use this in my app? Will it stay free?
Yes. As long as you don't abuse it, it'll be available and free of charge. I do not plan on monetizing
the service.
What are the uptime guarantees?
Best effort.
What happens if there are multiple subscribers to the same topic?
As per usual with pub-sub, all subscribers receive notifications if they are
subscribed to a topic.
Will you know what topics exist, can you spy on me?
If you don't trust me or your messages are sensitive, run your own server. It's open source.
That said, the logs do not contain any topic names or other details about you.
Messages are cached for {{.CacheDuration}} to facilitate service restarts, message polling and to overcome
client network disruptions.
Can I self-host it?
Yes. The server (including this Web UI) can be self-hosted, and the Android app supports adding topics from
your own server as well. There are install instructions
on GitHub.
Why is Firebase used?
In addition to caching messages locally and delivering them to long-polling subscribers, all messages are also
published to Firebase Cloud Messaging (FCM) (if FirebaseKeyFile is set, which it is on ntfy.sh). This
is to facilitate instant notifications on Android.
Why is there no iOS app (yet)?
I don't have an iPhone or a Mac, so I didn't make an iOS app yet. I'd be awesome if
someone else could help out.
Privacy policy
Neither the server nor the app record any personal information, or share any of the messages and topics with any outside service. All data is exclusively used to make the service function properly. The one exception is the Firebase Cloud Messaging (FCM) service, which is required to provide instant Android notifications (see FAQ for details).
The web server does not log or otherwise store request paths, remote IP addresses or even topics or messages, aside from a short on-disk cache (for {{.CacheDuration}}) to support service restarts.