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 :httpc also work.
  • One function for the simple message, and a Ntfy.Message / Ntfy.Action builder when a message needs a priority, tags, or buttons that open a URL, hit an HTTP endpoint, broadcast, or copy text.
  • publish_file/4 for 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-ID resumption and respect for the server’s retry: directive, which is the difference between a resilient listener and one that quietly stops during a long outage.
  • A Ntfy.Connection.Handler behaviour 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/1 that 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.

OVERBRING software
ntfy_ex 2026
/images/software/stack/Elixir.png Elixir
Proprietary In Production

Related

Have something worth building?

A paragraph about what you are working on is enough to start.

Say hello