Integrating LiveKit with Roark enables automatic analysis of audio call recordings. After each call, audio recordings and related metadata are made available to Roark. Roark processes this data to evaluate assistant or participant behavior and analyze tool usage and conversation flow.
LiveKit does not store call recordings by default. To enable recording, you need to explicitly start an egress session using the LiveKit Egress API. This setup guide walks you through the steps required to configure recording and send audio data to Roark for analysis.
In this example, we’ll use AWS S3 to store the recordings. To get started, you’ll need the following:
Your LiveKit API credentials (API Key and Secret)
A valid AWS S3 bucket and AWS credentials
The name of the LiveKit room you want to record
Once everything is set up, you can call the Egress API to start recording and store the audio in your S3 bucket.
Copy
Ask AI
// Initialize LiveKit Egress clientconst hostURL = new URL(process.env.LIVEKIT_URL);hostURL.protocol = 'https:';const egressClient = new EgressClient( hostURL.origin, process.env.LIVEKIT_API_KEY, process.env.LIVEKIT_API_SECRET);// Start recordingasync function startRecording(roomName: string) { const fileOutput = new EncodedFileOutput({ // Use a unique filename for each recording filepath: `${new Date(Date.now()).toISOString()}-${roomName}.mp4`, output: { case: 's3', value: new S3Upload({ endpoint: process.env.S3_ENDPOINT, accessKey: process.env.S3_KEY_ID, secret: process.env.S3_KEY_SECRET, region: process.env.S3_REGION, bucket: process.env.S3_BUCKET, }), }, }); await egressClient.startRoomCompositeEgress( roomName, { file: fileOutput }, { layout: 'speaker' } );}
4
Stopping the Recording in LiveKit
Once the session ends, you should stop the recording to ensure it is properly saved to your storage provider. This action will also trigger the egress_ended webhook event, which includes the recording URL.When stopping the egress session, make sure you reference the correct room name that was used to start the session.
For more details on available LiveKit webhook events, see the webhook documentation.
LiveKit provides webhooks that notify you about changes in the room, participants, and egress sessions. In our case, when you stop the recording using the Egress API, the egress_ended event will be triggered. This event includes the URL of the recording uploaded to your S3 storage.
The implementation for handling this webhook event is as follows:
Copy
Ask AI
// This example is using express.jsimport { WebhookReceiver } from "livekit-server-sdk";import express from "express";const app = express();// Enable raw body parsing for LiveKit webhook events// @see https://docs.livekit.io/home/server/webhooks/#receiving-webhooksapp.use(express.raw({ type: "application/webhook+json" }));// LiveKit webhook receiverconst receiver = new WebhookReceiver( process.env.LIVEKIT_API_KEY, process.env.LIVEKIT_API_SECRET);app.post("/webhook/livekit", async (req, res) => { const event = await receiver.receive( req.body, req.get("Authorization"), true ); // Handle egress ended event if (event.event === "egress_ended") { const result = event.egressInfo.result; // S3 Uploaded File URL const fileUrl = result.value.filename; // Rest of the implementation... }})
6
S3 Acccess
LiveKit does not support S3 pre-signed URLs. Therefore, once your recording is uploaded to your own S3 bucket, you should generate a signed URL yourself to provide secure, time-limited access to the file. This ensures that only authorized users can access the recording without exposing it publicly.
To send a call to evaluate using Roark, you need participant information from the session. You can retrieve participant details by using the LiveKit SDK.
Copy
Ask AI
import { RoomServiceClient } from "livekit-server-sdk";async function getParticipants(roomName) { const roomService = new RoomServiceClient( process.env.LIVEKIT_URL, process.env.LIVEKIT_API_KEY, process.env.LIVEKIT_API_SECRET ); const participants = await roomService.listParticipants(roomName); return participants;}
8
Send call to evaluate using Roark
Final step, once you have gathered all the necessary data, map it to the format required by the Roark SDK before sending. Below is an example of what the complete implementation should look like.
Copy
Ask AI
import Roark from "@roarkanalytics/sdk";// Initialize Roarkconst roark = new Roark(process.env.ROARK_API_KEY);// Your LiveKit webhook endpointapp.post("/webhook/livekit", async (req, res) => { const event = await receiver.receive( req.body, req.get("Authorization"), true ); // Handle egress ended event if (event.event === "egress_ended") { const result = event.egressInfo.result; // S3 Uploaded File URL const fileUrl = result.value.filename; // Generate signed URL for S3 file const signedUrl = await generateSignedUrl(fileUrl); // Get list of participants const participants = await getParticipants(event.egressInfo.roomName); const partipants = []; for (const participant of participants) { partipants.push({ role: participant?.kind === 0 ? "AGENT" : "CUSTOMER", name: participant?.name, spokeFirst: participant?.kind === 0, phoneNumber: participant?.sip?.phoneNumber, }); } // Create an evaluation for a single call await roark.evaluation.createJob({ /** * You can find the evaluator slug from the Evaluators section on the dashboard * Or you can use 'all' to evaluate with all available evaluators. * * Evaluators to evaluate the call * Usage examples: * - Specific evaluators: evaluators: ['evaluator-slug-1', 'evaluator-slug-2'] * - All evaluators: evaluators: 'all' */ evaluators: ["evaluator-slug-1", "evaluator-slug-2"], call: { recordingUrl: signedUrl, startedAt: new Date().toISOString(), callDirection: "INBOUND", interfaceType: "PHONE", participants: partipants, }, }); } res.sendStatus(200);});
🎉 You’re all set!
Your LiveKit assistant is now integrated with Roark.