I'd like to record audio conversations using the E...
# ask-ai
b
I'd like to record audio conversations using the Egress facility. Can I get transcripts of the speech?
✅ 1
t
Thanks for reaching out, Mat. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — regarding your question about Egress recordings and transcripts: • Egress can record audio (room- or track-level) and export those recordings to cloud storage or streams. • Egress does not itself produce speech-to-text transcripts. • To get transcripts you can use LiveKit Agents: they produce real-time transcriptions (published on the
lk.transcription
text stream and via agent transcription nodes) and provide timing/sync options. Agent transcripts and observability data can be used alongside Egress recordings for synchronized playback/analysis. Would you like help with: • configuring an Agent to produce transcripts for a room, or • wiring Egress recordings and Agent transcription output together (storage, timing, or formats)? Sources: Universal Egress | LiveKit | Text and transcriptions | LiveKit Documentation | Understanding Transcript Timing in Voice Conversations | LiveKit Agent Observability | Debug and optimize voice agents | LiveKit, with interactive elements
b
How would I send Egress output to Firestore?
t
Thanks — regarding sending Egress output to Firestore: • Egress cannot write media files directly to Firestore. Firestore is for structured documents, not binary media. • Recommended approach: a. Configure Egress to export recordings to Google Cloud Storage (GCS). b. Subscribe to the
egress_ended
webhook (it contains the output file URL). c. In a Cloud Function (or your backend) triggered by the webhook: • Read the file from GCS (or run STT if you need transcripts). • Save structured data to Firestore (file URL, metadata, transcript, timestamps, session IDs). • Alternatives: ◦ Export to S3 and use an AWS Lambda to write metadata to Firestore. ◦ Stream audio via WebSocket for real‑time processing, then persist results to Firestore. Would you like a sample Cloud Function (GCS -> Firestore) or the exact webhook payload fields to use? Sources: Universal Egress | LiveKit | Best practices for managing webhook event streams | LiveKit | server-sdk-js | livekit/livekit_composite | DeepWiki, with interactive elements
b
How would I sent Egress output to Firebase Storage?
t
You're asking how to send LiveKit Egress output to Firebase Storage — good question. Firebase Storage is backed by Google Cloud Storage (GCS), so the recommended path is to export Egress to GCS and access it via your Firebase project. High-level steps: 1. Configure Egress to export to GCS: ◦ Set the Egress output bucket/path to a GCS bucket in your Firebase project or a bucket you control. 1. Ensure permissions: ◦ Give LiveKit Egress (or the service account you use to run Egress) write access to that GCS bucket (e.g., roles/storage.objectCreator or storage.objectAdmin). 1. Use the
egress_ended
webhook: ◦ Subscribe to the webhook so you receive the output file URL and metadata when recording finishes. 1. (Optional) Move/serve via Firebase Storage SDK: ◦ If you want the file surfaced through Firebase Storage APIs, keep the file in the project’s GCS bucket (no extra copy needed). Firebase Storage clients can access files in that bucket, subject to Firebase security rules and IAM. 1. (Optional) Post-processing: ◦ Trigger a Cloud Function from the
egress_ended
webhook or a GCS upload trigger to update Firestore, generate thumbnails/transcripts, change ACLs, or notify users. If you’d like, I can provide: • A sample Egress output config targeting GCS, • Example IAM bindings for the service account, or • A Cloud Function template that handles
egress_ended
and updates Firebase (Storage/Firestore). Which would help most?, with interactive elements
b
I would like an example for writing Egress output GCS, in JavaScript.
t
Thanks — I’ll show a concise JavaScript example that starts a LiveKit Room Composite Egress writing to Google Cloud Storage (Firebase Storage uses the same GCS bucket). It also shows a webhook handler to catch
egress_ended
and save metadata to Firestore. Prerequisites: •
livekit-server-sdk
installed • A GCS service account JSON (client_email and private_key) • LIVEKIT_API_KEY, LIVEKIT_API_SECRET, LIVEKIT_URL, GCS_CLIENT_EMAIL, GCS_PRIVATE_KEY, GCS_BUCKET env vars • Your GCS bucket belongs to the Firebase project if you want Firebase Storage access 1) Start Egress to GCS (server-side)
Copy code
// startEgress.js
const { EgressClient, RoomCompositeEgressRequest } = require('livekit-server-sdk');

const egressClient = new EgressClient({
  apiKey: process.env.LIVEKIT_API_KEY,
  apiSecret: process.env.LIVEKIT_API_SECRET,
  host: process.env.LIVEKIT_URL,
});

async function startEgressToGCS(roomName, gcsPath) {
  const req = new RoomCompositeEgressRequest({
    roomName,
    output: {
      file: {
        filepath: gcsPath, // e.g., 'recordings/session-123.mp4'
        gcs: {
          bucket: process.env.GCS_BUCKET,
          credentials: {
            client_email: process.env.GCS_CLIENT_EMAIL,
            private_key: process.env.GCS_PRIVATE_KEY,
          },
        },
      },
    },
    // optional: format/layout settings
    // layout: 'speaker-dark',
  });

  const info = await egressClient.startRoomCompositeEgress(req);
  console.log('egress started:', info.egressId);
  return info;
}

module.exports = { startEgressToGCS };
2) Webhook to receive egress completion and write metadata to Firestore
Copy code
// webhook.js
const express = require('express');
const bodyParser = require('body-parser');
const admin = require('firebase-admin');
const { WebhookReceiver } = require('livekit-server-sdk');

admin.initializeApp(); // make sure FIREBASE credentials are set in env or runtime
const db = admin.firestore();

const receiver = new WebhookReceiver(process.env.LIVEKIT_API_KEY, process.env.LIVEKIT_API_SECRET);
const app = express();

app.post('/webhook', bodyParser.raw({ type: 'application/json' }), async (req, res) => {
  let event;
  try {
    event = receiver.receive(req.body, req.headers['authorization']);
  } catch (err) {
    console.error('invalid webhook signature', err);
    return res.status(400).end();
  }

  if (event.event === 'egress_ended' && event.egressInfo?.status === 'EGRESS_COMPLETE') {
    const info = event.egressInfo;
    const fileUrl = info.file?.location || null;
    const doc = {
      egressId: info.egressId,
      room: info.roomName,
      status: info.status,
      fileUrl,
      startedAt: info.startedAt,
      endedAt: info.endedAt,
      // add any other fields you need
    };
    try {
      await db.collection('egressRecords').doc(info.egressId).set(doc);
      console.log('egress metadata written to Firestore:', info.egressId);
    } catch (err) {
      console.error('failed to write to Firestore', err);
    }
  }

  res.status(200).end();
});

module.exports = app;
Notes and tips: • The GCS credentials in the Egress request are the service account that LiveKit will use to upload the file; ensure the service account has storage.objectCreator/storage.objectAdmin on the bucket. • If you prefer, you can export to a bucket you control and set Firebase security rules/IAM to allow access from Firebase clients. • Use the
egress_ended
webhook payload
egressInfo.file.location
for the stored object URL; you can then surface that URL via Firebase Storage APIs or Firestore documents. Would you like a ready-to-run example repository or the exact webhook payload shape copied for your function? Sources: Universal Egress | LiveKit | server-sdk-js | livekit/livekit_composite | DeepWiki, with interactive elements