Overview
Building an agent frontend requires coordinating several moving parts: fetching authentication tokens, connecting to a room, dispatching an agent, and then interacting with it through media, data, and state APIs. The Session API handles this orchestration for you, giving you a single entry point that manages the full lifecycle of a 1:1 agent interaction.
Without Session, you need to generate tokens manually, call Room.connect, set up agent dispatch configuration, and manage cleanup yourself. Session wraps all of this into a simple start/end interface while still giving you access to lower-level APIs when needed.
Session is available on Web, Swift, Kotlin, Flutter, and React Native.
If you're using a platform that doesn't yet support Session APIs, you can use manual token generation and connect directly with Room.connect. See Token creation for details.
Session lifecycle
A session has four stages:
- Create: Initialize a session with a
TokenSourceand options including the agent name.TokenSourcehandles token fetching, caching, and refreshing — see the Authentication guide for setup. - Start: Call
session.start()to fetch a token, connect to a room, and dispatch the agent. - Interact: The agent joins the room and begins the conversation. Your frontend can access agent state, media tracks, transcriptions, and data through the session.
- End: Call
session.end()to disconnect from the room and clean up resources.
What you get inside a session
Once a session is started and the agent has joined, your frontend has access to the full set of realtime APIs for interacting with the agent.
Agent state
The agent moves through a lifecycle of states — connecting, listening, thinking, speaking — that your frontend can observe. Use these states to drive UI updates, like showing a visual indicator when the agent is thinking or disabling the microphone when the agent is speaking. State getters like canListen and isFinished simplify common UI decisions. See Agent state for details.
Media tracks
Your frontend and agent exchange audio and video over media tracks. A simple voice agent subscribes to the user's microphone and publishes its own audio. Agents with vision capabilities can subscribe to the user's camera or screen share. See Realtime media and data for details.
Session messages
The session exposes a unified list of messages you can use to build chat panels and message lists. Your SDK provides a Session Messages API that gives you the list and a way to send new chat messages.
The following examples show how to render the message list and send user messages on each platform.
'use client';import { useState } from 'react';import { useAgent, useSessionMessages } from '@livekit/components-react';import { AgentChatTranscript } from '@/components/agents-ui/agent-chat-transcript';function ChatInterface({ session }) {const { state } = useAgent(session);const { messages, send, isSending } = useSessionMessages(session);const [chatMessage, setChatMessage] = useState('');return (<><AgentChatTranscript agentState={state} messages={messages} /><div><inputtype="text"value={chatMessage}onChange={(e) => setChatMessage(e.target.value)}/><buttondisabled={isSending}onClick={() => {send(chatMessage);setChatMessage('');}}>{isSending ? 'Sending' : 'Send'}</button></div></>);}
// In a SwiftUI view with access to your session:ForEach(session.messages) { message inswitch message.content {case let .agentTranscript(text),let .userTranscript(text),let .userInput(text):Text(text)}}TextField("Message", text: $inputText)Button("Send") {Task {await session.send(text: inputText)inputText = ""}}
val sessionMessages = rememberSessionMessages()LazyColumn {items(items = sessionMessages.messages) { message ->Text(message.message)}}val messageState = rememberTextFieldState()TextField(state = messageState)Button(onClick = {coroutineScope.launch {sessionMessages.send(messageState.text.toString())messageState.clearText()}}) {Text("Send")}
// session.messages is the list; session.sendText() sends user messagesListView.builder(itemCount: session.messages.length,itemBuilder: (context, index) {final message = session.messages[index];return Text(message.content.text);},)TextField(controller: _controller,onSubmitted: (text) async {await session.sendText(text);_controller.clear();},)
Chat messages
Messages that the user or agent types (rather than speaks) appear in the session messages list. Use the Session Messages API's send() method to post new messages from the user. The agent can add messages on its side via the same channel.
Transcriptions
Transcriptions of agent and user speech are included in the session messages list. They also exist as raw text streams for captions or custom UIs. See Text streams for details.
Data and state synchronization
Beyond media and transcriptions, your frontend and agent can exchange arbitrary data. Use byte streams for files and images, RPC for request-response interactions, and state synchronization for shared key-value data that stays in sync across participants. See Realtime media and data for an overview.
Session lifecycle examples
The following examples show how to create a session, start it (connect and dispatch the agent), and end it on each platform.
'use client';import { useEffect } from 'react';import { useSession, SessionProvider } from '@livekit/components-react';import { TokenSource } from 'livekit-client';const tokenSource = TokenSource.sandboxTokenServer('<your sandbox token server id>');export function App() {const session = useSession(tokenSource, { agentName: 'my-agent' });useEffect(() => {session.start();return () => {session.end();};}, []);return (<SessionProvider session={session}>{/* Your app components */}</SessionProvider>);}
import LiveKitComponentslet tokenSource = SandboxTokenSource(id: "<your sandbox token server id>")let session = Session.withAgent("my-agent", tokenSource: tokenSource)// Start the sessionawait session.start()// End the sessionawait session.end()
val tokenSource = remember {TokenSource.fromSandbox("<your sandbox token server id>")}val session = rememberSession(tokenSource = tokenSource)LaunchedEffect(Unit) {session.start()}// End the session when donesession.end()
import 'package:livekit_client/livekit_client.dart' as sdk;final tokenSource = sdk.SandboxTokenSource("<your sandbox token server id>");final session = sdk.Session.fromConfigurableTokenSource(tokenSource,const TokenRequestOptions(agentName: "my-agent"),);await session.start();// End the session when doneawait session.end();
Using AgentSessionProvider
If you're building with Agents UI components, the AgentSessionProvider component wraps the session from useSession and provides session context to all child components. Agents UI components like AgentControlBar, AgentChatTranscript, and the audio visualizers require this provider as an ancestor.
'use client';import { useSession } from '@livekit/components-react';import { AgentSessionProvider } from '@/components/agents-ui/agent-session-provider';import { TokenSource } from 'livekit-client';const tokenSource = TokenSource.sandboxTokenServer('<your sandbox token server id>');export function App() {const session = useSession(tokenSource, { agentName: 'my-agent' });return (<AgentSessionProvider session={session}>{/* Agents UI components can access session context here */}</AgentSessionProvider>);}
AgentSessionProvider reference
Full API reference and props documentation.