Notifications
Read notification data and build custom inbox surfaces.
useNotifications()
useNotifications() is the main notification list hook. It is the same stateful surface that powers <NotificationPanel />, including pagination, optimistic read and archive actions, and live inserts from the notification stream.
export default function Inbox() { const { loading, notifications, hasMore, markAsRead, archiveNotification, loadMore, } = useNotifications({ scope: 'all', is_archived: false, }); if (loading) { return <div>Loading notifications...</div>; } return ( <div className="space-y-4"> <ul className="space-y-2"> {notifications.map((notification) => ( <li key={notification.id} className="rounded-xl border p-4"> <div className="font-medium">{notification.title}</div> <p className="text-sm text-muted-foreground">{notification.body}</p> <div className="mt-3 flex gap-2"> {!notification.is_read ? ( <button onClick={() => markAsRead(notification.id)}>Mark as read</button> ) : null} <button onClick={() => archiveNotification(notification.id)}> {notification.is_archived ? 'Unarchive' : 'Archive'} </button> </div> </li> ))} </ul> {hasMore ? <button onClick={loadMore}>Load more</button> : null} </div> );}›params?: UseNotificationsOptions | undefined | undefined;
params?: UseNotificationsOptions | undefined | undefined;›limit?: number | undefined | undefined;
limit?: number | undefined | undefined;›cursor?: string | undefined | undefined;
cursor?: string | undefined | undefined;›scope?: 'all' | 'current' | 'user' | 'organization' | 'workspace' | undefined | undefined;
scope?: 'all' | 'current' | 'user' | 'organization' | 'workspace' | undefined | undefined;›channels?: ('user' | 'organization' | 'workspace' | 'current' | 'all')[] | undefined | undefined;
channels?: ('user' | 'organization' | 'workspace' | 'current' | 'all')[] | undefined | undefined;›organization_ids?: string[] | undefined | undefined;
organization_ids?: string[] | undefined | undefined;›workspace_ids?: string[] | undefined | undefined;
workspace_ids?: string[] | undefined | undefined;›is_read?: boolean | undefined | undefined;
is_read?: boolean | undefined | undefined;›is_archived?: boolean | undefined | undefined;
is_archived?: boolean | undefined | undefined;›is_starred?: boolean | undefined | undefined;
is_starred?: boolean | undefined | undefined;›severity?: 'info' | 'success' | 'warning' | 'error' | undefined | undefined;
severity?: 'info' | 'success' | 'warning' | 'error' | undefined | undefined;›onNotification?: ((notification: NotificationMessage) => void) | undefined | undefined;
onNotification?: ((notification: NotificationMessage) => void) | undefined | undefined;›loading?: boolean | undefined;
loading?: boolean | undefined;›notifications?: Notification[] | undefined;
notifications?: Notification[] | undefined;›id?: string | undefined;
id?: string | undefined;›deployment_id?: string | undefined;
deployment_id?: string | undefined;›user_id?: string | undefined;
user_id?: string | undefined;›organization_id?: string | undefined | undefined;
organization_id?: string | undefined | undefined;›workspace_id?: string | undefined | undefined;
workspace_id?: string | undefined | undefined;›title?: string | undefined;
title?: string | undefined;›body?: string | undefined;
body?: string | undefined;›ctas?: { label: string; payload: any }[] | undefined | undefined;
ctas?: { label: string; payload: any }[] | undefined | undefined;›label?: string | undefined;
label?: string | undefined;›payload?: any | undefined;
payload?: any | undefined;›severity?: 'info' | 'success' | 'warning' | 'error' | undefined;
severity?: 'info' | 'success' | 'warning' | 'error' | undefined;›is_read?: boolean | undefined;
is_read?: boolean | undefined;›read_at?: string | undefined | undefined;
read_at?: string | undefined | undefined;›is_archived?: boolean | undefined;
is_archived?: boolean | undefined;›archived_at?: string | undefined | undefined;
archived_at?: string | undefined | undefined;›is_starred?: boolean | undefined;
is_starred?: boolean | undefined;›metadata?: Record<string, any> | undefined | undefined;
metadata?: Record<string, any> | undefined | undefined;›created_at?: string | undefined;
created_at?: string | undefined;›updated_at?: string | undefined;
updated_at?: string | undefined;›expires_at?: string | undefined | undefined;
expires_at?: string | undefined | undefined;›hasMore?: boolean | undefined;
hasMore?: boolean | undefined;›error?: Error | null | undefined;
error?: Error | null | undefined;›markAsRead?: (notificationId: string) => Promise<void> | undefined;
markAsRead?: (notificationId: string) => Promise<void> | undefined;›markAllAsRead?: () => Promise<void> | undefined;
markAllAsRead?: () => Promise<void> | undefined;›archiveAllRead?: () => Promise<void> | undefined;
archiveAllRead?: () => Promise<void> | undefined;›archiveNotification?: (notificationId: string) => Promise<void> | undefined;
archiveNotification?: (notificationId: string) => Promise<void> | undefined;›starNotification?: (notificationId: string) => Promise<void> | undefined;
starNotification?: (notificationId: string) => Promise<void> | undefined;›markAsUnread?: (notificationId: string) => Promise<void> | undefined;
markAsUnread?: (notificationId: string) => Promise<void> | undefined;›refetch?: () => Promise<void> | undefined;
refetch?: () => Promise<void> | undefined;›loadMore?: () => Promise<void> | undefined;
loadMore?: () => Promise<void> | undefined;useNotificationStream()
useNotificationStream() manages the live websocket connection for notification updates. It is the low-level stream hook that useNotifications() uses to prepend new notifications into the cached list, but you can also use it directly when you need connection state or custom live handling.
import { useNotificationStream } from '@wacht/nextjs';export default function NotificationConnectionStatus() { const { isConnected, connectionError, reconnect } = useNotificationStream({ channels: ['user', 'organization'], }); return ( <div> <div>{isConnected ? 'Connected' : 'Disconnected'}</div> {connectionError ? <p>{connectionError}</p> : null} <button onClick={reconnect}>Reconnect</button> </div> );}›enabled?: boolean | undefined;
enabled?: boolean | undefined;›channels?: string[] | undefined;
channels?: string[] | undefined;›organizationIds?: number[] | undefined;
organizationIds?: number[] | undefined;›workspaceIds?: number[] | undefined;
workspaceIds?: number[] | undefined;›onNotification?: (notification: NotificationMessage) => void | undefined;
onNotification?: (notification: NotificationMessage) => void | undefined;›onError?: (error: string) => void | undefined;
onError?: (error: string) => void | undefined;›reconnectDelay?: number | undefined;
reconnectDelay?: number | undefined;›maxReconnectAttempts?: number | undefined;
maxReconnectAttempts?: number | undefined;›isConnected?: boolean | undefined;
isConnected?: boolean | undefined;›connectionError?: string | null | undefined;
connectionError?: string | null | undefined;›disconnect?: () => void | undefined;
disconnect?: () => void | undefined;›reconnect?: () => void | undefined;
reconnect?: () => void | undefined;›NotificationMessage?: { id: number; user_id: number; deployment_id: number; title: string; body: string; severity: string; ctas?: { label: string; payload: any }[]; created_at: string } | undefined;
NotificationMessage?: { id: number; user_id: number; deployment_id: number; title: string; body: string; severity: string; ctas?: { label: string; payload: any }[]; created_at: string } | undefined;›id?: number | undefined;
id?: number | undefined;›user_id?: number | undefined;
user_id?: number | undefined;›deployment_id?: number | undefined;
deployment_id?: number | undefined;›title?: string | undefined;
title?: string | undefined;›body?: string | undefined;
body?: string | undefined;›severity?: string | undefined;
severity?: string | undefined;›ctas?: { label: string; payload: any }[] | undefined | undefined;
ctas?: { label: string; payload: any }[] | undefined | undefined;›label?: string | undefined;
label?: string | undefined;›payload?: any | undefined;
payload?: any | undefined;›created_at?: string | undefined;
created_at?: string | undefined;useNotificationUnreadCount()
useNotificationUnreadCount() is the lightweight unread-count hook behind <NotificationBell /> and other summary UI. Use it when you only need the unread total for a scope and do not need the full notification list.
import { useNotificationUnreadCount } from '@wacht/nextjs';export default function NotificationBadge() { const { loading, count } = useNotificationUnreadCount({ scope: 'current' }); if (loading || count === 0) { return null; } return <span>{count}</span>;}›params?: NotificationListParams | undefined | undefined;
params?: NotificationListParams | undefined | undefined;›limit?: number | undefined | undefined;
limit?: number | undefined | undefined;›cursor?: string | undefined | undefined;
cursor?: string | undefined | undefined;›scope?: 'all' | 'current' | 'user' | 'organization' | 'workspace' | undefined | undefined;
scope?: 'all' | 'current' | 'user' | 'organization' | 'workspace' | undefined | undefined;›channels?: ('user' | 'organization' | 'workspace' | 'current' | 'all')[] | undefined | undefined;
channels?: ('user' | 'organization' | 'workspace' | 'current' | 'all')[] | undefined | undefined;›organization_ids?: string[] | undefined | undefined;
organization_ids?: string[] | undefined | undefined;›workspace_ids?: string[] | undefined | undefined;
workspace_ids?: string[] | undefined | undefined;›is_read?: boolean | undefined | undefined;
is_read?: boolean | undefined | undefined;›is_archived?: boolean | undefined | undefined;
is_archived?: boolean | undefined | undefined;›is_starred?: boolean | undefined | undefined;
is_starred?: boolean | undefined | undefined;›severity?: 'info' | 'success' | 'warning' | 'error' | undefined | undefined;
severity?: 'info' | 'success' | 'warning' | 'error' | undefined | undefined;›loading?: boolean | undefined;
loading?: boolean | undefined;›count?: number | undefined;
count?: number | undefined;›error?: Error | null | undefined;
error?: Error | null | undefined;›refetch?: () => Promise<void> | undefined;
refetch?: () => Promise<void> | undefined;