Skip to main content

Why is my agent slow to join a room?

Most users focus on improving conversational latency between the user and the agent, but you should also consider the time it takes for the agent to show up in the room in the first place.

This article focuses on agent join latency: the time from your backend requesting an agent to that agent being present and ready in the room. That wait is your user's first impression of your system, so it needs to be short.

How do I know my agent is slow to join?#

The tricky thing about join latency is that there isn't a single user-facing symptom. Instead, watch out for any of these:

  • Callers dialing into your agent hear a lot of ringing. Typically your agent answers the SIP call, so until it joins and connects, the call stays unanswered.
  • Web or app users hear silence. Your agent can't speak or interact with users until it has joined the room. If you dispatch your agent when users join, they wait in silence until it's ready.
  • The avatar screen is blank. The avatar isn't rendered until the agent joins and the avatar participant connects. Until then, the user sees a blank screen.
  • A client-side timeout fires. Some frontends time out when no media is detected, as a way of catching network connection failures. A slow agent join trips that same timeout.
  • Users leave before the agent joins. If your session logs show the user leaving before the agent joined, they may have given up waiting.
  • Authentication errors appear sporadically. The token issued at dispatch time can expire if the agent takes long enough to reach connect(), producing a 401 Unauthorized. It takes an extreme delay to trigger, but we have seen it happen when an agent took more than 60 seconds to join.

How an agent actually joins a room#

When a dispatch is triggered, this is roughly what happens:

Loading diagram…

The LiveKit server to agent worker step is fast, so when a join takes several seconds, the delay is elsewhere in the lifecycle.

Identify and fix the most common causes#

Scaling from zero to many agent workers on LiveKit Cloud#

Every job runs in its own process, and if no prewarmed process is ready, the job waits while one spins up. On LiveKit Cloud, agents on the Build plan scale down to zero once all active sessions end, so the next join has to start from cold, adding a delay. You can either upgrade your plan or set expectations for your users that they may need to wait for the agent to join.

LiveKit Cloud is designed to scale up as your workload grows. If you see capacity scaling up too slowly, the most frequent causes are:

  • Artificial traffic spikes, such as load testing with a large number of calls all arriving at the same instant. Be sure that any load tests follow a realistic pattern.
  • An exceptionally large container image.

Slow or blocking code in your entrypoint#

Anything your entrypoint does before it connects delays the agent join. Follow the advice in Diagnosing Blocked Event Loops in LiveKit Agents to keep blocking calls out of that path.

Virtual avatars#

An avatar typically* adds a second participant to the room. Your agent session sends its audio to an avatar worker, which renders lip-synced video and publishes synchronized audio and video back to the room:

Loading diagram…

This is by design: publishing straight into the room keeps the latency added by lip-sync as small as possible, but it does mean the avatar's own join time sits on the critical path to the first visible moment. wait_for_join() deliberately blocks the agent from speaking until the avatar has joined and published video, so users don't get audio over a black screen.

Provider choice matters a lot here, so it's worth experimenting to find the right balance between capability and join latency. Every avatar plugin emits an AvatarMetrics object through the avatar session's metrics_collected event, allowing you to measure:

MetricDescription
Join latencyAvatar session start to the participant publishing video.
Playback latencyThe agent's first audio frame to playback starting on the avatar.

* Although typical, not every avatar works this way. One notable exception is Spatius, which renders the avatar on the client rather than publishing video into the room.

Warm capacity for self-hosted agents#

If you self-host your agents, warm capacity and scaling are your responsibility.

In production, LiveKit keeps a number of warmed agent processes available. You can override this with num_idle_processes, but it's generally a good idea to accept the default, which sets the value based on the available CPU count. The agent worker always tries to keep this number of processes idle, so as soon as a job takes one, it starts warming a replacement. Running out will cause a delay while a replacement spins up, but raising num_idle_processes isn't free: every idle process consumes CPU and memory, and prewarming too many would exhaust your host.

If your host is running low on CPU or memory, spawning and initializing a process takes longer, and in extreme cases a loaded worker can report itself unavailable and stop accepting jobs. A slow join is sometimes just an under-resourced or over-packed host. Avoid burstable instance types such as AWS t3/t4g, which can stall badly even when CPU usage looks low, and use compute-optimized instances instead.

Autoscaling is yours to get right. Adjust the load_fnc and load_threshold values to match the scaling behavior of your environment. Get these values wrong and a subset of workers can become overloaded, leading to sporadic slow agent joins. If you'd rather not manage warm pools, instance types, and scaling, host your agents on LiveKit Cloud instead.

Clues in logging#

If you are using Python agents and see the following WARNING log, an agent was requested but no prewarmed process was ready to accept it:

1
no warmed process available for job, waiting for one to be created

On its own, this line is not a smoking gun. It might mean:

  • Your self-hosted production agent has genuinely hit the load its hardware supports.
  • The prewarmed process pool has been exhausted because jobs arrived faster than replacements could be warmed.
  • You are running in development mode, where there are no warmed processes at all, so every job logs it.

This line is a signal worth investigating when it appears on a production worker, but be aware that it can be emitted several times for a single job, because the pool retries. Also note that this log won't appear in your agent session logs (viewable in Agent Insights), since this event happens before the session is established. For more on this, see the related article about agent logs.

To measure the join delay yourself, record a timestamp just before your explicit dispatch call, then record a second one in your agent entrypoint immediately after await ctx.connect() returns, which is the point at which your agent is actually in the room. Since these timestaps will be shown in separate logs, be sure to pass an ID through the job metadata so you can correlate the two log lines.

When the agent never joins at all#

An agent that never shows up can be tricky to debug, but the cause is usually one of these:

IssueMitigation
The agent_name doesn't match. If the name you dispatch to doesn't exactly match the name your worker registered with, the job has nowhere to go and sits unrouted until it times out.Confirm an agent with the expected name is registered on the dashboard.
You relied on token dispatch for a room that already exists. Agent dispatch embedded in a participant's access token is only applied when the room is first created. If the room already exists, that configuration is silently ignored and no agent is dispatched.Use unique room names for each user-agent interaction.
Your self-hosted workers have run out of capacity. Every worker is either fully loaded or has reported itself unavailable, so the dispatch has nowhere to land and goes unrouted.Ensure you have sufficient capacity for your self-hosted agents and have correctly configured your autoscaling, as described earlier.
Your network blocks the connection. Traffic between your self-hosted agent and LiveKit Cloud isn't getting through. Most commonly this happens when you update your network without accounting for LiveKit's firewall requirements.Check your network against the LiveKit firewall configuration.

In summary#

Agent join latency is a distinct problem from conversational latency. Recognize what a slow join looks like to your users, confirm it in your logs, and then work through the causes above. If you're struggling to narrow it down, deploying your agents to LiveKit Cloud, even temporarily, can rule out a whole class of self-hosting problems.

Related