Most load testing failures aren't caused by LiveKit or your agent code. They're caused by how the test itself is run. The most common mistake is going from zero to full concurrency in a single burst, which overwhelms infrastructure that's designed to scale gradually and produces misleading results.
This guide covers the right way to load test voice agents on LiveKit Cloud, the tooling available, and the pitfalls to avoid.
Why burst testing produces bad results#
Burst tests — going from zero to full concurrency in a single spike — are most likely not representative of your actual user traffic. Real users don't all arrive at the exact same millisecond. They connect gradually, which gives autoscaling infrastructure time to respond.
When you bypass that natural ramp-up, you're testing cold-start behavior under artificial conditions, not steady-state performance. The results won't reflect what your users actually experience.
Common symptoms of a burst test that's fighting the infrastructure rather than measuring it:
- Inflated join latency. Autoscaling needs time to provision capacity. A burst forces all sessions to compete for resources simultaneously, producing latency numbers that wouldn't occur in production.
- Quota limits exhausted instantly. Concurrent session limits, LiveKit Inference quotas, and STT/TTS rate limits are consumed all at once instead of naturally staggering across sessions.
- Misleading error rates. Failures caused by the test design get attributed to the platform, leading to incorrect conclusions about reliability.
The fix is simple: add a ramp-up. The same infrastructure that struggles under a burst test will perform well with a controlled, gradual increase in load.
Use the CLI for agent load testing#
The LiveKit CLI includes a purpose-built agent load tester. It creates rooms, dispatches your agent, and places an echo participant in each room that plays back the agent's audio.
1lk perf agent-load-test \2--rooms 10 \3--agent-name my-agent \4--echo-speech-delay 10s \5--duration 5m
This command creates 10 rooms, dispatches my-agent to each one, and runs for 5 minutes. The echo participant waits 10 seconds before replaying the agent's speech, simulating a real conversation cadence.
Built-in ramp-up behavior#
The CLI doesn't create all rooms at once. It follows a sequential ramp-up:
- A room is created.
- The agent joins the room.
- After the agent successfully joins, the next room is created.
This produces a controlled, realistic ramp-up. If you need faster scaling, you can run the CLI from multiple machines.
Requirements for accurate results#
Your agent must initiate the conversation. The echo participant only responds to what it hears, so if your agent waits for user input, nothing happens. Add an initial greeting to your agent:
1await session.generate_reply(2instructions="Greet the user warmly and offer your assistance.",3)
Use start mode (production) rather than dev mode. Dev mode doesn't handle SIGTERM signals correctly, which can cause agents to keep accepting jobs after they should have stopped — something you definitely don't want during a load test.
Testing against deployed agents#
You can run the CLI load test against agents deployed to LiveKit Cloud (not just locally running agents). This is actually recommended, because you also get agent stats on the Cloud dashboard — including load, join latency percentiles, and session counts.
After the test completes, the CLI displays a table showing agent join delay for each room. You can also review detailed logs, transcripts, and audio recordings through Agent Insights on the dashboard.
Design a realistic ramp-up#
If the CLI tool doesn't meet your needs and you're writing a custom load test script, design the ramp-up to reflect actual production traffic patterns.
Recommended approach#
- Start small. Begin with 5–10 concurrent sessions and hold steady for a few minutes.
- Increase incrementally. Add 10–20 sessions per step, waiting 30–60 seconds between increases.
- Hold at target. Once you reach your target concurrency, hold for at least 5 minutes to observe steady-state behavior.
- Monitor between steps. Check join latency, error rates, and resource utilization before increasing further.
A reasonable ramp for testing 100 concurrent sessions:
10:00 — 10 sessions21:00 — 25 sessions32:00 — 50 sessions43:00 — 75 sessions54:00 — 100 sessions64:00–9:00 — hold at 100
What to measure#
- Agent join delay. Time from room creation to agent joining. This is the primary signal for scaling health.
- First-message delivery. Whether the agent's greeting reaches the participant.
- End-to-end latency. Time from user speech to agent response.
- Error rates. Connection failures, dispatch errors, or quota exceeded responses.
- Resource utilization. CPU, memory, and inference concurrency on the dashboard.
Know your plan limits#
Load tests are subject to the same quotas and limits as production traffic. Before running a test, verify your plan supports the concurrency you're targeting.
Key limits to check:
- Concurrent agent sessions. Each plan tier has a maximum. Build plan has limited concurrency with cold starts possible. Ship and Scale plans support higher concurrency with autoscaling.
- LiveKit Inference concurrency. If your agent uses LiveKit-hosted STT, LLM, or TTS models, those have separate concurrency limits. A burst of sessions can exhaust inference quotas before the agent even joins.
- Usage quotas. Load testing traffic counts toward your billing quotas, the same as production traffic.
If you need to test at a scale that exceeds your current plan limits, contact the LiveKit team before running the test. For expected burst traffic patterns in production, an enterprise plan can be provisioned to support your specific load profile.
Notify LiveKit before large-scale tests#
For tests involving more than a few hundred concurrent sessions, let the LiveKit team know in advance. This isn't a hard requirement at smaller scales — a 1,000 CCU test with a reasonable ramp-up (10 connections per second) likely won't even be noticed — but it's good practice to coordinate for larger tests.
Provide the following details:
- Project ID. Found on the Cloud dashboard.
- Expected peak concurrency. Maximum number of simultaneous sessions.
- Ramp-up plan. How quickly you'll increase load.
- Regions. Where participants will connect from.
- Media configuration. Audio-only, video tracks, simulcast settings.
This helps the team verify that capacity is available and prevents your test from being flagged as anomalous traffic.
Running load tests from cloud VMs#
Your local ISP bandwidth likely can't sustain hundreds of concurrent WebRTC connections. Run load tests from cloud VMs (AWS, GCP, Azure) where bandwidth isn't a constraint.
Before running, configure system limits on the VM:
1ulimit -n 655352sysctl -w fs.file-max=20971523sysctl -w net.core.somaxconn=655354sysctl -w net.core.rmem_max=251658245sysctl -w net.core.wmem_max=25165824
These settings ensure the kernel can handle the number of file descriptors and socket buffers needed for concurrent connections.
If the CLI doesn't meet your needs#
For more complex scenarios — custom conversation flows, integration testing with your backend, or multi-region tests — you can build your own load test by scripting room creation and agent dispatch directly.
Use the LiveKit Server SDKs to create rooms and dispatch agents programmatically. The same ramp-up principles apply: create rooms sequentially or with controlled delays, and don't burst all sessions simultaneously.
The lk load-test command (separate from lk perf agent-load-test) is designed for WebRTC transport-level testing — simulating publishers and subscribers in a room. It's useful for benchmarking video/audio infrastructure but isn't agent-aware. Use lk perf agent-load-test for agent-specific load testing.
Summary#
- Ramp up gradually. Never go from zero to full concurrency in a single burst.
- Use the CLI tool.
lk perf agent-load-testhandles ramp-up correctly and produces useful metrics. - Test against deployed agents. You get dashboard metrics and realistic infrastructure behavior.
- Check your plan limits first. Know your concurrency caps and inference quotas before testing.
- Run from cloud VMs. Local bandwidth is almost never sufficient for meaningful load tests.
- Coordinate for large tests. Let LiveKit know if you're testing at hundreds of concurrent sessions or above.