npm install @stream-io/video-react-sdkPrebuilt Components
Prebuilt components are drop-in React components that handle the entire call lifecycle in a single component. They manage client initialization, call joining, the complete meeting or livestream UI, and cleanup when the component is removed. You don't need to set up StreamVideoClient, wire up providers, or build any UI yourself.
Use EmbeddedCall for video and audio meetings, or EmbeddedLivestream for live streaming. Both components only require an API key, call type, call ID, and user identity to render a fully functional experience.
For full control over the UI and call behavior, see the Quickstart for manual integration.
Getting Started
Installation
Import components from /embedded and the dedicated stylesheet:
import {
EmbeddedCall,
EmbeddedLivestream,
} from "@stream-io/video-react-sdk/embedded";
import "@stream-io/video-react-sdk/dist/css/embedded.css";Use embedded.css instead of styles.css when using prebuilt components.
Call Creation
The call must exist before the prebuilt component can join it. Because the component manages the client internally, you need to create the call on your server using a server-side SDK. The callType and callId props must match the call you created on the server.
See also:
- Permissions & Moderation for assigning roles and capabilities
- Call Types for configuring permissions per call type
EmbeddedCall
For video and audio meetings. The callType should match a call type configured on your dashboard (e.g., "default").
Lifecycle
- Lobby: Camera/mic preview, device settings, display name.
- Joining: Connects and sets up media streams.
- Active Call: Full meeting UI with all controls.
- Feedback: Star rating (1-5) and optional text feedback.
Features
- Camera and microphone controls
- Screen sharing
- Reactions
- Recording controls
- Noise cancellation
- Background blur
- Participant sidebar
- Connection status notifications
- Call duration display
- Wake lock
import { EmbeddedCall } from "@stream-io/video-react-sdk/embedded";
import "@stream-io/video-react-sdk/dist/css/embedded.css";
export const MyMeeting = () => (
<EmbeddedCall
apiKey="YOUR_API_KEY"
callType="default"
callId="my-meeting"
user={{ type: "authenticated", id: "user-1", name: "John" }}
token="user-token"
/>
);EmbeddedLivestream
For livestreaming. The component automatically shows either the host or viewer UI based on the user's permissions. Users with the JOIN_BACKSTAGE capability see the host UI; everyone else sees the viewer UI. You can configure this through call type permissions on the dashboard.
Lifecycle
| Stage | Host | Viewer |
|---|---|---|
| 1. Pre-join | Lobby: camera/mic preview, device settings | Waiting lobby: countdown timer, auto-join option |
| 2. Connected | Backstage: prepare before going live | (waits for stream to start) |
| 3. Live | Broadcasting: go-live/stop controls, viewer count, elapsed time | Watching: live stream with viewer count |
| 4. End | Stops the stream | Leaves or stream ends |
| 5. Feedback | Star rating and text feedback | Star rating and text feedback |
Host Features
- Go-live / stop-live controls
- Viewer count and elapsed stream time
- Backstage mode
- Camera, microphone, and screen sharing controls
Viewer Features
- Countdown timer and auto-join on go-live
- Viewer count
import { EmbeddedLivestream } from "@stream-io/video-react-sdk/embedded";
import "@stream-io/video-react-sdk/dist/css/embedded.css";
// Host: requires an authenticated user with JOIN_BACKSTAGE capability
export const HostView = () => (
<EmbeddedLivestream
apiKey="YOUR_API_KEY"
callType="livestream"
callId="my-stream"
user={{ type: "authenticated", id: "host-1", name: "Jane" }}
token="host-token"
/>
);
// Viewer: anonymous users see the viewer UI
export const ViewerView = () => (
<EmbeddedLivestream
apiKey="YOUR_API_KEY"
callType="livestream"
callId="my-stream"
user={{ type: "anonymous" }}
/>
);Props
Both components accept the same props:
| Name | Type | Description | Default |
|---|---|---|---|
apiKey | string | Stream API key. Required. | |
callType | string | Call type (e.g., "default", "livestream"). Required. | |
callId | string | Unique call identifier. Required. | |
user | EmbeddedUser | User identity. See User Authentication. Required. | |
token | string | Static auth token. Required for authenticated users when tokenProvider is not set. | undefined |
tokenProvider | () => Promise<string> | Returns a fresh token. Recommended for production. | undefined |
logLevel | LogLevel | Logging level: "trace", "debug", "info", "warn", "error". | undefined |
layout | LayoutOption | Participant layout. See Layout Options. | "SpeakerTop" |
theme | CSSProperties | CSS variable overrides for theming. See Styling. | undefined |
onError | (error: any) => void | Error callback. | undefined |
children | ReactNode | Content rendered alongside the default UI. | undefined |
User Authentication
The user prop supports three authentication modes:
Authenticated
A registered user in your app. Requires either a token or tokenProvider.
<EmbeddedCall
apiKey="YOUR_API_KEY"
callType="default"
callId="my-meeting"
user={{ type: "authenticated", id: "user-1", name: "John" }}
token="user-token"
/>In production, use tokenProvider instead so tokens are refreshed automatically:
<EmbeddedCall
apiKey="YOUR_API_KEY"
callType="default"
callId="my-meeting"
user={{ type: "authenticated", id: "user-1", name: "John" }}
tokenProvider={async () => {
const res = await fetch("/api/stream-token");
const data = await res.json();
return data.token;
}}
/>Guest
A temporary user with server-generated credentials. No token needed.
<EmbeddedCall
apiKey="YOUR_API_KEY"
callType="default"
callId="my-meeting"
user={{ type: "guest", id: "guest-1", name: "Visitor" }}
/>Anonymous
Joins without any identity. Useful for open calls or public livestreams.
<EmbeddedCall
apiKey="YOUR_API_KEY"
callType="default"
callId="my-meeting"
user={{ type: "anonymous" }}
/>Layout Options
| Layout | Description |
|---|---|
"PaginatedGrid" | Equal-sized tiles in a grid, paginated. |
"SpeakerLeft" | Active speaker left, others right. |
"SpeakerRight" | Active speaker right, others left. |
"SpeakerTop" | Active speaker top, others below. (Default) |
"SpeakerBottom" | Active speaker bottom, others above. |
The layout automatically switches to a Speaker view when screen sharing starts.
<EmbeddedCall
apiKey="YOUR_API_KEY"
callType="default"
callId="my-meeting"
user={{ type: "authenticated", id: "user-1", name: "John" }}
token="user-token"
layout="PaginatedGrid"
/>Error Handling
<EmbeddedCall
apiKey="YOUR_API_KEY"
callType="default"
callId="my-meeting"
user={{ type: "authenticated", id: "user-1", name: "John" }}
token="user-token"
onError={(error) => {
console.error("Call error:", error);
}}
/>onError is called when the client fails to initialize, the user cannot join the call, or a media device error occurs.
Styling
The component expands to fill its parent container. To control the size, set dimensions on the wrapper element:
// Full screen
<div style={{ width: "100vw", height: "100vh" }}>
<EmbeddedCall {/* ...props */} />
</div>Via the theme prop
Pass CSS variables directly through the theme prop for per-instance theming:
<EmbeddedCall
apiKey="YOUR_API_KEY"
callType="default"
callId="my-meeting"
user={{ type: "authenticated", id: "user-1", name: "John" }}
token="user-token"
theme={{
"--str-video__primary-color": "#005fff",
"--str-video__background-color0": "#ffffff",
"--str-video__background-color1": "#f7f7f8",
"--str-video__text-color1": "#1c1e22",
"--str-video__text-color2": "#72767e",
"--str-video__button-default-base": "#eff0f1",
"--str-video__button-default-hover": "#e3e4e5",
"--str-video__icon-default": "#4c535b",
}}
/>Via CSS
Override CSS variables on .str-video in a stylesheet:
.str-video {
--str-video__primary-color: #6002ee;
--str-video__secondary-color: #90ee02;
--str-video__text-color1: #282b2b;
--str-video__border-radius-circle: 15px;
}Import SDK styles before your own for easier overrides:
import "@stream-io/video-react-sdk/dist/css/embedded.css";
import "./my-styles.css";Use CSS cascade layers for finer control:
@import url("@stream-io/video-react-sdk/dist/css/embedded.css")
layer(video-default);
.str-video__call-controls__button {
padding: 20px;
}All available variables are listed in the theme variables file. See the Theme page for full theming documentation.
Custom Children
Children are rendered alongside the default UI, not as a replacement:
<EmbeddedCall
apiKey="YOUR_API_KEY"
callType="default"
callId="my-meeting"
user={{ type: "authenticated", id: "user-1", name: "John" }}
token="user-token"
>
<MyCustomSidePanel />
</EmbeddedCall>Children have access to all SDK hooks since they render inside the StreamVideo and StreamCall providers. You can use this to respond to call state changes:
import { useEffect } from "react";
import { CallingState, useCallStateHooks } from "@stream-io/video-react-sdk";
import { EmbeddedCall } from "@stream-io/video-react-sdk/embedded";
import "@stream-io/video-react-sdk/dist/css/embedded.css";
const CallStateListener = () => {
const { useCallCallingState } = useCallStateHooks();
const callingState = useCallCallingState();
useEffect(() => {
if (callingState === CallingState.LEFT) {
console.log("User has left the call");
}
}, [callingState]);
return null;
};
export const MyApp = () => (
<EmbeddedCall
apiKey="YOUR_API_KEY"
callType="default"
callId="my-meeting"
user={{ type: "authenticated", id: "user-1", name: "John" }}
token="user-token"
>
<CallStateListener />
</EmbeddedCall>
);Audio Filters
To enable noise cancellation, install the @stream-io/audio-filters-web package:
npm install @stream-io/audio-filters-webThe prebuilt components will automatically detect the package and enable or disable noise cancellation based on your dashboard configuration. See the Noise Cancellation guide for more details.