React bindings for the Hiyve SDK. Provides a provider component, 31 hooks, and optional cloud integration for building video conferencing applications with React 18+.
npx @hiyve/cli login
npm install @hiyve/react @hiyve/core @hiyve/rtc-client
To use cloud features (AI, room discovery, meeting intelligence), also install:
npm install @hiyve/cloud
import { HiyveProvider, useConnection, useRoom, useParticipants, useLocalMedia } from '@hiyve/react';
function App() {
return (
<HiyveProvider>
<VideoRoom />
</HiyveProvider>
);
}
function VideoRoom() {
const { joinRoom, isConnecting, error } = useConnection();
const { room, isInRoom, isOwner } = useRoom();
const { participants, participantCount } = useParticipants();
const { isAudioMuted, isVideoMuted, toggleAudio, toggleVideo } = useLocalMedia();
if (!isInRoom) {
return (
<button onClick={() => joinRoom('my-room', 'user-123')} disabled={isConnecting}>
{isConnecting ? 'Joining...' : 'Join Room'}
</button>
);
}
return (
<div>
<h1>{room?.name} ({participantCount} participants)</h1>
<button onClick={toggleAudio}>{isAudioMuted ? 'Unmute' : 'Mute'}</button>
<button onClick={toggleVideo}>{isVideoMuted ? 'Camera On' : 'Camera Off'}</button>
</div>
);
}
Each hook tracks only its relevant state, so components re-render only when their data changes.
| Hook | Returns |
|---|---|
useConnection() |
isConnected, isConnecting, error, createRoom, joinRoom, joinRoomWithToken, getRoomInfoFromToken, leaveRoom |
useRoom() |
room, isOwner, isInRoom, isNoVideo |
useNoVideoRoom() |
isConnected, isConnecting, error, isNoVideo, isInRoom, room, createNoVideoRoom, joinNoVideoRoom, closeNoVideoRoom, setActiveRoom |
useClient() |
Raw rtc-client instance (Client | null) |
| Hook | Returns |
|---|---|
useParticipants() |
participants (array), participantsMap, localUserId, participantCount |
useParticipant(userId) |
Single Participant | undefined for a specific user |
useLocalMedia() |
isAudioMuted, isVideoMuted, isOutputMuted, isScreenSharing, toggleAudio, toggleVideo, toggleOutputMute, startScreenShare, stopScreenShare |
useDevices() |
setVideoDevice, setAudioInputDevice, setAudioOutputDevice |
useRemoteMute() |
remoteMuteAudio, remoteMuteVideo, muteRemoteOutput |
useOutputMute() |
muteRemoteOutput |
| Hook | Returns |
|---|---|
useRecording() |
isRecording, isRecordingStarting, recordingId, recordingStartTime, responseId, error, recordingDuration, startRecording, stopRecording, clearError |
useStreaming() |
isStreaming, isStreamingStarting, streamingId, featuredUserId, streamingStartTime, streamingUrl, error, streamingDuration, startStreaming, stopStreaming, switchStreamingUser, getStreamingUrls, clearError |
useTranscription() |
isTranscribing, isTranscriptionStarting, transcriptions, startTranscription, stopTranscription, enrichTranscription |
| Hook | Returns |
|---|---|
useChat() |
messages, unreadCount, sendMessage, sendDataMessage, clearUnread, loadChatHistory |
useWaitingRoom() |
waitingUsers, isWaitingForAdmission, wasRejected, admitUser, rejectUser |
useWaitForHost() |
isWaiting, roomName, timeout, elapsedTime |
useAiChat() |
messages, setMessages |
| Hook | Returns |
|---|---|
useIntelligenceStream() |
isActive, coachingEnabled, coachingVariant, hints, allHints, talkRatio, currentTopic, topicShifts, enableCoaching, disableCoaching, updateCoachingData, dismissHint |
| Hook | Returns |
|---|---|
useLayout() |
dominantSpeaker, setDominant |
useHandRaise() |
raisedHands, isHandRaised, raisedHandCount, toggleHandRaised, lowerAllHands |
useAudioProcessing() |
feedbackDetected, audioValidation, gainNode, audioInputMonitor, setGain |
| Hook | Returns |
|---|---|
useStoredRooms() |
rooms, isLoading, error, lastFetchedAt, fetchStoredRooms, addStoredRoom, updateStoredRoom, deleteStoredRoom, getStoredRoom, clearError, clearStoredRooms |
useUserFiles() |
files, isLoading, error, lastFetchedAt, fetchUserFiles, deleteFile, renameFile, moveFile, shareFile, createFolder, deleteFolder, getFileUrl, uploadFile, clearError |
useActiveRooms() |
rooms, isConnected, isLoading, error, connectActiveRooms, disconnectActiveRooms, fetchActiveRooms, advertiseRoom, removeAdvertisedRoom, updateAdvertisedRoom, clearError |
| Hook | Returns |
|---|---|
useJoinToken(options) |
Token validation, room info, password handling, auto-join |
| Hook | Returns |
|---|---|
useRoomFlow() |
screen ('lobby' | 'connecting' | 'waiting-for-host' | 'waiting-room' | 'waiting-room-rejected' | 'in-room'), isConnecting, isInRoom |
| Hook | Returns |
|---|---|
useAdditionalCameras(options) |
cameras, addCamera, removeCamera, removeAll, ghostUserIds, isGhostCamera, getLabel |
useRemoteCamera(options) |
startPairing, disconnect, qrUrl, status, ghostUserId, error, isExpired |
| Hook | Returns |
|---|---|
useCloudClient() |
CloudClient | null -- the cloud client from HiyveProvider, or null if no cloud auth was configured |
useUserChat() |
conversations, activeRoomName, activeMessages, isLoading, isLoadingHistory, error, nextCursor, fetchConversations, fetchHistory, sendMessage, setActiveConversation, loadMore |
Manages global chat conversations via the cloud service. Fetches conversation lists, loads message history with cursor-based pagination, sends messages with optimistic updates, and subscribes to real-time message delivery when a conversation is active.
import { useUserChat } from '@hiyve/react';
function ChatView({ userId }: { userId: string }) {
const {
conversations,
activeMessages,
isLoading,
isLoadingHistory,
nextCursor,
fetchConversations,
setActiveConversation,
fetchHistory,
sendMessage,
loadMore,
} = useUserChat();
useEffect(() => {
fetchConversations(userId);
}, [userId, fetchConversations]);
return (
<div>
{conversations.map((c) => (
<button key={c.roomName} onClick={() => {
setActiveConversation(c.roomName);
fetchHistory(c.roomName);
}}>
{c.roomName}
</button>
))}
{activeMessages.map((m) => (
<p key={m.id}>{m.userId}: {m.content}</p>
))}
{nextCursor && <button onClick={loadMore} disabled={isLoadingHistory}>Load older</button>}
</div>
);
}
Manages additional camera feeds that join as separate ghost participants. Each camera creates an independent WebRTC connection, so the feed appears automatically in recordings and live streams.
import { useAdditionalCameras } from '@hiyve/react';
function CameraManager() {
const { cameras, addCamera, removeCamera, removeAll } = useAdditionalCameras({
roomName: 'my-room',
ownerUserId: 'user@example.com',
generateRoomToken: async () => {
const res = await fetch('/api/generate-room-token', { method: 'POST' });
const data = await res.json();
return data.roomToken;
},
enabled: true,
});
return (
<div>
<button onClick={() => addCamera('device-id-123', 'Document Camera')}>Add Camera</button>
{cameras.map((cam) => (
<div key={cam.id}>
{cam.label} - {cam.isActive ? 'Active' : cam.isConnecting ? 'Connecting...' : 'Error'}
<button onClick={() => removeCamera(cam.id)}>Remove</button>
</div>
))}
</div>
);
}
Options (UseAdditionalCamerasOptions):
| Option | Type | Default | Description |
|---|---|---|---|
roomName |
string |
-- | Room name to join ghost cameras into |
ownerUserId |
string |
-- | Owner's userId (used to build ghost camera userIds) |
generateRoomToken |
() => Promise<string> |
-- | Async function that returns a room token for the ghost client |
enabled |
boolean |
true |
Whether the hook is enabled |
onError |
(error: Error, cameraId: string) => void |
-- | Callback when an error occurs |
Returns (UseAdditionalCamerasReturn):
| Property | Type | Description |
|---|---|---|
cameras |
AdditionalCamera[] |
List of all additional cameras (connecting, active, or errored) |
addCamera |
(deviceId: string, label?: string) => Promise<void> |
Add a new camera by device ID |
removeCamera |
(id: string) => Promise<void> |
Remove a specific camera by instance ID |
removeAll |
() => Promise<void> |
Remove all additional cameras |
ghostUserIds |
Set<string> |
Set of active ghost camera userIds |
isGhostCamera |
(userId: string) => boolean |
Check if a userId is a ghost camera |
getLabel |
(userId: string) => string | null |
Get the display label for a ghost camera userId |
Manages pairing a remote device (e.g., a phone) as an additional camera feed via QR code. The remote device joins the room as a ghost participant using a time-limited join token.
import { useRemoteCamera } from '@hiyve/react';
function RemoteCameraPairing() {
const { startPairing, disconnect, qrUrl, status, isExpired } = useRemoteCamera({
roomName: 'my-room',
ownerUserId: 'user@example.com',
enabled: true,
});
if (status === 'connected') {
return <button onClick={disconnect}>Disconnect Phone Camera</button>;
}
return (
<div>
<button onClick={startPairing}>Pair Phone Camera</button>
{qrUrl && <img src={`https://api.qrserver.com/v1/create-qr-code/?data=${encodeURIComponent(qrUrl)}`} alt="QR Code" />}
{isExpired && <p>Link expired. Tap to generate a new one.</p>}
</div>
);
}
Options (UseRemoteCameraOptions):
| Option | Type | Default | Description |
|---|---|---|---|
roomName |
string |
-- | Room name to pair the remote camera into |
ownerUserId |
string |
-- | Owner's userId |
baseUrl |
string |
window.location.origin |
Base URL for the QR code link |
joinPath |
string |
'/camera' |
Path for the camera page |
expiresIn |
number |
300 |
Token expiry in seconds |
label |
string |
'Phone' |
Label for the ghost camera |
enabled |
boolean |
true |
Whether the hook is enabled |
Returns (UseRemoteCameraReturn):
| Property | Type | Description |
|---|---|---|
startPairing |
() => Promise<void> |
Initiate pairing (generates join token and QR URL) |
disconnect |
() => void |
Disconnect the remote camera |
qrUrl |
string | null |
URL to display as a QR code |
status |
'idle' | 'waiting' | 'connected' | 'error' |
Current pairing status |
ghostUserId |
string | null |
Ghost userId for the remote camera |
error |
string | null |
Error message if pairing failed |
isExpired |
boolean |
Whether the current token has expired |
Utility functions for working with ghost camera participant IDs. Re-exported from @hiyve/core.
| Export | Type | Description |
|---|---|---|
GHOST_CAMERA_DELIMITER |
string |
The delimiter used in ghost camera userIds ('__cam__') |
isGhostCamera(userId) |
(userId: string) => boolean |
Returns true if the userId belongs to a ghost camera participant |
getGhostCameraLabel(userId) |
(userId: string) => string | null |
Extracts the human-readable label from a ghost camera userId |
getGhostCameraOwner(userId) |
(userId: string) => string | null |
Extracts the owner's userId from a ghost camera userId |
buildGhostCameraUserId(ownerUserId, label) |
(ownerUserId: string, label: string) => string |
Builds a ghost camera userId from the owner's userId and a label |
HiyveProvider is the recommended provider. It accepts all HiyveStoreOptions plus optional cloud configuration:
| Prop | Type | Default | Description |
|---|---|---|---|
generateRoomToken |
() => Promise<string> |
auto | Returns a Hiyve room token. Defaults to POST /api/generate-room-token when using @hiyve/admin server middleware |
localVideoElementId |
string |
'local-video' |
ID of the local video element |
connectOptions |
{ videoDeviceId?, audioDeviceId? } |
{} |
Initial device IDs |
persistDeviceChanges |
boolean |
false |
Persist device selections across sessions |
onError |
(error: Error) => void |
- | Error callback |
generateCloudToken |
() => Promise<string> |
auto | Returns a short-lived cloud token. Defaults to POST /api/generate-cloud-token when using @hiyve/admin server middleware |
cloudToken |
string |
- | Static cloud token. Use generateCloudToken instead for auto-refresh |
cloudEnvironment |
'production' | 'development' |
'production' |
Cloud API environment |
cloudBaseUrl |
string |
- | Override the cloud API base URL |
presence |
boolean | { intervalMs?: number } |
- | Enable automatic presence heartbeat. When true, the cloud client signals the server that the current user is online |
Both room tokens and cloud tokens are generated automatically when your server uses @hiyve/admin middleware. HiyveProvider calls POST /api/generate-room-token and POST /api/generate-cloud-token by default -- no props needed.
// Zero-config -- room and cloud tokens are generated automatically
<HiyveProvider>
<App />
</HiyveProvider>
You can still pass custom generators or static tokens to override the defaults:
// Custom token generators (override the defaults)
<HiyveProvider
generateRoomToken={myCustomRoomTokenGenerator}
generateCloudToken={myCustomCloudTokenGenerator}
>
<App />
</HiyveProvider>
A stable CloudClient instance is available to all child components via useCloudClient():
import { useCloudClient } from '@hiyve/react';
function MyComponent() {
const cloudClient = useCloudClient();
if (!cloudClient) return <p>Cloud not configured</p>;
// Use cloudClient for AI queries, room discovery, etc.
}
When used alongside @hiyve/react-identity, the IdentityProvider automatically provides the authenticated user's email to cloud services and the HiyveProvider. This allows cloud tokens to be generated for the correct user without passing userId manually.
import { IdentityBridgeContext, useIdentityEmail } from '@hiyve/react';
| Export | Type | Description |
|---|---|---|
IdentityBridgeContext |
React.Context |
Connects IdentityProvider to CloudProvider so cloud tokens include the authenticated user |
useIdentityEmail() |
() => string | null |
Returns the authenticated identity user's email, or null |
For custom integrations, access the HiyveStore directly:
import { useStore } from '@hiyve/react';
function CustomComponent() {
const store = useStore();
// Access store methods for custom integrations
}
All core state types are re-exported from @hiyve/core for convenience:
import type {
HiyveStoreState,
Participant,
RoomInfo,
ChatMessage,
TranscriptionEntry,
RecordingState,
StreamingState,
WaitingRoomUser,
// ... and more
} from '@hiyve/react';
Types specific to @hiyve/react hooks:
import type {
// Chat
UserChatMessage,
// Room flow
RoomFlowScreen,
UseRoomFlowReturn,
// Join token
UseJoinTokenState,
UseJoinTokenActions,
UseJoinTokenOptions,
// Additional cameras
AdditionalCamera,
UseAdditionalCamerasOptions,
UseAdditionalCamerasReturn,
// Remote camera
UseRemoteCameraOptions,
UseRemoteCameraReturn,
} from '@hiyve/react';
Join token error codes, re-exported from @hiyve/core:
| Constant | Value | Description |
|---|---|---|
TOKEN_NOT_FOUND |
'TOKEN_NOT_FOUND' |
Token does not exist (HTTP 404) |
TOKEN_EXPIRED |
'TOKEN_EXPIRED' |
Token has expired (HTTP 410) |
INVALID_PASSWORD |
'INVALID_PASSWORD' |
Incorrect room password (HTTP 401) |
USER_NOT_AUTHORIZED |
'USER_NOT_AUTHORIZED' |
User is not allowed to join via this token (HTTP 403) |
ROOM_NOT_ACTIVE |
'ROOM_NOT_ACTIVE' |
Room is not active yet (HTTP 503) |
| Function | Description |
|---|---|
resolveTabsConfig(config, mode) |
Resolves a StoredRoomTabsConfig into a flat TabsFeatureConfig for 'offline' or 'live' mode. Handles structured, legacy flat, and null configs. Re-exported from @hiyve/core. |
cleanUserId(userId) |
Sanitizes a user ID string for use with the signaling server. Re-exported from @hiyve/rtc-client. |
@hiyve/core and @hiyve/rtc-client as peer dependencies@hiyve/cloud as optional peer dependency (for cloud features)@hiyve/core -- Framework-agnostic state store (works with React, Angular, Vue, or any framework)@hiyve/react-ui -- Pre-built UI components (video tile, video grid, control bar, sidebar)@hiyve/react-capture -- Recording, streaming, and transcription components@hiyve/react-collaboration -- Chat, polls, Q&A, and file manager components@hiyve/react-intelligence -- AI assistant, meeting summary, alerts, and sentiment@hiyve/react-notes -- Collaborative meeting notes@hiyve/react-whiteboard -- Collaborative whiteboardProprietary - Hiyve SDK
@hiyve/react - React bindings for the Hiyve SDK core state store.
Remarks
This package provides React hooks that efficiently track state changes from the @hiyve/core HiyveStore. Each hook re-renders only when its relevant data changes.