Skip to content

Notifications

OriginChats has two ways to tell a user about a new message. A connected client can raise its own alert when a message_new event arrives. A client that is closed can still get a Web Push notification, which the server sends through Rotur. This guide covers both. Neither is needed to send or receive messages.

When a message_new event arrives, add the message to your state first, then decide whether to alert.

The server doesn’t know the user’s notification settings, muted channels, or blocked users. Those are decisions for your client. The message tells you what you need:

  • message.pings.users lists mentioned usernames.
  • message.pings.roles lists mentioned role IDs.
  • message.pings.replies lists the author of the message being replied to, when the reply pings them.

The message schema describes these fields.

Identify each alert by server, channel or thread, and message ID. That stops duplicates without merging alerts from different servers. When the user clicks an alert, open that same conversation.

When someone posts a message, the server picks recipients and asks Rotur to deliver a notification to each of them. Rotur then sends a Web Push message to every browser the recipient registered.

The server picks recipients according to the operator’s notifications.mode:

Mode Who is notified
mentions People mentioned directly or through a role, and the author of a message that was replied to with ping on.
all Every member who can see the channel.

In both modes the server skips the author, banned members, members who left, users severed from the author, and anyone who can’t see the channel.

Only messages sent with message_new trigger push. Webhook posts, slash command replies, and system messages don’t.

The server sends notifications after it saves the message. It retries up to three times on network errors, HTTP 429, and 5xx responses. A message arriving over the WebSocket doesn’t mean a push was delivered.

Web Push needs a secure context (HTTPS), a service worker, a Push API subscription, notification permission, and a signed-in Rotur account. Native system notifications are outside this flow.

With rotur-sdk:

  1. Get Rotur’s VAPID key with rotur.push.vapidKeys().
  2. Create or reuse a browser subscription through PushManager.
  3. Register the subscription’s endpoint and its p256dh and auth keys with Rotur, under the source originChats.
  4. Allow the server’s owner to send you notifications under that source.
await rotur.push.register(
subscription.endpoint,
bytesToBase64url(subscription.getKey("p256dh")!),
bytesToBase64url(subscription.getKey("auth")!),
"originChats",
deviceFingerprint,
);
await rotur.push.allowSender(ownerUsername, "originChats");
  • bytesToBase64url is your own helper that encodes bytes as base64url.
  • deviceFingerprint is a stable ID you choose for this browser registration. Check an existing one with rotur.push.check("originChats", deviceFingerprint).
  • ownerUsername is handshake.val.server.owner.name.

originChats is the default source. An operator can change it with the notifications.source setting.

Allowing a sender covers every server that owner runs, not only this one. To stop, call rotur.push.removeSender(ownerUsername, "originChats").

Update the registration when the subscription endpoint or VAPID key changes. When a different account signs in on the same browser, register again for that account.

The server sends Rotur a notification with a title, a body, the recipients’ usernames, and a data object. Your service worker receives data with these fields:

Field Meaning
source The OriginChats server URL. Not the same as the originChats source label.
serverName The server’s display name.
channelName The channel name.
threadId The thread ID. Present only for thread messages.
messageId The message to open.
actor, from The sender’s username. Both hold the same value.
type mention, reply, or all.
title Display title, such as alice mentioned you in #general.
content A preview of the message, or Open OriginChats to view this message. when the operator hides content.

Check the target before you open it. Prefer switching to an existing connection for that server over building a URL from the payload.

In the service worker, wrap async work in event.waitUntil(...) so the browser keeps it alive. Before you skip a push because a window is open, check that the window is actually showing that conversation. Use the message ID to match a push with a live event you already showed.