The useRealtime hook connects your React components to realtime events with full type safety. 
Basic Usage  
Subscribe to events in any client component: 
"use client"  
 
import  {  useRealtime  }  from  "@upstash/realtime/client"  
import  type  {  RealtimeEvents  }  from  "@/lib/realtime"  
 
export  default  function  Page ()  {  
  useRealtime < RealtimeEvents >({  
    event:  "notification.alert" ,  
    onData ( data ,  channel ) {  
      console . log ( "Received:" ,  data )  
    },  
  })  
 
  return  < p > Listening for events... </ p >  
}  
 
Hook Options  
The event to subscribe to (e.g. "notification.alert") 
 
Callback when an event is received. Receives data and channel as arguments. 
 
channels
string[] 
default: "[\"default\"]" 
Array of channel names to subscribe to 
 
history
boolean | object 
default: "false" 
true: Fetch all available history 
{ length: number }: Fetch the last N messages 
{ since: number }: Fetch messages after a Unix timestamp (in milliseconds) 
  
Whether the connection is active. Set to false to disconnect. 
 
Maximum number of reconnection attempts before giving up 
 
API configuration: - url: The realtime endpoint URL, defaults to /api/realtime -
withCredentials: Whether to send cookies with requests (useful for external backends) 
 
Return Value  
The hook returns an object with: 
Current connection state: "connecting", "connected", "reconnecting",
"disconnected", or "error" 
 
const  {  status  }  =  useRealtime < RealtimeEvents >({  
  event:  "notification.alert" ,  
  onData :  ( data ,  channel )  =>  {},  
})  
 
console . log ( status )  
 
Connection Control  
Enable or disable connections dynamically: 
"use client"  
 
import  {  useState  }  from  "react"  
import  {  useRealtime  }  from  "@upstash/realtime/client"  
import  type  {  RealtimeEvents  }  from  "@/lib/realtime"  
 
export  default  function  Page ()  {  
  const  [ enabled ,  setEnabled ]  =  useState ( true )  
 
  const  {  status  }  =  useRealtime < RealtimeEvents >({  
    enabled ,  
    event:  "notification.alert" ,  
    onData :  ( data ,  channel )  =>  {  
      console . log ( data ,  channel )  
    },  
  })  
 
  return  (  
    < div >  
      < button  onClick = { ()  =>  setEnabled (( prev )  =>  ! prev ) } >  
        { enabled  ?  "Disconnect"  :  "Connect" }  
      </ button >  
 
      < p > Status:  { status } </ p >  
    </ div >  
  )  
}  
 
Conditional Connections  
Connect only when certain conditions are met: 
"use client"  
 
import  {  useRealtime  }  from  "@upstash/realtime/client"  
import  type  {  RealtimeEvents  }  from  "@/lib/realtime"  
import  {  useUser  }  from  "@/hooks/auth"  
 
export  default  function  Page ()  {  
  const  {  user  }  =  useUser ()  
 
  useRealtime < RealtimeEvents >({  
    enabled:  Boolean ( user ),  
    channels:  [ `user- ${ user . id } ` ],  
    event:  "notification.alert" ,  
    onData :  ( data ,  channel )  =>  {  
      console . log ( data )  
    },  
  })  
 
  return  < p > Notifications  { user  ?  "enabled"  :  "disabled" } </ p >  
}  
 
Multiple Channels  
Subscribe to multiple channels at once: 
"use client"  
 
import  {  useRealtime  }  from  "@upstash/realtime/client"  
import  type  {  RealtimeEvents  }  from  "@/lib/realtime"  
 
export  default  function  Page ()  {  
  useRealtime < RealtimeEvents >({  
    channels:  [ "global" ,  "announcements" ,  "user-123" ],  
    event:  "notification.alert" ,  
    onData ( data ,  channel ) {  
      console . log ( `Message from  ${ channel } :` ,  data )  
    },  
  })  
 
  return  < p > Listening to multiple channels </ p >  
}  
 
Dynamic Channel Management  
Add and remove channels dynamically: 
"use client"  
 
import  {  useState  }  from  "react"  
import  {  useRealtime  }  from  "@upstash/realtime/client"  
import  type  {  RealtimeEvents  }  from  "@/lib/realtime"  
 
export  default  function  Page ()  {  
  const  [ channels ,  setChannels ]  =  useState < string []>([ "lobby" ])  
 
  useRealtime < RealtimeEvents >({  
    channels ,  
    event:  "chat.message" ,  
    onData ( data ,  channel ) {  
      console . log ( `Message from  ${ channel } :` ,  data )  
    },  
  })  
 
  const  joinRoom  =  ( roomId :  string )  =>  {  
    setChannels (( prev )  =>  [ ... prev ,  roomId ])  
  }  
 
  const  leaveRoom  =  ( roomId :  string )  =>  {  
    setChannels (( prev )  =>  prev . filter (( c )  =>  c  !==  roomId ))  
  }  
 
  return  (  
    < div >  
      < p > Active channels:  { channels . join ( ", " ) } </ p >  
      < button  onClick = { ()  =>  joinRoom ( "room-1" ) } > Join Room 1 </ button >  
      < button  onClick = { ()  =>  joinRoom ( "room-2" ) } > Join Room 2 </ button >  
      < button  onClick = { ()  =>  leaveRoom ( "lobby" ) } > Leave Lobby </ button >  
    </ div >  
  )  
}  
 
