import { StreamVideoClient, User } from "@stream-io/video-react-sdk";
const user: User = { id: "sara" };
const apiKey = "my-stream-api-key"; // from dashboard.getstream.io
const tokenProvider = async () => fetchTokenFromYourServer(user.id);
const client = new StreamVideoClient({ apiKey, user, tokenProvider });Client & Authentication
Set up StreamVideoClient to connect users and join calls.
Best Practices
- Create
StreamVideoClientonce at app root; usetokenProviderfor auto-refresh. - Always clean up with
client.disconnectUser()in useEffect return. - Use short-lived tokens with a
tokenProviderfor production. - Handle connection errors with try/catch around
connectUser().
Basic setup
- The API Key can be found in your dashboard.
- The user can be either authenticated, anonymous or guest.
- You can store custom data on the user object if required.
Typically, initialize the client when your application loads and use a context provider to make it available throughout your app.
Generating a token
Tokens must be generated server-side. Use our server-side SDKs to add support for this - typically integrated with your login/registration flow.
Here are credentials to try out the app with:
| Property | Value |
|---|---|
| API Key | mmhfdzb5evj2 |
| Token | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3Byb250by5nZXRzdHJlYW0uaW8iLCJzdWIiOiJ1c2VyL1RocmlsbGluZ19DbG92ZXIiLCJ1c2VyX2lkIjoiVGhyaWxsaW5nX0Nsb3ZlciIsInZhbGlkaXR5X2luX3NlY29uZHMiOjYwNDgwMCwiaWF0IjoxNzcxNDA1MjcyLCJleHAiOjE3NzIwMTAwNzJ9.ydXnPNBq-VTCbRe6_JWW6Bbt5UUbh2c7mUVH5LGG8tw |
| User ID | Thrilling_Clover |
| Call ID | EhbmenSskpoYMdExL2ozG |
For development purposes, you can use our Token Generator.
User types
- Authenticated users - users with an account in your app.
- Guest users - temporary accounts with a name and image.
- Anonymous users - unauthenticated users (common for livestream viewers).
Guest users
Example setup for a guest user:
import { StreamVideoClient, User } from "@stream-io/video-react-sdk";
const user: User = { id: "jack-guest", type: "guest" };
const apiKey = "my-stream-api-key";
const client = new StreamVideoClient({ apiKey, user });Anonymous users
Example for an anonymous user:
import { StreamVideoClient, User } from "@stream-io/video-react-sdk";
const user: User = { type: "anonymous" };
const apiKey = "my-stream-api-key";
const client = new StreamVideoClient({ apiKey, user });Anonymous users don't establish a WebSocket connection, so they won't receive events. They can only watch livestreams or join calls.
The token for anonymous users should include call_cids - an array of call CIDs they're allowed to join:
{
"iss": "@stream-io/dashboard",
"iat": 1726406693,
"exp": 1726493093,
"user_id": "!anon",
"role": "viewer",
"call_cids": ["livestream:123"]
}Connecting a user and error handling
Connect users in two ways:
Automatic connection - when creating the client:
const client = new StreamVideoClient({
apiKey,
user,
token,
options: {
maxConnectUserRetries: 3,
onConnectUserError: (err: Error, allErrors: Error[]) => {
console.error("Failed to connect user", err, allErrors);
// handle the connect error, i.e. ask the user to retry
// later when they have better connection or show an error message
},
},
});Manual connection - using client.connectUser():
const client = new StreamVideoClient({ apiKey });
try {
await client.connectUser(user, token);
} catch (err) {
console.error("Failed to connect user", err);
// handle the connect error
}Disconnecting a user
Discard a client instance or disconnect a user with client.disconnectUser():
await client.disconnectUser();Client options
token or tokenProvider
Authenticate users with a string token or a tokenProvider function that returns Promise<string>.
import { StreamVideoClient, User } from "@stream-io/video-react-sdk";
const tokenProvider = async () => {
const response = await fetch("/api/token");
const data = await response.json();
return data.token;
};
const user: User = { id: "sara" };
const apiKey = "my-stream-api-key";
const client = new StreamVideoClient({ apiKey, tokenProvider, user });Reject incoming call when busy
Auto-reject incoming ringing calls when the user is already in a call:
import { StreamVideoClient } from "@stream-io/video-react-native-sdk";
const client = new StreamVideoClient({
apiKey,
tokenProvider,
user,
options: { rejectCallWhenBusy: true },
});Logging
The SDK uses scoped logging with configurable levels per module. Log levels ordered by severity:
| Level | Severity |
|---|---|
| trace | 0 |
| debug | 1 |
| info | 2 |
| warn | 3 |
| error | 4 |
import { StreamVideoClient, Logger } from "@stream-io/video-react-sdk";
const client = new StreamVideoClient({
apiKey,
token,
user,
options: {
logOptions: {
default: {
level: "info",
},
coordinator: {
level: "warn",
sink: (logLevel, message, ...rest) => {
switch (logLevel) {
case "warn": {
console.warn(message, ...rest);
break;
}
case "error": {
SuperLogger.error(message, ...rest);
}
}
},
},
},
},
});Configure the default scope to apply settings globally:
import { videoLoggerSystem } from "@stream-io/video-client";
import SuperLogger from "./SuperLogger";
videoLoggerSystem.configureLoggers({
default: {
level: "info",
sink: (logLevel, message, ...rest) => {
SuperLogger[logLevel](message, ...rest);
},
},
});Reset specific scopes to defaults:
import { videoLoggerSystem } from "@stream-io/video-client";
videoLoggerSystem.configureLoggers({
"event-dispatcher": {
level: null,
sink: null,
},
});Reset all scopes to defaults:
import { videoLoggerSystem } from "@stream-io/video-client";
videoLoggerSystem.restoreDefaults();Sentry integration
Example Sentry integration:
import { LogLevel, Sink, logToConsole } from "@stream-io/video-client";
import * as Sentry from "@sentry/nextjs";
const logLevelMapping = new Map<LogLevel, Sentry.SeverityLevel>();
logLevelMapping.set("debug", "debug");
logLevelMapping.set("info", "info");
logLevelMapping.set("warn", "warning");
logLevelMapping.set("error", "error");
export const customSentryLogger: Sink = (
logLevel: LogLevel,
message: string,
...args: unknown[]
) => {
if (logLevel === "warn" || logLevel === "error") {
Sentry.captureEvent({
level: logLevelMapping.get(logLevel),
extra: args,
});
}
// Call the SDK's default log method
logToConsole(logLevel, message, { data: "some data" });
};StreamVideo context provider
The StreamVideo provider makes the client available throughout your app:
import { useEffect, useState } from "react";
import {
StreamVideo,
StreamVideoClient,
User,
} from "@stream-io/video-react-sdk";
const apiKey = "my-stream-api-key";
const user: User = { id: "sara", name: "Sara" };
export const MyApp = () => {
const [client, setClient] = useState<StreamVideoClient>();
useEffect(() => {
const tokenProvider = () => Promise.resolve("<token>");
const myClient = new StreamVideoClient({ apiKey, user, tokenProvider });
setClient(myClient);
return () => {
myClient.disconnectUser();
setClient(undefined);
};
}, []);
if (!client) return null;
return (
<StreamVideo client={client}>
<MyVideoApp />
</StreamVideo>
);
};