Push
Send push notifications
The push channel is provided by @betternotify/push. It defines slots for title, body, optional data payload, and badge count.
When to use push
Push is the right channel when the notification should appear instantly on the user's device as a system-level alert. Use it for real-time events — new messages, live score updates, price alerts, or activity from other users — where the value is in the immediate interruption. Push also carries a data payload, so the app can navigate to the right screen when the user taps.
npm install @betternotify/pushSetup
import { createNotify } from '@betternotify/core';
import { pushChannel } from '@betternotify/push';
const push = pushChannel();
const rpc = createNotify({ channels: { push } });Slots
Prop
Type
Send arguments
Prop
Type
Full example
import { createNotify, createClient } from '@betternotify/core';
import { createMockTransport } from '@betternotify/core/transports';
import { pushChannel } from '@betternotify/push';
import { z } from 'zod';
const push = pushChannel();
const rpc = createNotify({ channels: { push } });
const catalog = rpc.catalog({
newMessage: rpc
.push()
.input(z.object({ sender: z.string(), preview: z.string() }))
.title(({ input }) => `New message from ${input.sender}`)
.body(({ input }) => input.preview)
.data(({ input }) => ({ sender: input.sender }))
.badge(() => 1),
});
const notify = createClient({
catalog,
transportsByChannel: { push: createMockTransport() },
});
await notify.newMessage.send({
to: 'device-token-abc123',
input: { sender: 'Ada', preview: 'Hey, are you coming to the meeting?' },
});
// Send to multiple devices
await notify.newMessage.send({
to: ['device-token-abc123', 'device-token-def456'],
input: { sender: 'Ada', preview: 'Hey, are you coming to the meeting?' },
});Transport
The push channel produces a RenderedPush with title, body, to, and optional data/badge. Better-Notify does not ship a built-in push provider transport — use createTransport to build one for your provider (FCM, APNs, Expo, etc.):
import { createTransport } from '@betternotify/core/transports';
import type { RenderedPush } from '@betternotify/push';
const fcmTransport = (serverKey: string) =>
createTransport<RenderedPush>({
name: 'fcm',
send: async (rendered) => {
const tokens = Array.isArray(rendered.to) ? rendered.to : [rendered.to];
const response = await fetch('https://fcm.googleapis.com/fcm/send', {
method: 'POST',
headers: {
Authorization: `key=${serverKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
registration_ids: tokens,
notification: { title: rendered.title, body: rendered.body, badge: rendered.badge },
data: rendered.data,
}),
});
const json = (await response.json()) as { success?: number; failure?: number };
if (json.failure) {
return { ok: false, error: new Error(`FCM: ${json.failure} failures`) };
}
return { ok: true, data: json };
},
});