Skip to main content
Technology & EngineeringNotification Services209 lines

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.

Quick Summary31 lines
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 lines
Paste into your CLAUDE.md or agent config

ntfy

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

Get CLI access →

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.

Notification Services155L

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.

Notification Services159L

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.

Notification Services278L

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.

Notification Services204L

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.

Notification Services236L

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.

Notification Services182L