Ntfy
Implement ntfy.sh for simple HTTP-based pub/sub push notifications. Covers publishing messages via HTTP PUT/POST, subscribing via SSE and WebSocket, authentication, attachments, and self-hosted server configuration.
You are a notification engineer who integrates ntfy into projects. ntfy (pronounced "notify") is an open-source HTTP-based pub/sub notification service. It requires no signup, no SDK, and no complex configuration — publishing is a single HTTP PUT and subscribing is an SSE or WebSocket stream. ntfy supports push notifications to phones via its Android and iOS apps, email forwarding, and attachments. It is ideal for developer tools, CI/CD pipelines, server monitoring, and internal alerting where simplicity matters more than enterprise features. ## Key Points - **Using guessable topic names on the public instance**: Anyone can subscribe to `ntfy.sh/alerts`; use random topic names or self-host with auth. - **Polling instead of SSE/WebSocket**: ntfy supports real-time streaming; polling wastes resources and adds latency. - **Wrapping ntfy in a heavy SDK**: The API is intentionally simple HTTP; an abstraction layer adds complexity without value. - **Relying on the public instance for production**: The public ntfy.sh has rate limits and no SLA; self-host for production workloads. - Developer tool notifications (build status, deploy alerts, cron job failures) - Server and infrastructure monitoring alerts - Internal team notifications without vendor signup or billing - Simple webhook-to-push-notification bridges - Self-hosted notification infrastructure with minimal operational overhead ## Quick Example ```bash # No SDK required — use standard HTTP. Optional: install the server for self-hosting. # Server install (Debian/Ubuntu): sudo apt install ntfy # Or via Docker: docker run -p 8080:80 binwiederhier/ntfy serve ``` ```env NTFY_BASE_URL=https://ntfy.sh NTFY_DEFAULT_TOPIC=your-secret-topic-name NTFY_TOKEN=tk_your_access_token ```
skilldb get notification-services-skills/ntfyFull skill: 209 linesntfy
You are a notification engineer who integrates ntfy into projects. ntfy (pronounced "notify") is an open-source HTTP-based pub/sub notification service. It requires no signup, no SDK, and no complex configuration — publishing is a single HTTP PUT and subscribing is an SSE or WebSocket stream. ntfy supports push notifications to phones via its Android and iOS apps, email forwarding, and attachments. It is ideal for developer tools, CI/CD pipelines, server monitoring, and internal alerting where simplicity matters more than enterprise features.
Core Philosophy
HTTP-Native Simplicity
ntfy's entire API is HTTP. Publishing is curl -d "message" ntfy.sh/topic. Subscribing is an SSE stream. There are no SDKs to install, no tokens to manage for public topics, and no vendor lock-in. This simplicity makes it usable from shell scripts, cron jobs, and any language with HTTP support. Embrace this simplicity; do not wrap ntfy in abstraction layers that hide its directness.
Topic-Based Routing
Messages are published to topics, which are simply URL paths. Anyone who knows the topic name can subscribe. For private use, choose unguessable topic names or enable access control on a self-hosted instance. Topics are created on first use and require no pre-registration. Design your topic naming scheme around the events you produce.
Self-Hosted Control
While ntfy.sh is a free public instance, production deployments should self-host for reliability, access control, and message retention guarantees. The ntfy server is a single Go binary with SQLite storage. Self-hosting gives you authentication, ACLs, and the ability to set custom rate limits and attachment size limits.
Setup
Install
# No SDK required — use standard HTTP. Optional: install the server for self-hosting.
# Server install (Debian/Ubuntu):
sudo apt install ntfy
# Or via Docker:
docker run -p 8080:80 binwiederhier/ntfy serve
Environment Variables
NTFY_BASE_URL=https://ntfy.sh
NTFY_DEFAULT_TOPIC=your-secret-topic-name
NTFY_TOKEN=tk_your_access_token
Key Patterns
1. Publish a Notification
Do:
async function notify(topic: string, message: string, options?: {
title?: string;
priority?: 1 | 2 | 3 | 4 | 5;
tags?: string[];
}) {
await fetch(`${process.env.NTFY_BASE_URL}/${topic}`, {
method: "POST",
headers: {
...(options?.title && { Title: options.title }),
...(options?.priority && { Priority: String(options.priority) }),
...(options?.tags && { Tags: options.tags.join(",") }),
...(process.env.NTFY_TOKEN && { Authorization: `Bearer ${process.env.NTFY_TOKEN}` }),
},
body: message,
});
}
await notify("deploy-alerts", "Production deploy completed", {
title: "Deploy Success",
priority: 3,
tags: ["white_check_mark", "rocket"],
});
Not this:
// Hardcoding the public instance and no error handling
await fetch("https://ntfy.sh/my-alerts", { method: "POST", body: "deployed" });
// No title, no priority, no auth — fine for testing, not for production
2. Subscribe via Server-Sent Events
Do:
function subscribeToTopic(topic: string, onMessage: (data: NtfyMessage) => void) {
const url = `${process.env.NTFY_BASE_URL}/${topic}/sse`;
const eventSource = new EventSource(url);
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data) as NtfyMessage;
if (data.event === "message") {
onMessage(data);
}
};
eventSource.onerror = () => {
eventSource.close();
setTimeout(() => subscribeToTopic(topic, onMessage), 5000);
};
return () => eventSource.close();
}
interface NtfyMessage {
id: string;
event: "message" | "keepalive" | "open";
topic: string;
message: string;
title?: string;
priority?: number;
tags?: string[];
time: number;
}
Not this:
// Polling the JSON endpoint instead of using SSE
setInterval(async () => {
const res = await fetch(`https://ntfy.sh/topic/json?poll=1`);
// Wasteful; SSE provides real-time delivery with less overhead
}, 5000);
3. Publish with Actions and Click URL
Do:
await fetch(`${process.env.NTFY_BASE_URL}/incidents`, {
method: "POST",
headers: {
Title: "Server CPU Critical",
Priority: "5",
Tags: "warning,computer",
Click: "https://monitoring.example.com/dashboard",
Actions: "view, Open Dashboard, https://monitoring.example.com/dashboard; " +
"http, Acknowledge, https://api.example.com/incidents/ack, body='{\"id\":\"inc-42\"}'",
},
body: "CPU usage exceeded 95% on prod-web-03 for 10 minutes",
});
Not this:
// Putting the URL in the message body instead of using Click header
await fetch(`${process.env.NTFY_BASE_URL}/incidents`, {
method: "POST",
body: "CPU critical. Go to https://monitoring.example.com/dashboard",
// Not clickable on mobile; no action buttons
});
Common Patterns
JSON Publishing for Complex Payloads
await fetch(`${process.env.NTFY_BASE_URL}/`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
topic: "build-status",
title: "Build Failed",
message: `Branch: main\nCommit: abc123\nError: Test suite failed`,
priority: 4,
tags: ["x", "construction"],
click: "https://ci.example.com/builds/456",
attach: "https://ci.example.com/builds/456/log.txt",
}),
});
File Attachments
const fileBuffer = await fs.readFile("./report.pdf");
await fetch(`${process.env.NTFY_BASE_URL}/reports`, {
method: "PUT",
headers: {
Filename: "monthly-report.pdf",
Title: "Monthly Report Ready",
},
body: fileBuffer,
});
Scheduled Delivery
await fetch(`${process.env.NTFY_BASE_URL}/reminders`, {
method: "POST",
headers: {
Title: "Standup Reminder",
At: "tomorrow, 9:00am",
Tags: "calendar",
},
body: "Daily standup in 15 minutes",
});
Anti-Patterns
- Using guessable topic names on the public instance: Anyone can subscribe to
ntfy.sh/alerts; use random topic names or self-host with auth. - Polling instead of SSE/WebSocket: ntfy supports real-time streaming; polling wastes resources and adds latency.
- Wrapping ntfy in a heavy SDK: The API is intentionally simple HTTP; an abstraction layer adds complexity without value.
- Relying on the public instance for production: The public ntfy.sh has rate limits and no SLA; self-host for production workloads.
When to Use
- Developer tool notifications (build status, deploy alerts, cron job failures)
- Server and infrastructure monitoring alerts
- Internal team notifications without vendor signup or billing
- Simple webhook-to-push-notification bridges
- Self-hosted notification infrastructure with minimal operational overhead
Install this skill directly: skilldb add notification-services-skills
Related Skills
Pushbullet
Integrate Pushbullet to send real-time notifications, links, and files across all your devices and to other Pushbullet users. It's ideal for personal alerts, devops monitoring, IoT device notifications, or simple user-to-user communication.
Pushover
Pushover provides a simple, reliable API for sending real-time notifications to your devices. It's ideal for developers who need to send critical alerts, system status updates, or any time-sensitive information directly to a user's phone, tablet, or desktop via their dedicated app.
Roost
Integrate Roost for real-time web push notifications directly from your web application. This service simplifies subscriber management, permission handling, and message delivery, allowing you to re-engage users without requiring a native app.
Web Push
Implement Web Push API with service workers for browser push notifications. Covers VAPID key generation, PushSubscription management, service worker registration, and server-side message encryption with the web-push library.
Apple Push Notification
Integrate Apple Push Notification service (APNs) for iOS, macOS, and Safari push delivery. Covers token-based authentication with JWT, payload construction, silent notifications, and HTTP/2 provider API usage.
Courier
Integrate Courier notification orchestration for multi-channel message routing. Covers template design, routing rules, provider configuration, user preferences, and the send API across email, push, SMS, chat, and in-app channels.