Pipe alerts, deploys and CI straight to your phone — emit a signal from anything that can run curl.
Quick look · Features · Packages · Getting started · Architecture
EmitSignal is a self-hostable, real-time notification platform built for developers. Publishers POST messages to named topics; subscribers receive them live over Server-Sent Events in the web dashboard and mobile app, and as push notifications on their phone. Emails and push are dispatched asynchronously through queued workers, so publishing stays fast.
No SDK required to send — if it can make an HTTP request, it can emit a signal. The publish API is ntfy-style: set everything through headers and skip the JSON.
Two ways to send a signal: curl needs nothing installed, the CLI is nicer to live in.
With curl — works from anything that can make an HTTP request
Publish a message — header-based, no body parsing required:
curl -X POST https://emitsignal.com/publish/alerts \
-H "X-Title: Deploy finished" \
-H "X-Priority: high" \
-H "X-Tags: ci,prod" \
-d "v2.4.0 shipped to production"Or send JSON, authenticated with an API key:
curl -X POST https://emitsignal.com/publish/alerts \
-H "Authorization: Bearer es_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "title": "Latency alert", "body": "p99 over 800ms", "priority": 5, "tags": ["prod"] }'Subscribe and stream signals live over SSE:
# one topic
curl -N https://api.emitsignal.com/topics/alerts/listen
# several at once, replaying the last 10 minutes first
curl -N "https://api.emitsignal.com/listen?topics=alerts,ci,deploys&since=$(($(date +%s000) - 600000))"Schedule for later — relative durations (30m, 2h, 1d) or a unix timestamp:
curl -X POST https://emitsignal.com/publish/reminders \
-H "X-Title: Stand-up in 30 minutes" \
-H "X-Delay: 30m" \
-d "Don't forget the daily"With the CLI — emitsignal, aliased to es
Install — a single static binary, no runtime required:
npm i -g @emitsignal/cli
# or the install script
curl -fsSL https://github.com/emitsignal/emitsignal/releases/latest/download/install.sh | shAuthenticate once — writes a token to ~/.emitsignalrc:
es loginPublish a message — the title defaults to the first line of the body:
es publish alerts "v2.4.0 shipped to production" \
--title "Deploy finished" \
--priority 4 \
--tag ci,prod
# ✓ published → alerts · cmt4hcs5m000001t64ujxh3m5 · 73msSubscribe and stream signals live:
# one topic
es listen alerts
# every subscription, replaying the last 10 minutes first
es listen --since 10m
# glob a channel, and only surface high-priority signals
es listen --channel "alerts/*" --priority ">=4"Point it at a self-hosted instance:
es config set-url https://signals.internal.example.comScheduling is header-only for now — es publish has no --delay flag yet, so use the
curl form above for delayed signals.
-
Topics —
POST /publish/<topic>to any named topic; subscribers tune in by name, no pre-registration. Topic names may contain slashes (alerts/prod,ci/web). -
Live delivery (SSE) —
GET /topics/:name/listenorGET /listen?topics=a,b,c, both with?since=backlog replay and heartbeats. - Push notifications — delivered to the Expo mobile app (iOS, Android) via queued workers.
-
Priorities —
1–5, or the aliasesmin/low/default/high/urgent. -
Tags & actions — categorize with
X-Tags, attach interactiveX-Actionsto a message. -
Scheduling —
X-Delayaccepts relative durations (5m,2h,1d,1w) or a unix timestamp, up to a year out. -
Webhooks — receive from external services at
POST /h/:slugwith built-in templates forgithub,grafana,stripe,vercel, andcustom. - Attachments — upload files alongside a message, stored locally or on S3.
-
Flexible auth — magic link, passkey (WebAuthn), API keys (
es_…), and optional GitHub and Apple sign-in, via Better Auth. - Rate limiting — per-IP and per-user limits, backed by Redis, fail-open if Redis is down.
-
Email digests — transactional emails through a pluggable provider (
log,smtp, or Resend).
This is a Bun workspace monorepo.
| Package | Description |
|---|---|
@emitsignal/server |
Elysia API — topics, auth, SSE, queued delivery |
@emitsignal/website |
TanStack Start web dashboard |
@emitsignal/mobile |
Expo React Native app (iOS, Android, Web) |
@emitsignal/cli |
Terminal client — publish and stream from your shell |
@emitsignal/shared |
Shared TypeScript types and API client |
@emitsignal/emails |
React Email templates |
@emitsignal/docs |
Mintlify documentation site (CLI & API reference) |
@emitsignal/docker |
Docker Compose stack for local dev and deployment |
@emitsignal/e2e-testing |
Playwright end-to-end tests |
You'll need Bun >= 1.3 and Docker.
bun install
docker compose -f packages/emitsignal-docker/docker-compose.dev.yml upThat brings up the whole stack with hot reload — PostgreSQL, Redis, an SMTP inbox (localhost:3134), all BullMQ workers, the API server (localhost:5100) and the website (localhost:5173).
Run pieces by hand (without Docker)
# API + workers
cd packages/emitsignal-server
cp .env.example .env # edit DATABASE_URL, REDIS_URL, etc.
bun run db:migrate && bun run db:seed
bun run dev:worker # all workers (separate terminal)
bun run dev # API server
# web dashboard
cd packages/emitsignal-website && bun run dev
# mobile app
cd packages/emitsignal-mobile && bun run startWorkspace-wide scripts run from the root: bun format, bun lint, bun test, and bun dev (runs dev in every package).
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Website │ SSE/HTTP │ Server │ BullMQ │ Workers │
│ (TanStack) │ ◄──────────► │ (Elysia) │ ────────────► │ email/push/ │
└─────────────┘ └──────┬──────┘ │ schedule │
│ └──────┬──────┘
┌─────────────┐ ┌──────┴──────┐ │
│ Mobile │ SSE/HTTP │ PostgreSQL │ ┌──────┴──────┐
│ (Expo/RN) │ ◄──────────► │ + Redis │ │ Email │
└─────────────┘ └─────────────┘ │ Provider │
│ smtp/resend │
└─────────────┘
A publish immediately fires an in-process event bus (powering live SSE) and enqueues a push job; scheduled messages skip the bus and go straight to the schedule queue. Dedicated workers drain the email, push, and schedule queues so the publish path never blocks on delivery.
Bun · Elysia · Prisma + PostgreSQL · Redis + BullMQ · Better Auth · TanStack Start · Expo / React Native · React Email · Tailwind CSS · TypeScript
