Quickstart
Connect to an Expressive Agent with the LiveKit SDK in six steps
Create a V2 session for an Expressive Agent and connect to it directly with the LiveKit SDK. This path is for backend services and native apps.
Install the LiveKit SDK
Install the SDK for your platform.
npm install livekit-server-sdk node-fetchnpm install livekit-clientpip install livekit-apiCreate an Expressive Agent
V2 sessions only work with Expressive Agents. Create one via the Agents API or D-ID Studio. The presenter type must be expressive.
curl -X POST "https://api.d-id.com/agents" \
-H "Authorization: Basic <YOUR KEY>" \
-H "Content-Type: application/json" \
-d '{
"presenter": {
"type": "expressive",
"presenter_id": "public_mia_elegant@avt_TJ0Tq5"
}
}'{
"id": "agt_abc123",
"status": "created"
}Save the id — this is your agentId for the next step.
Create a session
Call Create Session V2 to get a LiveKit URL and token.
curl -X POST "https://api.d-id.com/v2/agents/agt_abc123/sessions" \
-H "Authorization: Basic <YOUR KEY>"{
"id": "session_abc123xyz",
"session_url": "wss://livekit.d-id.com",
"session_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Save session_url and session_token for the next step.
Connect to the LiveKit room
Use the credentials from step 3 to join the LiveKit room.
import { Room } from "livekit-client";
const room = new Room();
await room.connect(session.session_url, session.session_token);from livekit import rtc
room = rtc.Room()
await room.connect(session["session_url"], session["session_token"])Render the agent's video and audio
The agent publishes its video and audio as separate LiveKit tracks. Listen for TrackSubscribed and attach each track to a media element so the user can see and hear the agent.
import { RoomEvent, Track } from "livekit-client";
room.on(RoomEvent.TrackSubscribed, (track) => {
if (track.kind === Track.Kind.Video) {
track.attach(document.getElementById("agent-video") as HTMLVideoElement);
} else if (track.kind === Track.Kind.Audio) {
track.attach(document.getElementById("agent-audio") as HTMLAudioElement);
}
});Your HTML needs a <video> and <audio> element for the tracks to attach to:
<video id="agent-video" autoplay playsinline></video>
<audio id="agent-audio" autoplay></audio>from livekit import rtc
def on_track_subscribed(track, publication, participant):
if track.kind == rtc.TrackKind.KIND_VIDEO:
# Handle video frames (e.g. forward to a renderer or recorder)
pass
elif track.kind == rtc.TrackKind.KIND_AUDIO:
# Handle audio frames (e.g. forward to a speaker or recorder)
pass
room.on("track_subscribed", on_track_subscribed)Python rendering depends on your runtime — see the LiveKit Python tracks guide for frame handling examples.
Control the agent and handle responses
Commands are sent as text on a data-channel topic. Responses arrive as data events on the same channel.
// Send a speak command (text → video)
await room.localParticipant.sendText(
JSON.stringify({ script: { type: "text", input: "Hello!" } }),
{ topic: "did.speak" }
);
// Listen for agent responses
room.on(RoomEvent.DataReceived, (payload) => {
const data = JSON.parse(new TextDecoder().decode(payload));
if (data.subject === "stream-video/done") console.log("Video ready");
if (data.subject === "chat/answer") console.log("Agent:", data.content);
});import json
# Send a speak command (text → video)
await room.local_participant.send_text(
json.dumps({"script": {"type": "text", "input": "Hello!"}}),
topic="did.speak",
)
# Listen for agent responses
def on_data(packet, participant):
data = json.loads(packet.data.decode("utf-8"))
if data.get("subject") == "stream-video/done":
print("Video ready")
elif data.get("subject") == "chat/answer":
print("Agent:", data.get("content"))
room.on("data_received", on_data)Your app is now streaming from the agent. For deeper coverage of each interaction, see Control the Agent, Subscribe to Media Tracks, and Listen for Agent Events.
Updated 3 months ago
