Every internal tool eventually needs to shout at me, and half of them need to listen.
The shout is easy: a deploy finished, a backup slipped, a job died at 03:00. Without a client, each project grows its own HTTP call to whichever notification service was fashionable when it started, with its own retry behaviour and its own idea of what a failure looks like.
The listening is the part I did not expect to need: subscribing to a topic and reacting to messages, which is how a small service gets told to do something without exposing a webhook to the internet.
This is the one client for both.
Publishing
- Public ntfy.sh and self-hosted servers, Basic auth or bearer token.
- Pluggable adapters: Req is the sane default; HTTPoison, Tesla, Hackney and
:httpcalso work. - One function for the simple message, and a
Ntfy.Message/Ntfy.Actionbuilder when a message needs a priority, tags, or buttons that open a URL, hit an HTTP endpoint, broadcast, or copy text. publish_file/4for a real binary attachment, because “the report is ready” with the report attached saves a second trip.- Options validated with
NimbleOptions, and zero network calls before validation passes.
Subscribing
An optional supervised Ntfy.Connection handles the receiving side over SSE:
- One topic per process, so a topic that dies cannot take the others with it.
Last-Event-IDresumption and respect for the server’sretry:directive, which is the difference between a resilient listener and one that quietly stops during a long outage.- A
Ntfy.Connection.Handlerbehaviour for the business logic, plus raw-message mode for GenStage or Broadway pipelines. - Telemetry for the states that matter: started, stopped, topic connected, topic disconnected, message received, reconnect attempt, and errors with a classification.
- A
stop/1that drains gracefully instead of dropping in-flight messages.
Why it is not on Hex
It is internal plumbing. The page exists for the same reason the library does: so that in six months I find it instead of writing it again. If you are not on Elixir with Req, the public ntfy clients exist and one of them is probably better for you.