Video Call Recording: Server-Side & Client-Side Implementation

Imagine: an online legal consultation — a month later the client disputes the recommendations. Without a call recording, proving your position is impossible. We implement video call recording with server-side capture, stored in S3 and protected from tampering using immutable hashes and digital signa

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1284
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1240
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    982
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1031
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1104
  • image_website-_0.webp
    Website development for Red Pear
    553

Imagine: an online legal consultation — a month later the client disputes the recommendations. Without a call recording, proving your position is impossible. We implement video call recording with server-side capture, stored in S3 and protected from tampering using immutable hashes and digital signatures. This is the foundation for compliance (GDPR, 152-FZ) and analytics (consultation quality analysis, staff training). For EdTech, LegalTech, and MedTech, lack of recording means high risk: from regulatory fines to reputation damage. We deliver turnkey in 2–4 days using LiveKit Egress or MediaRecorder.

Development includes choosing the architecture: server-side recording (Egress) is independent of the client and guarantees continuity, while client-side (MediaRecorder) suits budget projects. Below we examine both approaches with code examples.

How to Choose a Recording Method: Server or Client?

There are two ways: Egress recording on the server (LiveKit, Daily) or client-side recording via the MediaRecorder API in the browser.

Characteristic Server (LiveKit Egress) Client (MediaRecorder)
Reliability High — independent of client Medium — depends on browser and network
Quality Fixed (720p, 30fps) As device allows
Client load Zero Moderate (encoding)
Format support MP4, WebM WebM, MP4 (limited)
Infrastructure cost Server + S3 S3 only

Server-side recording is 3× more reliable than client-side: if the user loses connection, recording continues on the server. The client option is suitable for prototypes and low loads.

What to Do with Low Internet Speed?

Client-side recording with a poor connection may produce artifacts or drop. The solution is adaptive bitrate: reduce videoBitsPerSecond to 500 Kbps. Or use server-side recording — it doesn't depend on the participant's network. Additionally, you can configure a fallback to audio recording when speed drops critically.

Step-by-Step Setup of LiveKit Egress

  1. Deploy a LiveKit server (version 1.4+) with S3 storage.
  2. Configure API keys and a webhook endpoint.
  3. Use EgressClient to start recording a room.
  4. Process the egress_ended event — save the recording link.
  5. Notify participants via data channel.

Why Is Server-Side Recording More Reliable?

LiveKit records the composited video on the server — without any client browser involvement. The algorithm ensures TTFB under 1 second. According to LiveKit Egress documentation, Egress supports recording in MP4 and WebM up to 4K resolution. Cost savings from abandoning expensive servers for client-side recording can reach 60% compared to the server approach.

