nuxt-livekit
v0.0.2
Published
LiveKit integration for Nuxt: realtime video, audio, and data with client composables and server utilities
Downloads
112
Maintainers
Readme
nuxt-livekit
LiveKit integration for Nuxt. Add realtime video, audio, and data features to your Nuxt application with auto-imported client composables and Nitro server utilities.
Features
- 🔌 Auto-imported composables —
useLiveKitRoom()anduseLiveKitToken()available in any component - 🖥️ Server utilities —
generateLiveKitToken(),useLiveKitRoomService(),useLiveKitWebhookReceiver()auto-imported in Nitro routes - ⚡ Reactive state — connection state, participants, active speakers, reconnection status, and event log
- 🔐 Secure by default — API key/secret stay server-side via runtime config
- 📦 Zero config — just add your LiveKit credentials and go
- 🛡️ SSR-safe — composables are guarded to only run on the client
Compatibility
| nuxt-livekit | Nuxt | livekit-client | livekit-server-sdk |
| --- | --- | --- | --- |
| >=0.0.1 | >=3.0.0 | ^2.x | ^2.x |
Quick Setup
Install the module:
npx nuxi module add nuxt-livekitThat's it! The module is now installed and you can start using it.
Configuration
Add your LiveKit credentials to nuxt.config.ts:
export default defineNuxtConfig({
modules: ['nuxt-livekit'],
livekit: {
wsUrl: 'wss://your-project.livekit.cloud',
},
})| Option | Description | Required |
| --- | --- | --- |
| wsUrl | LiveKit server WebSocket URL | Yes |
| apiKey | LiveKit API key (server-only) | Yes |
| apiSecret | LiveKit API secret (server-only) | Yes |
[!IMPORTANT]
apiKeyandapiSecretare never exposed to the client. OnlywsUrlis available in the browser viauseRuntimeConfig().public.livekit.wsUrl.
Environment Variables
Instead of hardcoding values in nuxt.config.ts, you can use environment variables with the standard Nuxt runtime config override convention:
| Variable | Maps to |
| --- | --- |
| NUXT_LIVEKIT_WS_URL | runtimeConfig.livekit.wsUrl |
| NUXT_LIVEKIT_API_KEY | runtimeConfig.livekit.apiKey |
| NUXT_LIVEKIT_API_SECRET | runtimeConfig.livekit.apiSecret |
| NUXT_PUBLIC_LIVEKIT_WS_URL | runtimeConfig.public.livekit.wsUrl |
Create a .env file in your project root:
NUXT_LIVEKIT_WS_URL=wss://your-project.livekit.cloud
NUXT_LIVEKIT_API_KEY=your-api-key
NUXT_LIVEKIT_API_SECRET=your-api-secretUsage
Client-side
useLiveKitRoom(options?)
Manages a LiveKit Room instance with reactive state. The room is automatically disconnected and cleaned up when the component is unmounted.
<script setup>
const {
room, // ShallowRef<Room>
connectionState, // Ref<ConnectionState>
remoteParticipants, // ShallowRef<RemoteParticipant[]>
localParticipant, // ShallowRef<LocalParticipant>
activeSpeakers, // ShallowRef<Participant[]>
isReconnecting, // Ref<boolean>
error, // Ref<string | null>
events, // Ref<LiveKitRoomEvent[]>
connect, // (token: string, url?: string) => Promise<void>
disconnect, // () => Promise<void>
clearEvents, // () => void
} = useLiveKitRoom({ adaptiveStream: true, dynacast: true })
await connect(token)
</script>Options: Accepts all RoomOptions from livekit-client (e.g. adaptiveStream, dynacast, videoCaptureDefaults).
useLiveKitToken(endpoint?)
Fetches a token from your server API route:
<script setup>
const { token, wsUrl, error, pending, fetchToken } = useLiveKitToken('/api/livekit/token')
const response = await fetchToken({ roomName: 'my-room', participantName: 'user-1' })
</script>Server-side (Nitro)
All server utilities are auto-imported in your server/ routes.
generateLiveKitToken(identity, roomName, options?)
Generate a JWT token in one line:
// server/api/livekit/token.post.ts
export default defineEventHandler(async (event) => {
const { roomName, participantName } = await readBody(event)
const token = await generateLiveKitToken(participantName, roomName, {
name: participantName,
grants: { canPublish: true, canSubscribe: true },
})
return { token }
})useLiveKitAccessToken(identity, options?)
Lower-level — returns an AccessToken instance for full control:
const at = useLiveKitAccessToken('user-1', { ttl: '2h' })
at.addGrant({ roomJoin: true, room: 'my-room', canPublish: false })
const token = await at.toJwt()useLiveKitRoomService(host?)
Returns a RoomServiceClient for managing rooms:
const svc = useLiveKitRoomService()
const rooms = await svc.listRooms()
await svc.deleteRoom('old-room')useLiveKitWebhookReceiver()
Returns a WebhookReceiver for verifying incoming LiveKit webhooks:
// server/api/livekit/webhook.post.ts
export default defineEventHandler(async (event) => {
const receiver = useLiveKitWebhookReceiver()
const body = await readRawBody(event)
const authHeader = getHeader(event, 'authorization')
const webhookEvent = await receiver.receive(body!, authHeader!)
// Handle webhookEvent...
return { ok: true }
})Full Example
A complete flow from joining a room to rendering participants:
<script setup>
const roomName = ref('my-room')
const userName = ref('')
const { token, fetchToken } = useLiveKitToken()
const {
connectionState,
remoteParticipants,
localParticipant,
connect,
disconnect,
} = useLiveKitRoom({ adaptiveStream: true, dynacast: true })
async function joinRoom() {
const { token: t, wsUrl } = await fetchToken({
roomName: roomName.value,
participantName: userName.value,
})
await connect(t, wsUrl)
}
</script>
<template>
<div>
<div v-if="connectionState !== 'connected'">
<input v-model="userName" placeholder="Your name" />
<button @click="joinRoom">Join</button>
</div>
<div v-else>
<p>Connected as {{ localParticipant?.identity }}</p>
<p>{{ remoteParticipants.length }} other participant(s)</p>
<button @click="disconnect">Leave</button>
</div>
</div>
</template>Contributing
# Install dependencies
pnpm install
# Generate type stubs
pnpm dev:prepare
# Develop with the playground
pnpm dev
# Build the playground
pnpm dev:build
# Run ESLint
pnpm lint
pnpm lint:fix
# Run Vitest
pnpm test
pnpm test:watch
# Type check
pnpm test:types
# Release new version
pnpm release