Self-hosted. Single binary. Multi-tenant by default.

Real-time events your users never miss

Self-host a WebSocket event layer that authorizes every frame, replays missed events on reconnect, and scales across instances. Turn on chat and presence only where you need them.

~8,000 msg/s · p50 0.10msSingle port, zero external DB11 SDKs, all codegen-verified

Compose what you need

Run only the surface area your product uses

Pick from four Docker images. Transport is always in. Add chat, add presence, add both, or keep it pure for service-to-service events — same wire protocol, same SDKs.

Always included

Transport

Ship events now, catch up missed ones on reconnect. Publish, subscribe, ephemeral triggers, delivery acks, stream and member CRUD, multi-tenant auth — the core you get in every image.

ghcr.io/skeptik-io/herald-transport
Opt-in

Chat engine

Drop in the chat semantics you'd otherwise hand-roll — edits, deletes, reactions, read cursors, typing indicators, and server-side block filtering that stops fanout before it leaves the box.

ghcr.io/skeptik-io/herald-chat
Opt-in

Presence engine

Real presence, not just a green dot. Manual away / dnd / appear-offline with per-override expiry, a tenant-wide broadcast stream, watchlist awareness, batch queries, and overrides that survive restarts.

ghcr.io/skeptik-io/herald-presence
Chat + Presence

Social (default)

Everything wired up — full chat and rich presence in one image. Reach for this when you're building messaging, team workspaces, or creator platforms.

ghcr.io/skeptik-io/herald

Delivery semantics

Go fast by default, go durable when it matters

Every subscriber gets sub-millisecond fanout out of the box. Flip on ack mode for the streams that can't afford a dropped event and Herald redelivers until the client confirms — no client changes required elsewhere.

Best-effort real-time

Reach every connected subscriber in under a millisecond. Reconnect catch-up paginates through the WAL retention window, so a user who drops wifi for 20 seconds comes back caught up — not refreshed.

  • ~8,000 msg/s, p50 0.10ms end-to-end
  • Strict per-stream FIFO via atomic seq
  • Paginated catch-up across reconnects

At-least-once (opt-in)

Set ackMode: "required" and Herald tracks acks per subscriber by seq. Unacked events redeliver on reconnect until the client confirms. Dedupe by seq on your side.

  • Per-subscriber high-water-mark tracking
  • Redelivery queue survives restarts
  • Fully backwards compatible with no-ack clients

Production-grade

Answer the security review without a roadmap

Clustered fanout, end-to-end encryption, observability, audit trails, and GDPR deletion — everything buyers ask about, shipped in the binary. No plugins, no enterprise tier.

Scale out without sharding users

Run as many Herald instances as you need against a shared store and pub/sub backplane. Any subscriber receives events published on any node.

Encrypted at rest, out of the box

The ShroudB WAL encrypts every record with your master key. Skip the separate disk-encryption setup and the DB-level key management review.

E2EE your server can't read

TypeScript, Go, Python, and Ruby clients ship interoperable x25519 + AES-256-GCM with HMAC blind tokens for searchable encryption. Ciphertext in, ciphertext out.

Trace every event end-to-end

Per-stage latency histograms at /metrics and W3C traceparent propagation across HTTP and WebSocket frames via the otel feature — plug straight into your existing stack.

Answer auditors with a query

Chronicle v1.5 runs in-process with per-tenant hash chains, diff tracking, and a filterable query API. When compliance asks, you have receipts.

GDPR delete in one call

Admin endpoints purge a full tenant or a single user across streams, reactions, cursors, presence, and blocks — no manual cleanup across tables.

SDK coverage

Write in your language, stay on one protocol

Browser clients for real-time, admin SDKs for every backend language. The admin SDKs generate from OpenAPI and run against shared contract tests — so your Go service and your TypeScript service never disagree.

Browser / WebSocket

Run in the browser with zero external deps

  • @skeptik-io/herald-sdk
    Connect, reconnect, dedupe, and encrypt — the browser client handles it for you
  • @skeptik-io/herald-chat-sdk
    Wire up edits, deletes, cursors, typing, and reactions without writing frame handlers
  • @skeptik-io/herald-presence-sdk
    Set presence and clear overrides with one call from the browser
  • @skeptik-io/herald-chat
    Own your UI, borrow the state machine — messages, members, presence, typing, cursors
  • @skeptik-io/herald-chat-react
    Ship faster in React with hooks and headless components

Server-side admin HTTP

Generated from OpenAPI, contract-tested across languages

  • @skeptik-io/herald-adminTypeScript
  • herald-admin-goGo
  • herald-adminPython
  • herald-adminRuby
  • herald-admin-phpPHP
  • Herald.AdminC#

Use cases

Built for the products you're already shipping

Chat and messaging

Ship a full messaging product without writing your own sync layer — typing, reactions, read receipts, edits, deletes, blocks, presence with overrides.

ChatPresence

Collaboration tools

Broadcast cursors and selections at real-time speed with typing, presence, and ephemeral triggers you don't have to persist.

ChatPresence

Creator and fan platforms

Give creators the presence controls they actually want — away, dnd, appear-offline — plus watchlist notifications scoped per tenant.

Presence

IoT and activity feeds

Get strict per-stream ordering, at-least-once delivery, and webhook mirroring for pipelines that can't drop an event.

Transport

Live dashboards

Push updates to every viewer in real time with ephemeral triggers, fanout filtering, and an OpenTelemetry trace on every frame.

Transport

Multi-tenant SaaS

Onboard tenants without provisioning infrastructure — isolated storage, self-service token rotation, per-tenant retention, one key+secret each.

TransportChatPresence
Design principle

Keep your database canonical. Use Herald for the live stuff.

Think Pusher, Ably, or Centrifugo — not a message store. The internal WAL is a short-horizon catch-up buffer (default 7 days, pruned hourly) so reconnecting clients replay the deltas they missed without refreshing the page.

Inside the buffer window, Herald owns deltas. Across it, your app database owns state. A webhook mirrors every event — edits, deletes, reactions — into your DB as it happens, so the two stay aligned.

Rule of thumb: if you're deciding where something lives past a reconnect window, it lives in your DB. Herald is the expiring pipe that remembers just long enough to make reconnects seamless.

Self-host quickstart

One container. One port. One master key.

Pull an image, generate a key, run the container. Herald provisions a default tenant on first boot — save the printed credentials and you're live.

deploy.sh
docker pull ghcr.io/skeptik-io/herald:latest

docker run -d \
  -p 6200:6200 \
  -e SHROUDB_MASTER_KEY="$(openssl rand -hex 32)" \
  -e HERALD_AUTH_PASSWORD="your-admin-password" \
  -v herald-data:/data \
  ghcr.io/skeptik-io/herald:latest

Pick your image

  • heralddefault — chat + presence
  • herald-transporttransport only
  • herald-chattransport + chat
  • herald-presencetransport + presence
WebSocket and HTTP share port 6200. TLS terminates at your reverse proxy.

Your first event on the wire in a minute

Pull the image, run the container, provision a stream. No account to create, no sales call, no credit card.