Use this SDK to add realtime video, audio and data features to your JavaScript/TypeScript app. By connecting to LiveKit Cloud or a self-hosted server, you can quickly build applications such as multi-modal AI, live streaming, or video calls with just a few lines of code.
[!NOTE]
This is v2 of livekit-client. When migrating from v1.x to v2.x you might encounter a small set of breaking changes.
Read the migration guide for a detailed overview of what has changed.
Installation
Yarn
yarn add livekit-client
NPM
npm install livekit-client --save
Minified JS
To use the SDK without a package manager, you can include it with a script tag:
The module will be exported under LivekitClient in the global namespace. When
accessing symbols from the class, you'd need to prefix them with LivekitClient..
For example, Room becomes LivekitClient.Room.
Usage
Examples below are in TypeScript, if using JS/CommonJS imports replace import with:
const livekit = require('livekit-client');
const room = new livekit.Room(...);
// call this some time before actually connecting to speed up the actual connection
room.prepareConnection(url, token);
await room.connect(...);
Connecting to a room, publish video & audio
import {
Participant,
RemoteParticipant,
RemoteTrack,
RemoteTrackPublication,
Room,
RoomEvent,
VideoPresets,
Track,
LocalTrackPublication,
LocalParticipant
} from'livekit-client';
// creates a new room with optionsconst room = newRoom({
// automatically manage subscribed video qualityadaptiveStream: true,
// optimize publishing bandwidth and CPU for published tracksdynacast: true,
// default capture settingsvideoCaptureDefaults: {
resolution: VideoPresets.h720.resolution,
},
});
// pre-warm connection, this can be called as early as your page is loaded
room.prepareConnection(url, token);
// set up event listeners
room
.on(RoomEvent.TrackSubscribed, handleTrackSubscribed)
.on(RoomEvent.TrackUnsubscribed, handleTrackUnsubscribed)
.on(RoomEvent.ActiveSpeakersChanged, handleActiveSpeakerChange)
.on(RoomEvent.Disconnected, handleDisconnect)
.on(RoomEvent.LocalTrackUnpublished, handleLocalTrackUnpublished);
// connect to roomawait room.connect('ws://localhost:7800', token);
console.log('connected to room', room.name);
// publish local camera and mic tracksawait room.localParticipant.enableCameraAndMicrophone();
functionhandleTrackSubscribed(
track: RemoteTrack,
publication: RemoteTrackPublication,
participant: RemoteParticipant,
) {
if (track.kind === Track.Kind.Video || track.kind === Track.Kind.Audio) {
// attach it to a new HTMLVideoElement or HTMLAudioElementconst element = track.attach();
parentElement.appendChild(element);
}
}
functionhandleTrackUnsubscribed(
track: RemoteTrack,
publication: RemoteTrackPublication,
participant: RemoteParticipant,
) {
// remove tracks from all attached elements
track.detach();
}
functionhandleLocalTrackUnpublished(
publication: LocalTrackPublication,
participant: LocalParticipant,
) {
// when local tracks are ended, update UI to remove them from rendering
publication.track.detach();
}
functionhandleActiveSpeakerChange(speakers: Participant[]) {
// show UI indicators when participant is speaking
}
functionhandleDisconnect() {
console.log('disconnected from room');
}
In order to connect to a room, you need to first create an access token.
While LiveKit is designed to be flexible, we've added a few shortcuts that makes working with common track types simple. For a user's camera, microphone, and screen share, you can enable them with the following LocalParticipant methods:
const p = room.localParticipant;
// turn on the local user's camera and mic, this may trigger a browser prompt// to ensure permissions are grantedawait p.setCameraEnabled(true);
await p.setMicrophoneEnabled(true);
// start sharing the user's screen, this will trigger a browser prompt to select// the screen to share.await p.setScreenShareEnabled(true);
// disable camera to mute them, when muted, the user's camera indicator will be turned offawait p.setCameraEnabled(false);
Similarly, you can access these common track types on the other participants' end.
// get a RemoteParticipant by their identityconst p = room.remoteParticipants.get('participant-identity');
if (p) {
// if the other user has enabled their camera, attach it to a new HTMLVideoElementif (p.isCameraEnabled) {
const publication = p.getTrackPublication(Track.Source.Camera);
if (publication?.isSubscribed) {
const videoElement = publication.videoTrack?.attach();
// do something with the element
}
}
}
Creating a track prior to creating a room
In some cases, it may be useful to create a track before creating a room. For
example, when building a staging area so the user may check their own camera.
You can use our global track creation functions for this:
LiveKit lets you publish any track as long as it can be represented by a MediaStreamTrack. You can specify a name on the track in order to identify it later.
const pub = await room.localParticipant.publishTrack(mediaStreamTrack, {
name: 'mytrack',
simulcast: true,
// if this should be treated like a camera feed, tag it as such// supported known sources are .Camera, .Microphone, .ScreenSharesource: Track.Source.Camera,
});
// you may mute or unpublish the track later
pub.setMuted(true);
room.localParticipant.unpublishTrack(mediaStreamTrack);
Device management APIs
Users may have multiple input and output devices available. LiveKit will automatically use the one that's deemed as the default device on the system. You may also list and specify an alternative device to use.
// list all microphone devicesconst devices = awaitRoom.getLocalDevices('audioinput');
// select last deviceconst device = devices[devices.length - 1];
// in the current room, switch to the selected device and set// it as default audioinput in the future.await room.switchActiveDevice('audioinput', device.deviceId);
You can also switch devices given a constraint. This could be useful on mobile devices to switch to a back-facing camera:
When creating tracks using LiveKit APIs (connect, createLocalTracks, setCameraEnabled, etc), it's possible to encounter errors with the underlying media device. In those cases, LiveKit will emit RoomEvent.MediaDevicesError.
You can use the helper MediaDeviceFailure.getFailure(error) to determine specific reason for the error.
PermissionDenied - the user disallowed capturing devices
NotFound - the particular device isn't available
DeviceInUse - device is in use by another process (happens on Windows)
These distinctions enables you to provide more specific messaging to the user.
You could also retrieve the last error with LocalParticipant.lastCameraError and LocalParticipant.lastMicrophoneError.
Audio playback
Browsers can be restrictive with regards to audio playback that is not initiated by user interaction. What each browser considers as user interaction can vary by vendor (for example, Safari on iOS is very restrictive).
LiveKit will attempt to autoplay all audio tracks when you attach them to audio elements. However, if that fails, we'll notify you via RoomEvent.AudioPlaybackStatusChanged. Room.canPlaybackAudio will indicate if audio playback is permitted. LiveKit takes an optimistic approach so it's possible for this value to change from true to false when we encounter a browser error.
In the case user interaction is required, LiveKit provides Room.startAudio to start audio playback. This function must be triggered in an onclick or ontap event handler. In the same session, once audio playback is successful, additional audio tracks can be played without further user interactions.
room.on(RoomEvent.AudioPlaybackStatusChanged, () => {
if (!room.canPlaybackAudio) {
// UI is necessary.
...
button.onclick = () => {
// startAudio *must* be called in an click/tap handler.
room.startAudio().then(() => {
// successful, UI can be removed now
button.remove();
});
}
}
});
Configuring logging
This library uses loglevel for its internal logs. You can change the effective log level with the logLevel field in ConnectOptions.
The method setLogExtension allows to hook into the livekit internal logs and send them to some third party logging service
Perform your own predefined method calls from one participant to another.
This feature is especially powerful when used with Agents, for instance to forward LLM function calls to your client application.
Registering an RPC method
The participant who implements the method and will receive its calls must first register support:
room.localParticipant?.registerRpcMethod(
// method name - can be any string that makes sense for your application'greet',
// method handler - will be called when the method is invoked by a RemoteParticipantasync (data: RpcInvocationData) => {
console.log(`Received greeting from ${data.callerIdentity}: ${data.payload}`);
return`Hello, ${data.callerIdentity}!`;
}
);
In addition to the payload, your handler will also receive responseTimeout, which informs you the maximum time available to return a response. If you are unable to respond in time, the call will result in an error on the caller's side.
You may find it useful to adjust the responseTimeout parameter, which indicates the amount of time you will wait for a response. We recommend keeping this value as low as possible while still satisfying the constraints of your application.
Errors
LiveKit is a dynamic realtime environment and calls can fail for various reasons.
You may throw errors of the type RpcError with a string message in an RPC method handler and they will be received on the caller's side with the message intact. Other errors will not be transmitted and will instead arrive to the caller as 1500 ("Application Error"). Other built-in errors are detailed in RpcError.
Examples
Demo App
examples/demo contains a demo webapp that uses the SDK. Run it with pnpm install && pnpm examples:demo
RPC Demo
examples/rpc contains a demo webapp that uses the SDK to showcase the RPC capabilities. Run it with pnpm install && pnpm dev from the examples/rpc directory.
Browser Support
Browser
Desktop OS
Mobile OS
Chrome
Windows, macOS, Linux
Android
Firefox
Windows, macOS, Linux
Android
Safari
macOS
iOS
Edge (Chromium)
Windows, macOS
We aim to support a broad range of browser versions by transpiling the library code with babel.
You can have a look at the "browerslist" section of package.json for more details.
Note that the library requires some specific browser APIs to be present.
You can check general compatibility with the helper function isBrowserSupported().
Support for more modern features like adaptiveStream and dynacast can be checked for with supportsAdaptiveStream() and supportsDynacast().
If you are targeting legacy browsers, but still want adaptiveStream functionality you'll likely need to use polyfills for ResizeObserver and IntersectionObserver.
Also when targeting legacy browsers, older than the ones specified in our browserslist target, make sure to transpile the library code to your desired target and include required polyfills with babel and/or corejs.
The npm package livekit-client receives a total of 33,956 weekly downloads. As such, livekit-client popularity was classified as popular.
We found that livekit-client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.It has 29 open source maintainers collaborating on the project.
Package last updated on 31 Oct 2024
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.