push.send() call, Sublay can automatically push in-app events (comments, mentions, follows, chat messages, …) to a user’s registered devices. This page covers the surfaces that control that automatic delivery:
- Per-user preferences — each user can disable push for specific event types.
- Per-conversation mute — a user can silence a single conversation’s push for a duration or forever.
- Per-event copy templates & project-level toggles — the developer authors the push title/body per event type and can disable an event project-wide, from the dashboard.
The event palette
Every automatic push is keyed by an event type. These are the server’s exact type names — the full app-notification set plus the chatmessage event (which is push-only and writes no in-app notification):
entity-comment, comment-reply, entity-mention, comment-mention, entity-reaction, comment-reaction, entity-reaction-milestone-specific, entity-reaction-milestone-total, comment-reaction-milestone-specific, comment-reaction-milestone-total, new-follow, connection-request, connection-accepted, space-membership-approved, event-invite, event-updated, event-cancelled, message.
The same names are used everywhere: a user’s disabledTypes, the project-level per-event toggle, and the template map all key on this exact list. The SDKs export the list as PUSH_EVENT_TYPES (@sublay/core, @sublay/node, @sublay/js).
Preference & mute model
Per-user preferences (disabledTypes)
Each user has at most one preference row, holding the set of event types they’ve opted out of for push. The model is:
- Absence of a row = all-on. A user with no preference row receives push for every enabled event type. Reading preferences for such a user returns
{ "disabledTypes": [] }. - Updating replaces the set. The update endpoint upserts the whole
disabledTypesarray — send the complete set you want stored, not a delta. - Only valid type names are accepted. Unknown names are rejected server-side.
Per-conversation mute (mutedUntil / mutedForever)
A user can mute a single conversation for a fixed duration or forever. Mute suppresses the message push for that conversation only; the message is still delivered, socket-emitted, and available in the conversation as normal.
The client sends a duration choice, never a raw timestamp — the server resolves the window from its own clock so client skew can’t distort it:
Timed mutes expire lazily — once the window passes, push resumes with no user action.
The viewer’s own member row (
currentMember) is serialized as:
Mute state is personal. A member’s
mutedUntil / mutedForever is present only on that member’s own row. Endpoints that return other members’ rows (listMembers, changeMemberRole, addMember, the member:joined socket broadcast) omit both keys entirely — a user’s mute state is never exposed to other participants.Gating precedence
When an event fires, whether a push is dispatched is decided in this order:- Project-level event disable (dashboard toggle) — if the developer disabled the event, no one is pushed.
- Conversation mute (chat
messageonly) — muted members are dropped. - Per-user type toggle — users who disabled the type are dropped.
- Send to everyone remaining who has a registered device.
Copy templates & project-level toggles (dashboard)
The developer authors the push title/body copy per event type and can disable an event project-wide, from Settings → Push Notifications in the dashboard, beside the provider configuration.- Each event type has an editable template field and a project-level enable toggle.
- A template is a plain-text string with
{variableName}placeholders. Substitution is plain-text only — no expressions, no markup execution. Unknown tokens render empty. - If a project configures no template for an event, a shipped default is used. Template edits take effect on the next send.
Template variable palette
Each event exposes a fixed set of variables its template may interpolate. Values come from the notification metadata (app-notification events) or the message context (message). A token that isn’t in the event’s list renders empty.
Example template for
entity-comment:
Privacy
Muted-conversation content and disabled-type content is simply not dispatched — when a mute or a preference suppresses a push, the notification’s title/body (which for chat/comments contains a content snippet) is never sent to APNs, FCM, or Web Push at all. Suppression happens before any provider call, so muted/opted-out content never leaves Sublay’s infrastructure to a third-party push provider.Building a settings UI
The SDKs expose the read/update primitives so you can build a notification-settings screen and per-conversation mute control:useNotificationPreferences
Read + update the current user’s disabled types (React / RN / Expo)
useMuteConversation
Set / clear the current user’s conversation mute
Node SDK — Push Notifications
push.getNotificationPreferences / updateNotificationPreferences, chat.muteConversationJS SDK — Push Notifications
push.getNotificationPreferences / updateNotificationPreferences, chat.muteConversationAPI endpoints
Mute Conversation
POST /chat/conversations/:conversationId/muteGet Notification Preferences
GET /push-notifications/preferencesUpdate Notification Preferences
PUT /push-notifications/preferences
