WebSocket
Push real-time updates and notifications from Hono routes to the browser over a multiplexed, cookie-authenticated WebSocket connection.
VitNode provides a unified, multiplexed WebSocket connection at /api/ws. Browsers share a single connection across tabs via a Web Lock leader election, authenticated by session cookies.
Quick start
1. Send User Notification
Push real-time notifications to any signed-in user from any Hono route or service:
import { notificationsChannel } from "@vitnode/core/ws/notifications"
c.get("realtime").sendToUser(userId, notificationsChannel, {
title: "New Comment",
description: "Alex commented on your post.",
type: "info",
})The user receives an immediate sonner toast in all open tabs across devices.
2. Broadcast to Everyone
Broadcast live updates to all connected visitors:
c.get("realtime").broadcast(myChannel, {
count: 142,
})Define a Custom Channel
Create typed channels in your plugin:
import { defineWebSocketChannel } from "@vitnode/core/ws"
import { z } from "zod"
export interface MessagePayload {
roomId: string
message: string
senderId: number
}
export const chatChannel = defineWebSocketChannel<MessagePayload>({
id: "chat_room_messages",
schema: z.object({
roomId: z.string(),
message: z.string(),
senderId: z.number(),
}),
})Client-Side Consumption
Listen for incoming channel messages with useWebSocketChannel:
import { useWebSocketChannel } from "@vitnode/core/hooks/use-websocket-channel"
import { chatChannel } from "../ws/chat.channel"
export const ChatRoom = ({ roomId }: { roomId: string }) => {
const [messages, setMessages] = React.useState<string[]>([])
useWebSocketChannel(chatChannel, (payload) => {
if (payload.roomId === roomId) {
setMessages((prev) => [...prev, payload.message])
}
})
return (
<div>
{messages.map((msg, i) => (
<p key={i}>{msg}</p>
))}
</div>
)
}Architectural Highlights
- Single Connection: Only one
/api/wssocket is opened per client. All features share it via message multiplexing. - Tab Leader Election: When a user opens multiple tabs, a Web Lock elects one leader tab to hold the socket, distributing messages across tabs via
BroadcastChannel. - Automatic Reconnect: Backoff retry automatically re-establishes dropped connections within seconds.