LiveKit vs ZEGOCLOUD vs Agora: what a voice-chat app really costs, and when self-hosting wins
A worked cost comparison for audio rooms using each provider's published prices, how participant-minutes add up, and what it takes to run LiveKit on your own server instead.
If you're building a voice-chat app (audio rooms, a social app with live "majlis" rooms, a tutoring app), the real-time audio bill can grow faster than your user base. This guide works through the arithmetic with each provider's published prices, then looks at what self-hosting LiveKit actually involves.
The unit that matters: participant-minutes
All three hosted options bill roughly the same thing: minutes each participant spends connected. A room with 20 people for one hour is not 60 minutes, it is 20 × 60 = 1,200 participant-minutes.
So for an audio-room app:
monthly minutes = rooms per day × participants per room × minutes per session × 30Example A, a small community app: 5 rooms a day, 20 people each, 2 hours → 5 × 20 × 120 × 30 = 360,000 participant-minutes/month.
Example B, a growing app: 40 rooms a day, 25 people, 2 hours → 3,600,000 participant-minutes/month.
Published prices (October 2026)
| Provider | Free allowance | Paid rate |
|---|---|---|
| Agora RTC | 10,000 minutes/month | "Starts at $0.59 per 1,000 minutes" (voice, video and live streaming share one RTC line on the page) |
| ZEGOCLOUD Voice Call | 10,000 minutes on sign-up | $0.99 per 1,000 participant-minutes |
| LiveKit Cloud: Build | 5,000 WebRTC minutes, 50 GB downstream | $0 |
| LiveKit Cloud: Ship | 150,000 minutes, 250 GB included | from $50/month, then $0.0005/min and $0.12/GB |
| LiveKit Cloud: Scale | 1.5M minutes, 3 TB included | from $500/month, then $0.0004/min and $0.10/GB |
Agora's page shows one "starts at" figure for all RTC usage and does not break out audio pricing on that page, so treat $0.59 as a floor and confirm the audio rate in your console. Older listings commonly showed $0.99 per 1,000 audio minutes.
Worked costs
Example A (360,000 min/month):
- Agora: (360,000 − 10,000) ÷ 1,000 × $0.59 ≈ $207 (≈ $347 at $0.99)
- ZEGOCLOUD: 350 × $0.99 ≈ $347 (the 10,000 free minutes are a sign-up allowance, so after that month it's ≈ $356)
- LiveKit Cloud Ship: $50 + (360,000 − 150,000) × $0.0005 = $155, plus bandwidth beyond 250 GB
Example B (3.6M min/month):
- Agora: ≈ 3,590 × $0.59 ≈ $2,118 (≈ $3,554 at $0.99)
- ZEGOCLOUD: 3,600 × $0.99 ≈ $3,564
- LiveKit Cloud Scale: $500 + (3,600,000 − 1,500,000) × $0.0004 = $1,340, plus bandwidth beyond 3 TB
These are list-price calculations only. They ignore extras like recording, transcoding or AI noise suppression, which each provider bills separately.
What self-hosting changes
LiveKit's media server is open source, so you can run it yourself. The cost model flips from per minute to per server: you pay for capacity whether or not anyone is talking, and nothing per participant-minute.
To size a server, you need to know how an SFU (selective forwarding unit) works. LiveKit doesn't mix audio; it forwards each speaker's stream to each listener:
forwarded streams ≈ people talking at the same moment × people listeningTwo consequences:
- Silent open mics cost almost nothing. Opus with DTX sends very little during silence. What costs CPU and bandwidth is many people talking at once in a big room.
- One room must fit on one server. LiveKit spreads rooms across nodes, but never splits a single room.
For scale reference, LiveKit's published benchmark ran 10 speakers to 3,000 listeners (about 30,000 forwarded streams) on a 16-core compute-optimized Google Cloud VM at around 80% CPU. Your numbers will differ, which is why you load-test before launch.
Bandwidth is the other half. Voice is roughly 24 to 32 kbps per forwarded stream while someone talks. Many VPS providers include several TB of traffic per month, which is why self-hosting audio rooms can be much cheaper than per-minute billing once usage is steady.
When self-hosting makes sense
- Usage is steady and you can estimate peak concurrent talkers.
- Your users are concentrated in one region (one well-placed server gives good latency).
- Someone on the team can run a Linux server: updates, monitoring, and a plan for when it goes down.
When it doesn't
- You're still under the free tiers. Don't operate infrastructure you don't need yet.
- You need a global low-latency mesh across many regions on day one.
- Nobody owns the server. A hosted provider's bill is cheaper than an outage nobody notices.
How to self-host LiveKit (the short version)
LiveKit's docs include a config generator for deploying to a VM:
docker pull livekit/generate
docker run --rm -it -v$PWD:/output livekit/generateIt produces a docker-compose.yaml, livekit.yaml, a Caddy config for TLS, a Redis config, and an init script or cloud-init file. Then:
- Point two DNS records (the main domain and the TURN domain) at the VM, so Caddy can get certificates.
- Open the firewall: 443 (HTTPS and TURN/TLS), 80 (certificate issuance), 7881/tcp (WebRTC over TCP), 3478/udp (TURN/UDP) and 50000–60000/udp (WebRTC over UDP).
- Run the init script, or paste the cloud-init file when creating the VM.
The commonest failure is "connects but no audio": the UDP range is blocked by a cloud firewall. TURN over TLS on 443 is the fallback that gets through restrictive networks.
Tokens: never ship your API secret
Clients join with a short-lived JWT that your backend signs with the LiveKit API key and secret. From LiveKit's docs, in Node:
import { AccessToken } from "livekit-server-sdk";
const at = new AccessToken(process.env.LIVEKIT_API_KEY, process.env.LIVEKIT_API_SECRET, {
identity: userId, // an opaque id, not a phone number
ttl: "10m",
});
at.addGrant({ room: roomName, roomJoin: true, canPublish: true, canSubscribe: true });
const token = await at.toJwt();For a listen-only audience, set canPublish: false, or restrict sources with canPublishSources: ["microphone"]. Issue tokens only after verifying your own user session. Server SDKs default to a 6-hour TTL if you don't set one.
Migrating from ZEGOCLOUD or Agora
The audio itself is standard WebRTC/Opus, so the migration is mostly client work:
- Swap the SDK (LiveKit has Flutter, React Native, iOS, Android and web SDKs) and rebuild the room screen: join, mic toggle, speaking indicators.
- Move token issuance to your backend.
- Re-implement anything that depended on the old provider's signalling or messaging features.
- Run both in parallel behind a feature flag, then switch rooms over gradually.
A real test before you commit
When I packaged a self-hosted LiveKit setup for Flutter, I tested it locally with livekit-server v1.13.10 and an audio load test of 3 speakers × 10 listeners: all 30 forwarded tracks arrived, with 0% packet loss. That's a functional check, not a capacity benchmark. Run LiveKit's lk load-test against your own server with your expected speaker and listener counts before you move real users.
The bottom line
- Under the free tiers: stay hosted.
- At a few hundred thousand minutes a month, LiveKit Cloud's included minutes already undercut per-minute pricing on these list prices.
- At millions of minutes a month with predictable usage in one region, a self-hosted LiveKit server trades a large variable bill for a fixed server bill, plus the responsibility of running it.
Sources
Want this done for you?
Kit
Self-hosted LiveKit voice server for Flutter apps
One-command install on Ubuntu 24.04 with automatic TLS and built-in TURN, a Node/TypeScript token server, a Flutter voice-room screen, a sizing table and a ZEGOCLOUD migration checklist.