How It Works
- Configure credentials in the dashboard — paste your APNs
.p8key, FCM service account JSON, or enable Web Push (keypair generated server-side). - Register devices — your client app calls
register()fromusePushRegistrationat a moment that makes sense for your UX (settings screen, first-run prompt, etc.). The SDK handles permission, token retrieval, and server registration. - Send notifications — your backend calls
sublay.push.send({ userIds, title, body, data }). Sublay fans the message out to every registered device for those users across all platforms.
Dashboard Setup
Installing the bundle
Open Database → Bundles in the dashboard and installpush. Once provisioning completes, the Push Notifications settings page becomes active.
Configuring providers
Go to Settings → Push Notifications in the dashboard. Configure each platform you want to support: APNs (iOS)
FCM (Android)
Upload or paste your Firebase service account JSON. This is the file downloaded from the Firebase console under Project Settings → Service Accounts → Generate new private key.
Web Push
No credentials to paste — click Enable. Sublay generates a VAPID EC keypair server-side and stores the private key encrypted. Only the public key is returned and displayed; it is also available via the unauthenticated
GET /vapid-public-key endpoint for use in your service worker.
Automatic push settings
Sublay can fan a push out automatically whenever an in-app notification is created (a new comment, reply, mention, reaction, follow, connection, RSVP-event change, space-membership approval) or a chat message is sent — nopush.send() call required. The Settings → Push Notifications page lets you tune what those automatic pushes look like per event type:
These settings affect only the automatic path. The manual
push.send() call already accepts title, sound, channelId, priority, and everything else directly.
See Automatic Pushes below for the full delivery-config, title-template, and tap-routing contract.
Test-send UI
Each provider card in the dashboard includes a Send Test Push panel. Supply a platform, a device token or subscription, a title, and a body, then click Send Test Push to verify credentials before shipping.Client SDK — Registering Devices
UseusePushRegistration with the adapter for your platform. Call register() in response to a deliberate user action — not on mount — because requesting OS push permission is a one-shot prompt that users cannot undo.
register(). See SDK Reference → Push Notifications for per-platform setup and usePushRegistration for the full hook API.
Server SDK — Sending Notifications
Callclient.push.send() from your backend whenever you want to notify users:
Rich Notification Payloads
Beyondtitle, body, and data, push.send() accepts optional fields for sound, badges, images, grouping, priority, and lifetime. Each maps to the native APNs / FCM / Web Push capability and is silently ignored on platforms that don’t support it — so you can set subtitle (iOS-only) and channelId (Android-only) in the same call without branching.
Client-side requirements
Three of these need setup in your app — Sublay forwards the field but cannot do this part for you:Android sound → notification channels
Android sound → notification channels
On Android 8+ the notification channel owns the sound, importance, and vibration — the payload can’t override it. Create the channel once in your app (with the bundled sound) and pass its id as Then
channelId:push.send({ ..., channelId: "messages", sound: "notification.wav" }). The sound field alone is only a pre-Android-8 fallback. Sublay does not create channels for you.iOS images → Notification Service Extension
iOS images → Notification Service Extension
iOS does not download remote images from the payload on its own. To show
imageUrl on iOS, add a Notification Service Extension to your app that reads the URL from the notification payload, downloads it, and attaches it. Sublay sets mutable-content automatically whenever imageUrl is present so the extension is allowed to run. Android and Web render imageUrl with no extra work.Web rendering → your service worker
Web rendering → your service worker
Sublay ships no service worker — your app’s own SW renders web notifications. The server forwards the web-renderable fields (
sound, image, tag) in the push JSON; your push event handler decides how to display them via registration.showNotification(...).Automatic Pushes
Whenever Sublay writes an in-app notification (a new comment, reply, mention, reaction, milestone, follow, connection request/accept, RSVP-event invite/update/cancel, or space-membership approval) or a chat message is sent, it can fan a native push out to the recipient’s registered devices automatically — you don’t callpush.send() for these. What each automatic push looks like is configured per project on the Settings → Push Notifications page.
Everything in this section applies to the automatic path only. The manual
push.send() call takes title, body, data, sound, channelId, priority, and the rich fields directly and is unchanged.Title & body templates
Each event type has a body template (shipped with sensible defaults) and an optional title template. Both are interpolated against the same per-event{variable} palette shown next to each row in the dashboard.
The title template ships empty for every event type — an unset title renders as an empty string, which is the historical behavior. Set a title only for the events where you want one; leaving it blank is a no-op.
Delivery: sound, channel & priority
You can set a project-wide default delivery block and, optionally, a per-event override:- Default — a single
{ sound, channelId, priority }applied to every automatic push. - Override — a per-event-type
{ sound, channelId, priority }. Any field you set on the override wins for that event; any field you leave unset inherits the project default. Precedence is per-event override → project default → none.
These are the same three fields
push.send() accepts, wired to the automatic path. The other rich fields (badge, imageUrl, tag, etc.) are configurable on the manual path only.
Tap-routing data
Every automatic push carries a flat data object of string identifiers so your app’s tap handler can deep-link to the right screen. All data values are flat top-level strings (FCM coerces data values with String(), so nested objects are not used).
Two keys are on every automatic push:
Beyond
type and action, each push forwards every identifier form for each object the notification references, so you can route on whichever id your app uses (UUID, short id, foreign id, slug, or username). Per referenced object:
Which of those apply depends on the event type:
Content and RSVP-event notifications also carry the parent space. A notification about an Entity or Comment (a “content notification”) or an RSVP-event notification additionally forwards the parent Space id set (
spaceId, spaceShortId, spaceSlug) when the subject lives in a space, so you can route within a space. Don’t confuse the message event type or an RSVP Event (the data model) with the generic idea of a “notification event.”These
data keys are additive and non-breaking. Existing tap handlers that ignore unknown keys are unaffected — nothing that was present before was removed or renamed. A key whose underlying value is absent (e.g. a user with no foreignId, a space with no slug) is simply omitted rather than sent empty.data from the send context rather than notification metadata, so it always carries exactly { type: "message", action: "open-conversation", conversationId, messageId }.
Device Lifecycle
- Re-registration: registering the same physical device again (same token or endpoint) updates the existing record instead of duplicating it.
- Device reassignment: if the same device is registered by a different user (e.g. a shared device after logout/login), the record is reassigned to the new user.
- Stale token cleanup: tokens or subscriptions permanently rejected by APNs, FCM, or Web Push during a send are automatically deleted — no separate cleanup pass is needed.
- Explicit logout: call
unregister()in your logout flow so the device stops receiving notifications after sign-out.
References
Everything related to push notifications across the docs:SDK Reference — Push Notifications
Per-platform client setup for Expo, React Native, and Web
usePushRegistration
Request permission, register, and unregister the current user’s device
Node SDK — Push Notifications
The
push.send() server module referenceWebhooks — Push Bridge
Forward
notification.created events to pushAPI Endpoints
Register Device
POST /push-notifications/devicesDeregister Device
DELETE /push-notifications/devicesSend Push
POST /push-notifications/sendGet VAPID Public Key
GET /push-notifications/vapid-public-key