Fetch History on Connection  
Replay past messages when connecting: 
"use client"  
 
import  {  useState  }  from  "react"  
import  {  useRealtime  }  from  "@upstash/realtime/client"  
import  type  {  RealtimeEvents  }  from  "@/lib/realtime"  
 
export  default  function  ChatRoom ()  {  
  const  [ messages ,  setMessages ]  =  useState < string []>([])  
 
  useRealtime < RealtimeEvents >({  
    event:  "chat.message" ,  
    history:  {  length:  50  },  
    onData ( data ,  channel ) {  
      // each history item is automatically passed to this handler  
      // so you can replay with any logic you like  
      setMessages (( prev )  =>  [ ... prev ,  data ])  
    },  
  })  
 
  return  (  
    < div >  
      { messages . map (( msg ,  i )  =>  (  
        < p  key = { i } > { msg } </ p >  
      )) }  
    </ div >  
  )  
}  
 
Custom API Endpoint  
Configure a custom realtime endpoint: 
"use client"  
 
import  {  useRealtime  }  from  "@upstash/realtime/client"  
import  type  {  RealtimeEvents  }  from  "@/lib/realtime"  
 
export  default  function  Page ()  {  
  useRealtime < RealtimeEvents >({  
    event:  "notification.alert" ,  
    api:  {  
      url:  "/api/custom-realtime" ,  
      withCredentials:  true ,  
    },  
    onData :  ( data ,  channel )  =>  {  
      console . log ( data )  
    },  
  })  
 
  return  < p > Connected to custom endpoint </ p >  
}  
 
Use Cases  
Show real-time notifications to users: "use client"  
 
import  {  useState  }  from  "react"  
import  {  useRealtime  }  from  "@upstash/realtime/client"  
import  type  {  RealtimeEvents  }  from  "@/lib/realtime"  
import  {  toast  }  from  "react-hot-toast"  
import  {  useUser  }  from  "@/hooks/auth"  
 
export  default  function  Notifications ()  {  
  const  {  user  }  =  useUser ()  
 
  useRealtime < RealtimeEvents >({  
    channels:  [ `user- ${ user . id } ` ],  
    event:  "notification.alert" ,  
    onData ( content ,  channel ) {  
      toast ( content )  
    },  
  })  
 
  return  < p > Listening for notifications... </ p >  
}  
Build a real-time chat: "use client"  
 
import  {  useState  }  from  "react"  
import  {  useRealtime  }  from  "@upstash/realtime/client"  
import  type  {  RealtimeEvents  }  from  "@/lib/realtime"  
import  z  from  "zod/v4"  
 
type  Message  =  z . infer < RealtimeEvents [ "chat" ][ "message" ]>  
 
export  default  function  Chat ()  {  
  const  [ messages ,  setMessages ]  =  useState < Message []>([])  
 
  useRealtime < RealtimeEvents >({  
    channels:  [ "room-123" ],  
    event:  "chat.message" ,  
    history:  true ,  
    onData ( message ,  channel ) {  
      setMessages (( prev )  =>  [ ... prev ,  message ])  
    },  
  })  
 
  return  (  
    < div >  
      { messages . map (( msg ,  i )  =>  (  
        < p  key = { i } >  
          < span  className = "font-bold" > { msg . sender } : </ span >  { msg . text }  
        </ p >  
      )) }  
    </ div >  
  )  
}  
Update metrics in real-time: "use client"  
 
import  {  useQuery ,  useQueryClient  }  from  "@tanstack/react-query"  
import  {  useRealtime  }  from  "@upstash/realtime/client"  
import  type  {  RealtimeEvents  }  from  "@/lib/realtime"  
 
export  default  function  Dashboard ()  {  
  const  queryClient  =  useQueryClient ()  
    
  const  {  data :  metrics  }  =  useQuery ({  
    queryKey:  [ "metrics" ],  
    queryFn :  async  ()  =>  {  
      const  res  =  await  fetch ( "/api/metrics?user=user-123" )  
      return  res . json ()  
    },  
  })  
 
  useRealtime < RealtimeEvents >({  
    channels:  [ "user-123" ],  
    event:  "metrics.update" ,  
    onData () {  
      // 👇 invalidate, so react-query refetches  
      queryClient . invalidateQueries ({  queryKey:  [ "metrics" ] })  
    },  
  })  
 
  return  (  
    < div >  
      < p > Active Users:  { metrics . users } </ p >  
      < p > Revenue: $ { metrics . revenue } </ p >  
    </ div >  
  )  
}  
Sync changes across users: "use client"  
 
import  {  useState  }  from  "react"  
import  {  useRealtime  }  from  "@upstash/realtime/client"  
import  type  {  RealtimeEvents  }  from  "@/lib/realtime"  
 
export  default  function  Editor ({  documentId  } :  {  documentId :  string  })  {  
  const  [ content ,  setContent ]  =  useState ( "" )  
 
  useRealtime < RealtimeEvents >({  
    channels:  [ `doc- ${ documentId } ` ],  
    event:  "document.update" ,  
    history:  {  length:  1  },  
    onData ( data ,  channel ) {  
      setContent ( data . content )  
    },  
  })  
 
  return  < textarea  value = { content }  onChange = { ( e )  =>  setContent ( e . target . value ) }  />  
}  
 
Next Steps