# Quickstart

>
> **Info:** **v2 is in beta.** It publishes to the `beta` npm tag, so the install commands below
> pin `@beta`. The v1 docs, which cover the `latest` tag, are one version back in the
> version picker.
>

This quickstart covers manual integration with full control over the client, call state, and UI. For a simpler setup, see [Prebuilt Components](https://getstream.io/video/docs/react/v2/basics/prebuilt/).

## Best Practices

- Create `StreamVideoClient` once at app root; clean up with `disconnectUser()` on unmount.
- Use `tokenProvider` with short-lived tokens instead of static tokens.
- Create and join calls in `useEffect`; clean up with `call.leave()`.
- Handle all `callingState` values in your UI (RINGING, JOINING, JOINED, etc.).
- Handle errors from `call.join()`, device toggles, and `connectUser()`.
- Browser permissions: users get **one chance** to grant camera/mic access - handle denials gracefully.
- Add a user interaction (button click) before joining to satisfy browser autoplay policies.

See [Integration Best Practices](https://getstream.io/video/docs/react/v2/advanced/integration-best-practices/) for the complete checklist.

## Installation

```bash
npm install @stream-io/video-react-sdk@beta
# or
yarn add @stream-io/video-react-sdk@beta
```

### SDK Size

The SDK is optimized for tree-shaking. After minification it's ~600KB, or ~165KB gzipped. Check [Bundlephobia](https://bundlephobia.com/result?p=@stream-io/video-react-sdk) for current stats.

## Client Setup & Calls

Create a `StreamVideoClient` at the app root, then create and join calls as needed:

```tsx
import { useEffect, useState } from "react";
import {
  Call,
  StreamCall,
  StreamVideo,
  StreamVideoClient,
  User,
} from "@stream-io/video-react-sdk";

const apiKey = "your-api-key";
const userId = "user-id";
const token = "authentication-token";
const user: User = { id: userId };

export const MyApp = () => {
  const [client, setClient] = useState<StreamVideoClient>();

  useEffect(() => {
    const myClient = new StreamVideoClient({ apiKey, user, token });
    setClient(myClient);

    return () => {
      myClient.disconnectUser().catch(console.error);
      setClient(undefined);
    };
  }, []);

  if (!client) return null;

  return (
    <StreamVideo client={client}>
      <MyCallUI client={client} />
    </StreamVideo>
  );
};

const MyCallUI = ({ client }: { client: StreamVideoClient }) => {
  const [call, setCall] = useState<Call>();

  useEffect(() => {
    const myCall = client.call("default", "my-first-call");
    myCall.join({ create: true }).catch(console.error);
    setCall(myCall);

    return () => {
      myCall.leave().catch(console.error);
      setCall(undefined);
    };
  }, [client]);

  if (!call) return null;

  return <StreamCall call={call}>{/* <MyVideoUI /> */}</StreamCall>;
};
```

`default` is a call type. There are 4 built-in [call types](https://getstream.io/video/docs/react/v2/guides/configuring-call-types/) and you can also create your own. The call type controls the permissions and which features are enabled.

Device preferences are persisted by default on web. Configure or disable this via `options.devicePersistence` when creating the client. See the [Camera & Microphone guide](https://getstream.io/video/docs/react/v2/guides/camera-and-microphone/).

The second argument is the call id. Call IDs can be reused, so you can join the same id multiple times (for example, for recurring meetings).
To load an existing call without joining:

```ts
const call = client.call("default", "my-first-call");
await call.getOrCreate();
```

## Rendering Video

Access call state with hooks from `useCallStateHooks`:

```tsx
import { useCallStateHooks, ParticipantView } from "@stream-io/video-react-sdk";

export const MyVideoUI = () => {
  const { useParticipants } = useCallStateHooks();
  const participants = useParticipants();
  return (
    <>
      {participants.map((p) => (
        <ParticipantView participant={p} key={p.sessionId} />
      ))}
    </>
  );
};
```

The participant object contains audio/video tracks, user info, and enabled states. `sessionId` uniquely identifies each participant.

More: [Call & Participant State](https://getstream.io/video/docs/react/v2/guides/call-and-participant-state/)

## Camera & Microphone

```tsx
import { useCallStateHooks } from "@stream-io/video-react-sdk";

export const MyVideoButton = () => {
  const { useCameraState } = useCallStateHooks();
  const { camera, isMute } = useCameraState();
  return (
    <button onClick={() => camera.toggle()}>
      {isMute ? "Turn on camera" : "Turn off camera"}
    </button>
  );
};

export const MyMicrophoneButton = () => {
  const { useMicrophoneState } = useCallStateHooks();
  const { microphone, isMute } = useMicrophoneState();
  return (
    <button onClick={() => microphone.toggle()}>
      {isMute ? "Turn on microphone" : "Turn off microphone"}
    </button>
  );
};
```

More: [Camera & Microphone](https://getstream.io/video/docs/react/v2/guides/camera-and-microphone/)

## UI Components

You can:

- Build custom UI using state hooks
- Use built-in SDK components
- Mix both approaches

Built-in components support [theming](https://getstream.io/video/docs/react/v2/ui-components/video-theme/) and props customization. See the UI Cookbook for custom component examples.

### Using Built-in Components

```tsx
import {
  CallControls,
  SpeakerLayout,
  StreamCall,
  StreamTheme,
  StreamVideo,
} from "@stream-io/video-react-sdk";

import "@stream-io/video-react-sdk/dist/css/styles.css";

export const MyApp = () => (
  <StreamVideo client={client}>
    <StreamCall call={call}>
      <StreamTheme>
        <SpeakerLayout participantsBarPosition="right" />
        <CallControls />
      </StreamTheme>
    </StreamCall>
  </StreamVideo>
);
```

## See It in Action

Try the [CodeSandbox example](https://codesandbox.io/p/devbox/practical-solomon-cjd4ww) to explore the SDK.

---

For the most recent version of this documentation, visit [https://getstream.io/video/docs/react/v2/basics/quickstart/](https://getstream.io/video/docs/react/v2/basics/quickstart/).