Using a newer version? See the updated quickstart for Next.js 13+.
1. Install LiveKit SDK
Install the necessary LiveKit SDKs for the web frontend and for the server APIs:
yarn add livekit-server-sdk @livekit/components-react @livekit/components-styles
2. Keys and Configuration
To start, your app needs an LiveKit API key and secret, as well as your LiveKit project URL.
Create a new file at .env.development.local
with the following content. Do not commit this file!
LIVEKIT_API_KEY=<your API Key>LIVEKIT_API_SECRET=<your API Secret>NEXT_PUBLIC_LIVEKIT_URL=<your LiveKit server URL>
3. Create token endpoint
Create a new file at /api/get_lk_token.ts
with the following content:
import { NextApiRequest, NextApiResponse } from 'next';import { AccessToken } from 'livekit-server-sdk';export default async function handler(req: NextApiRequest, res: NextApiResponse) {const room = req.query.room as string;const username = req.query.username as string;if (req.method !== 'GET') {return res.status(400).json({ error: 'Invalid method' });} else if (!room) {return res.status(400).json({ error: 'Missing "room" query parameter' });} else if (!username) {return res.status(400).json({ error: 'Missing "username" query parameter' });}const apiKey = process.env.LIVEKIT_API_KEY;const apiSecret = process.env.LIVEKIT_API_SECRET;const wsUrl = process.env.NEXT_PUBLIC_LIVEKIT_URL;if (!apiKey || !apiSecret || !wsUrl) {return res.status(500).json({ error: 'Server misconfigured' });}const at = new AccessToken(apiKey, apiSecret, { identity: username });at.addGrant({ room, roomJoin: true, canPublish: true, canSubscribe: true });res.status(200).json({ token: await at.toJwt() });}
4. Make a page in your web app
Make a new file at /pages/room.tsx
with the following content:
import {ControlBar,GridLayout,LiveKitRoom,ParticipantTile,RoomAudioRenderer,useTracks,} from '@livekit/components-react';import '@livekit/components-styles';import { useEffect, useState } from 'react';import { Track } from 'livekit-client';export default () => {// TODO: get user input for room and nameconst room = 'quickstart-room';const name = 'quickstart-user';const [token, setToken] = useState('');useEffect(() => {(async () => {const resp = await fetch(`/api/get_lk_token?room=${room}&username=${name}`);const data = await resp.json();setToken(data.token);})();}, []);if (token === '') {return <div>Getting token...</div>;}return (<LiveKitRoomvideo={true}audio={true}token={token}serverUrl={process.env.NEXT_PUBLIC_LIVEKIT_URL}// Use the default LiveKit theme for nice styles.data-lk-theme="default"style={{ height: '100dvh' }}>{/* Your custom component with basic video conferencing functionality. */}<MyVideoConference />{/* The RoomAudioRenderer takes care of room-wide audio for you. */}<RoomAudioRenderer />{/* Controls for the user to start/stop audio, video, and screenshare tracks and to leave the room. */}<ControlBar /></LiveKitRoom>);};function MyVideoConference() {// `useTracks` returns all camera and screen share tracks. If a user// joins without a published camera track, a placeholder track is returned.const tracks = useTracks([{ source: Track.Source.Camera, withPlaceholder: true },{ source: Track.Source.ScreenShare, withPlaceholder: false },],{ onlySubscribed: false },);return (<GridLayout tracks={tracks} style={{ height: 'calc(100vh - var(--lk-control-bar-height))' }}>{/* The GridLayout accepts zero or one child. The child is usedas a template to render all passed in tracks. */}<ParticipantTile /></GridLayout>);}
5. Load the page and connect
Start your server with:
yarn dev
And then open localhost:8000/room
in your browser.
6. Next Steps
If you're looking to dive deeper into building your LiveKit app with React, check out the React Components reference section. There you'll find a comprehensive list of available components and React hooks, along with examples of how to use them. This is a great resource for building more complex and advanced apps. Happy coding!