# Add Jitsi to a small React app, one stage at a time

> Use JitsiMeeting to embed an existing Jitsi service in a React app. Our downloadable example collects the server and room first, opens the embed on request, distinguishes API readiness from conference joining and disposes the API when closing. Its production build was verified; browser interaction and real meeting media were not tested. [S1][S2]

Source: https://jitsi.help/guides/jitsi-react-sdk-example/
Updated: October 30, 2026
Publisher: Jitsi Help (https://jitsi.help/)

## The result and its limits

You will build a small React page with three fields: a meeting-server hostname, a test room and a display name. Submitting the form mounts the meeting embed. A status message distinguishes loading, API readiness and conference joining. A Close embed button disposes the API and returns to the form. This is our original example, not a copy of the handbook demo. [S1][S2]

The versions checked on 30 October 2026 are **React/React DOM 19.3.1**, **@jitsi/react-sdk 1.4.4** and **Vite 8.3.5**. The recorded production build used **Node 22.23.4**. Vite's package declares Node `^20.19.0 || >=22.12.0`; this example selects the Node 22 line. Exact dependencies and a lockfile are included. These pins identify the reviewed example, not a promise that they stay the newest versions. [S1][S4]

No actual browser join, permission prompt, microphone/camera, navigation lifecycle or two-party media test was completed. Browser control was unavailable during authoring. Build success is the verified result; the checks below describe what you should verify on your own service.

## 1. Download the complete example

[Download the React example source ZIP](/downloads/jitsi-react-sdk-example.zip), extract it, and open the `jitsi-react-sdk` folder in a terminal. The archive contains source and the lockfile, not installed dependencies or a compiled application. [S1]

```text
jitsi-react-sdk/
  package.json
  package-lock.json
  index.html
  README.md
  src/
    main.jsx
    App.jsx
    style.css
```

| File | What to understand first |
| --- | --- |
| `package.json` and lockfile | Exact dependencies and development/build commands. |
| `index.html` | The root element and entry script. |
| `src/main.jsx` | Mounts the React application. |
| `src/App.jsx` | Form, embed lifecycle, status messages and cleanup. |
| `src/style.css` | Small standalone styles; no dependency on jitsi.help's site theme. |

**Check:** start in the folder that contains `package.json`. Read the README and verify that your selected service permits your intended embedding and testing. The example starts on a local form; it does not silently join a public room.

## 2. Install and run the browser application

From the extracted example folder:

```bash
npm ci
npm run dev
```

**Why:** `npm ci` uses the supplied lockfile. Vite supplies the development page. [S1][S4]

**Check:** open the localhost address printed by Vite and expect the input form. No meeting is created by compiling the project. If installation fails, check your Node version, package registry access and whether you are in the correct folder before changing Jitsi configuration.

The development command binds to `127.0.0.1`. It is a local learning app, not a deployment instruction for a public server. Production hosting and its HTTPS requirements are a separate task. [S1][S4]

## 3. Enter a service, a room and a display name

Use the hostname of a service you are authorized to access, such as your own `meet.example.com`. The form expects the hostname only, without `https://` or a path. The placeholder is an example domain, not a working test server. Choose a new room you are authorized to use and a suitable display name. [S1]

**Why:** the SDK's `domain` selects the service that supplies the External API. A room name identifies the meeting within that service. `userInfo.displayName` supplies display information; it is not proof of authentication. `JitsiMeeting` and `JaaSMeeting` are different SDK entry points; this example uses the former with an explicitly chosen domain. [S2]

**Check:** select **Open meeting embed** and follow the chosen service's join, login or admission flow. Private services can require their own integration setup. For meet.jit.si, check its current service policies; embedding does not remove them. Use the [login guide](/guides/jitsi-login-moderator-password/) for access questions.

## 4. Understand the readiness boundaries

This excerpt is from the complete `App.jsx`; surrounding form and cleanup code are in the download. [S1][S2][S3]

```jsx
<JitsiMeeting
  domain={meeting.domain}
  roomName={meeting.roomName}
  userInfo={{ displayName: meeting.displayName }}
  configOverwrite={{ startWithAudioMuted: true, startWithVideoMuted: true }}
  onApiReady={(api) => {
    apiRef.current = api;
    setStatus('Meeting API ready. Complete the service join flow.');
    api.addListener('videoConferenceJoined', () => {
      setStatus('Conference joined. Verify audio and video with a consenting attendee.');
    });
  }}
  onReadyToClose={closeMeeting}
  getIFrameRef={(container) => { container.style.height = 'min(70vh, 720px)'; }}
/>
```

Read the statuses in order:

1. **Loading:** the application has requested the embed.
2. **API ready:** the wrapper has initialized its External API reference.
3. **Conference joined:** the embedded meeting has emitted that event.
4. **Media received:** another attendee confirms actual reception. The example does not measure this fourth result automatically. [S1][S2][S3]

`startWithAudioMuted` and `startWithVideoMuted` are starting preferences, not guarantees about permission prompts, remote delivery or authorization. Check the client's actual state before a test. For more commands and event handling, use the existing [IFrame API guide](/guides/embed-jitsi-iframe-api/).

## 5. Close the embed deliberately

The inspected SDK 1.4.4 component creates the External API but does not include a disposal effect for component unmount. Our example owns that cleanup. It clears its stored reference, calls `dispose()` on the existing API and removes the meeting component. An application-unmount cleanup also disposes a stored API. These are source-reviewed implementation choices; their browser behavior still needs testing. [S1][S2]

**Check:** close after API readiness, then open another test room. Also check your real application's navigation/unmount path. Confirm that the previous iframe and meeting participation end, and that another embed can open. Closing a frame is not a recording-retention policy or an account deletion operation.

## 6. Build and verify the result

```bash
npm run build
npm run preview
```

The production build was completed during review. Preview serves its output locally for your checks. Verify the form, loading status, API-ready boundary, join event, close action and a fresh second embed. Then use consenting attendees to check audio/video in both directions, including your service's authentication and actual network conditions. [S1][S4]

## Diagnose by stage

| Observation | First useful check |
| --- | --- |
| The form never appears | Folder, dependency installation, Vite output and local console. |
| Form appears, but API readiness never arrives | The chosen domain, its `external_api.js`, script/network errors, embedding policy and actual service availability. [S2] |
| API is ready but the meeting is not joined | Service login, room/access rules and join UI; readiness does not bypass admission. |
| Conference joins but no one receives media | Mute/device state, permission and the service's media path, not simply the SDK import. |
| Old room remains after navigation | Verify explicit disposal and unmount in your application; compare the pinned example before altering the SDK. [S1][S2] |

This page does not prescribe an untested `window is not defined` fix. It is a Vite client app, not a Next.js server-rendering example. If you use another framework, reproduce its execution boundary and consult that framework's current documentation before adding a workaround.

The example contains no JWT signer. If your service needs issued tokens, add that flow through an authorized backend and follow the [JWT guide](/guides/jitsi-jwt-authentication/). Never put a signing secret or provider credentials in a browser bundle.

## Sources and maintenance

- **[S1]** Our downloadable example above, exact lockfile and build receipt reviewed 30 October 2026. No live meeting or browser lifecycle was tested.
- **[S2]** Official [SDK documentation](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-react-sdk/), [SDK 1.4.4 package metadata](https://registry.npmjs.org/@jitsi/react-sdk/1.4.4) and pinned [JitsiMeeting implementation](https://github.com/jitsi/jitsi-meet-react-sdk/blob/f027efae03f3574392dfbc387db6b2e6c1bfd96b/src/components/JitsiMeeting.tsx): props, loading and lifecycle behavior.
- **[S3]** Official [IFrame events](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-iframe-events/): listener API and conference event boundaries.
- **[S4]** [Vite guide](https://vite.dev/guide/) and [Vite 8.3.5 package metadata](https://registry.npmjs.org/vite/8.3.5): development/build commands and engine requirements.

Recheck the lockfile, SDK loading/disposal behavior and your service's API after upgrades. Open questions are your actual authentication setup, browser behavior, readiness failures and successful two-party media on the intended networks.

## Frequently asked questions

### Does this example create a Jitsi server?

No. The React app embeds a meeting service you choose. That service still controls availability, authentication, admission and feature configuration. Hosting the frontend does not provision a meeting backend.

### Does onApiReady mean I have joined the conference?

No. The example treats the API-ready callback and videoConferenceJoined event as different boundaries. Neither proves that a second attendee receives your microphone or camera. Verify media separately in an authorized test meeting.

### Can I paste this Vite example into Next.js unchanged?

This recipe is for a browser application built with Vite. A server-rendered framework has different execution and lifecycle boundaries. No Next.js or SSR recipe was tested here; establish that framework's browser-side boundary before integrating the meeting SDK.

### Where should I put my JWT signing secret?

Keep signing secrets on an authorized backend. This example contains no signer or token-generation endpoint. A browser may receive an appropriate issued token for a configured service, but it must not contain the secret that signs tokens.


---

Jitsi Help is an independent service. It is not affiliated with, endorsed by or sponsored by 8x8, Inc. or the Jitsi project. Jitsi and Jitsi Meet are trademarks of 8x8, Inc., used here only to describe the software we host and support.
