Broadcast Notifications
Send a notification to all active users at a scheduled time using a one-off event
one-off event broadcast notifications scheduled event webhook handler exampleA one-off scheduled event fires at a specific date and time. The handler sends a broadcast notification to all active users. You can see this in action in the react-demo example, see Notifications.tsx.
import { createHash, timingSafeEqual } from 'node:crypto'import { createClient, withAdminSession } from '@nhost/nhost-js'import type { Request, Response } from 'express'
const hash = (value: string) => createHash('sha256').update(value).digest()
export default async (req: Request, res: Response) => { // Validate the webhook secret — see the Webhook Security guide const webhookSecret = req.headers['nhost-webhook-secret'] as string | undefined const expected = process.env.NHOST_WEBHOOK_SECRET if ( !webhookSecret || !expected || !timingSafeEqual(hash(webhookSecret), hash(expected)) ) { return res.status(401).json({ message: 'Unauthorized' }) }
// One-off events and cron triggers deliver their payload at req.body.payload const payload = req.body.payload if (!payload) { return res.status(400).json({ message: 'No payload' }) }
// Extract the broadcast details from the payload configured in the dashboard const { title, message } = payload const type = payload.type || 'announcement'
if (!title) { return res.status(400).json({ message: 'Missing required field: title' }) } if (!message) { return res.status(400).json({ message: 'Missing required field: message' }) }
// Create an admin client to query the database const nhost = createClient({ region: process.env.NHOST_REGION, subdomain: process.env.NHOST_SUBDOMAIN, configure: [ withAdminSession({ adminSecret: process.env.NHOST_ADMIN_SECRET, }), ], })
// Fetch all active (non-disabled) users const { body } = await nhost.graphql.request<{ users: Array<{ id: string }> }>({ query: ` query GetActiveUsers { users(where: { disabled: { _eq: false } }) { id } } `, })
if (body.errors) { return res.status(500).json({ errors: body.errors }) }
const activeUsers = body.data?.users || []
if (activeUsers.length === 0) { return res.status(200).json({ message: 'No active users found' }) }
// Create a notification for every active user const notifications = activeUsers.map((u) => ({ user_id: u.id, title, message, type, }))
const insertResult = await nhost.graphql.request<{ insert_notifications: { affected_rows: number } | null }>({ query: ` mutation InsertNotifications($objects: [notifications_insert_input!]!) { insert_notifications(objects: $objects) { affected_rows } } `, variables: { objects: notifications }, })
if (insertResult.body.errors) { return res.status(500).json({ errors: insertResult.body.errors }) }
res.status(200).json({ message: `Broadcast sent to ${activeUsers.length} user(s)`, })}Related resources
Section titled “Related resources”- One-off event configuration — how to schedule the event
- Webhook Security — configuring the shared secret
- Full source code on GitHub