@petop30/n8n-nodes-ntfy
v0.2.2
Published
n8n community node for ntfy: send push notifications with text, images and action buttons, and trigger workflows from ntfy topics.
Maintainers
Readme
@petop30/n8n-nodes-ntfy
An n8n community node for ntfy: send push notifications with text, images and action buttons — and start workflows from an ntfy topic.
Works with ntfy.sh and with self-hosted instances.
Why another ntfy node
@jyln/n8n-nodes-ntfy already exists, is well maintained, and covers sending. If sending is all you need, use that one.
This package exists for two reasons:
- A trigger node. Action buttons can only report back if something is listening. The trigger subscribes to a topic, so an
httpbutton can publish to a second ntfy topic and n8n picks it up — no inbound connection to n8n required. - Header encoding. ntfy passes every parameter header through a MIME word decoder. Without RFC 2047 encoding, umlauts and other non-ASCII characters in titles, tags and button labels arrive mangled. That matters if your notifications aren't in English.
Nodes
ntfy
Publishes a message to a topic. Also available as an AI agent tool (usableAsTool).
| Field | Notes |
| --- | --- |
| Topic | Comma-separated list allowed |
| Message / Title | UTF-8 safe, multi-line supported |
| Priority | 1 (min) … 5 (urgent) |
| Emojis | Searchable picker, 1855 short codes |
| Tags | Additional free-text tags, comma-separated |
| Image / Attachment | From URL or From Binary Data |
| Buttons | Up to 3 actions: view, http, copy, broadcast |
| Options | Click URL, Icon URL, Markdown, Email, Scheduled Delivery, Custom Headers |
Two attachment modes
- From URL — only the link is sent (
X-Attach). The client downloads the file itself, nothing touches your server. The file must be reachable from the device. - From Binary Data — the file is uploaded to the ntfy server, so it works for files that aren't publicly reachable. The server must allow attachments: self-hosted needs
attachment-cache-dirset (mindattachment-file-size-limit); on ntfy.sh uploads require a paid plan.
ntfy Trigger
Subscribes to /{topic}/json and emits one item per message.
- Server-side filters for title, message, priority and tags — the server sends nothing that doesn't match.
Delivercontrols what arrives from the message cache on connect: only new / last / all / last 10m / last 24h.- Automatic reconnect with exponential backoff, plus an idle watchdog. ntfy sends a keepalive roughly every 45 s, so no traffic for 120 s counts as a dead connection.
- Resumes at the last seen message ID after a reconnect, so nothing is lost while the connection was down.
- Outgoing connection only — works behind NAT, n8n does not need to be reachable from outside.
Credentials
| Field | Notes |
| --- | --- |
| Server URL | e.g. https://ntfy.sh or https://ntfy.example.com |
| Authentication | None, Access Token (tk_…) or Username & Password |
The credential test hits GET /v1/account, which validates both the server URL and the token.
Reacting to buttons
Two patterns — pick by what your n8n instance can reach.
A — button calls an n8n webhook directly
Button type Send HTTP Request, URL of a Webhook node. The request is made by the phone, so the webhook URL has to be reachable from the device: public, or same VPN/LAN.
B — button publishes back to ntfy
Button type Send HTTP Request with:
- URL
https://ntfy.example.com/replies - Method
POST - Headers
{"Authorization": "Bearer tk_..."}(only for protected topics) - Body
approved:{{ $json.id }}
An ntfy Trigger on topic replies picks it up. Everything stays inside ntfy and n8n only needs outgoing connections. Put an ID in the body so you can correlate the answer with the original request.
view and copy buttons never report back.
Implementation notes
Things that turned out to matter, mostly found by reading the ntfy server source:
- All parameters are sent as
X-*headers. The unprefixedPriorityheader collides with the HTTP priority header (RFC 9218) that some proxies and CDNs inject. ntfy works around the common patterns, but the prefix avoids the problem entirely. - Non-ASCII header values are RFC 2047 encoded.
readHeaderParaminserver/util.goruns every parameter header throughmime.WordDecoder, so=?UTF-8?B?…?=is decoded server-side and umlauts survive. - Buttons are sent as a JSON array in
X-Actions.action.Parseaccepts JSON whenever the string starts with[, alongside the comma-separated short format. JSON means commas in a label and semicolons in a request body don't break parsing. - An uploaded file always gets a filename.
handlePublishBodydecides body-vs-attachment by whether a filename was passed: without one, a file that is ≤ 4096 bytes and valid UTF-8 is treated as the message text instead of an attachment. - Without an attachment the message goes into the request body, so it needs no header escaping at all.
- Large attachments are streamed. When n8n has the binary on disk, it is passed as a stream rather than buffered in memory.
Custom Headers (JSON)is applied last and passes through anything this node doesn't model:X-Call,X-Cache,X-Firebase,X-Poll,X-Template, …
Install
In n8n: Settings → Community Nodes → Install → @petop30/n8n-nodes-ntfy.
Manually:
cd ~/.n8n/nodes
npm install @petop30/n8n-nodes-ntfyThe unscoped name n8n-nodes-ntfy on npm belongs to an unrelated package — make sure you install the scoped one.
Development
npm install
npm run build # tsc, then copies the SVG icon and emoji data into dist/
npm run lintLink into a local n8n for testing:
npm run build && npm link
cd ~/.n8n/nodes && npm link @petop30/n8n-nodes-ntfyCompatibility note
inputs / outputs are declared as string literals ('main'). If you build against an older n8n-workflow where NodeConnectionType is still an enum, swap them for NodeConnectionType.Main — both spots are marked with a comment.
Credits
This node stands on other people's work.
- binwiederhier/ntfy — the service itself. The behaviour described under Implementation notes was verified against
action/action.go,server/util.goandserver/server.gorather than guessed. - JYLN/n8n-nodes-ntfy — the established ntfy node for n8n. The emoji picker, the scheduled-delivery field, the streamed file upload and the
X-header prefix here are all modelled on it. Worth using instead of this one if you don't need the trigger. - github/gemoji (MIT) — the original emoji data.
nodes/Ntfy/data/emojis.jsonis generated from ntfy'sweb/src/app/emojis.js, which is itself generated from gemoji, so the short codes match what the ntfy server understands. - n8n-io/n8n-nodes-starter — the community node project layout. Note that n8n now recommends the
@n8n/node-clitooling instead; this package still uses the older plain-tscsetup.
License
MIT