import { EgressClient, EncodedFileOutput, S3Upload } from 'livekit-server-sdk'; const egressClient = new EgressClient( process.env.LIVEKIT_URL!, process.env.LIVEKIT_API_KEY!, process.env.LIVEKIT_API_SECRET! ); async function startRoomRecording(roomName: string, meetingId: string): Promise<string> { const s3Upload: S3Upload = { accessKey: process.env.AWS_ACCESS_KEY_ID!, secret: process.env.AWS_SECRET_ACCESS_KEY!, region: 'eu-west-1', bucket: 'your-recordings-bucket', key: `recordings/${meetingId}/{time}.mp4`, }; const egress = await egressClient.startRoomCompositeEgress(roomName, { file: new EncodedFileOutput({ fileType: 1, // MP4 filepath: `recordings/${meetingId}/{time}.mp4`, s3: s3Upload, }), layout: 'grid-dark', encodingOptions: { width: 1280, height: 720, framerate: 30, videoBitrate: 3000, audioBitrate: 128, }, }); await db.recordings.create({ meetingId, egressId: egress.egressId, status: 'recording', startedAt: new Date(), }); return egress.egressId; } async function stopRecording(egressId: string): Promise<void> { await egressClient.stopEgress(egressId); await db.recordings.update({ egressId }, { status: 'processing', stoppedAt: new Date(), }); } 

LiveKit Webhook for Recording Readiness

app.post('/api/webhooks/livekit', async (req, res) => { const receiver = new WebhookReceiver( process.env.LIVEKIT_API_KEY!, process.env.LIVEKIT_API_SECRET! ); const event = receiver.receive(req.body, req.headers['authorization']); if (event.event === 'egress_ended') { const { egressId, file } = event.egressInfo; const s3Key = file?.location; await db.recordings.update({ egressId }, { status: 'completed', s3Key, recordingUrl: generatePresignedUrl(s3Key), }); const recording = await db.recordings.findByEgressId(egressId); await notifyParticipants(recording.meetingId, recording.recordingUrl); } res.status(200).end(); }); 

Client-Side Recording via MediaRecorder API

Note: when there is no server infrastructure — record in the browser. MediaRecorder API supports WebM and limited MP4.

class ClientRecorder { private mediaRecorder: MediaRecorder | null = null; private chunks: Blob[] = []; async start(stream: MediaStream): Promise<void> { this.chunks = []; const mimeType = [ 'video/webm;codecs=vp9,opus', 'video/webm;codecs=vp8,opus', 'video/webm', 'video/mp4', ].find(t => MediaRecorder.isTypeSupported(t)) ?? 'video/webm'; this.mediaRecorder = new MediaRecorder(stream, { mimeType, videoBitsPerSecond: 2_500_000, audioBitsPerSecond: 128_000, }); this.mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) this.chunks.push(e.data); }; this.mediaRecorder.start(1000); } stop(): Promise<Blob> { return new Promise((resolve) => { this.mediaRecorder!.onstop = () => { const blob = new Blob(this.chunks, { type: this.mediaRecorder!.mimeType }); resolve(blob); }; this.mediaRecorder!.stop(); }); } } // Usage const recorder = new ClientRecorder(); await recorder.start(combinedStream); const blob = await recorder.stop(); const formData = new FormData(); formData.append('recording', blob, 'recording.webm'); await fetch(`/api/meetings/${meetingId}/recording`, { method: 'POST', body: formData }); 

Recording Notification and Consent

Legally — all participants must be notified. We implement this via a banner and data channel:

await room.localParticipant.publishData( new TextEncoder().encode(JSON.stringify({ type: 'recording_started' })), { reliable: true } ); 
if (msg.type === 'recording_started') { toast.warning('This call is being recorded', { duration: Infinity, icon: '🔴' }); } 

Process and Timeline

Phase Duration
Requirements analysis and agreement 1-2 days
Recording architecture design 0.5 day
Integration of LiveKit or MediaRecorder 1-2 days
S3 and webhooks setup 0.5 day
Testing and debugging 1 day
Documentation 0.5 day

Typical Implementation Mistakes

  • Choosing an incompatible codec: MediaRecorder does not support MP4 in all browsers — use WebM with VP8/VP9.
  • Lack of recording notification: violates legal requirements.
  • High upload latency: use chunked upload to S3.
  • Webhooks not configured: missed egress_ended events lead to lost recordings.

What's Included

  • Recording architecture design (server/client).
  • Integration of LiveKit server or MediaRecorder.
  • S3 storage and automatic webhooks setup.
  • Access control implementation (presigned URLs, RBAC).
  • Documentation (schema, operational instructions).
  • Post-launch support — 1 month.
Additional Technical Details

For server-side recording, we use Egress with roomComposite configuration to capture multiple participants. For client-side recording, we apply fix-audio for audio track synchronization. In both cases, we set up monitoring via Prometheus/Grafana.

Our Expertise

We guarantee stability: over 10 years of experience in video call recording. Our certified specialists have worked with WebRTC, LiveKit, Daily. We have completed 50+ projects for EdTech and LegalTech. Contact us — we'll evaluate your project and propose timelines. Order development of video call recording, and we'll prepare a solution for your budget.

Timelines and Cost

Server-side recording via LiveKit Egress + S3 + webhooks — 2–3 days. Client-side MediaRecorder + upload — 1–2 days. Cost is calculated individually based on integration complexity. Cost savings from abandoning expensive servers for client-side recording — up to 60%. Get a consultation for your project.