Header Logo

How to Debug WebRTC Session Drops in a Realtime AI Avatar Customer Support Bot

How to Debug WebRTC Session Drops in a Realtime AI Avatar Customer Support Bot

Debug WebRTC session drops in AI avatar bots with logs, ICE/TURN checks, agent latency tracing, and session state inspection.

Introduction


When a realtime avatar session drops, the failure mode is usually not “the model stopped talking.” It is almost always a transport or session-lifecycle problem: the browser lost its WebRTC connection, the signaling path stalled, the media track was renegotiated incorrectly, the room was torn down, or your bot stopped sending frames/audio in time and the peer considered the session dead.


If you are building a customer-support bot with a talking face, you need a reliable way to separate media problems from app problems. By the end of this post, you should be able to diagnose where the session is breaking, reproduce the issue with logs and network traces, and decide whether the fix belongs in your WebRTC layer, your agent loop, or your avatar session orchestration.


Start with the right mental model


A “WebRTC session drop” is usually the visible symptom of one of four underlying classes of failure:


  1. Signaling failure: SDP offer/answer or ICE candidate exchange never completes, or completes too slowly.

  2. ICE connectivity failure: peers never find a working candidate pair, or the selected pair becomes unusable after a network change.

  3. Media starvation: the session stays connected, but your bot stops producing audio or video, so the remote side times out or appears frozen.

  4. Application lifecycle failure: the avatar/session is ended, disconnected, or garbage-collected by your own code, a webhook handler, or an infra timeout.


In a realtime AI avatar flow, these failure modes are easy to confuse because the “bot stopped responding” symptom can be triggered by any layer. The first debugging rule is to ask: did the peer connection drop, or did the agent stop making progress while the connection remained up?


Instrument the connection before you chase the model


You should always collect three timelines for the same incident:


  • WebRTC state transitions from the browser or client: connection state, ICE connection state, signaling state, and track mute/unmute events.

  • Agent logs: when the voice agent received audio, produced text, emitted TTS, or updated avatar state.

  • Session lifecycle events: creation, room join, token issuance, avatar binding, and explicit teardown.


For the client side, the most useful signals are the browser’s native peer connection states. You want to log transitions, not just the final state. Example:


pc.onconnectionstatechange = () => {

};
pc.onconnectionstatechange = () => {

};
pc.onconnectionstatechange = () => {

};


What you are looking for is the sequence, not just the terminal state. For example:


  • connecting → connected → disconnected often points to network instability or a transient relay problem.

  • connecting → failed usually means ICE never found a viable candidate pair.

  • connected with a silent or frozen avatar usually means media generation or track delivery failed higher up the stack.


On the server side, log the session ID or room ID at every step. If you cannot correlate the browser console with your agent logs and your session records, you are debugging blind.


Differentiate WebRTC transport issues from bot runtime issues


In support-bot systems, “dropped session” often gets reported when the avatar face stops moving or the bot appears to ignore the user. That does not always mean WebRTC failed. A connected peer can still exhibit a broken user experience if the bot is stalled on one of these common paths:


  • LLM latency spike: the agent waits too long for a response, so audio output dries up.

  • TTS queue backpressure: text is generated, but speech synthesis lags and the video face has no synchronized audio to animate against.

  • Audio source starvation: no inbound microphone frames reach the agent, so the conversation appears stuck.

  • Event loop blockage: synchronous work in the bot process delays media handling enough to trigger timeouts.


A practical rule: if the peer connection remains connected but the avatar freezes, inspect the agent pipeline first. If the peer connection goes to failed or disconnected, focus on ICE, NAT traversal, TURN usage, and network churn.


Reproduce the drop deterministically


Randomly “it dropped once in production” incidents are hard to fix unless you can reproduce them. The easiest way to do that is to reduce the system to a minimal session and then vary one thing at a time.


Start with a known-good quickstart and confirm that the same browser, same network, same agent code, and same avatar can sustain a session for several minutes. The quickstarts in the public repo are useful for this sort of controlled repro, especially when you want to compare a healthy baseline against your app-specific integration.


Then test the usual failure injectors:


  1. Network transitions: switch Wi-Fi networks, enable a VPN, or move between a strong and weak signal.

  2. Tab lifecycle: background the tab, suspend the laptop, or navigate away and back.

  3. Load: open multiple sessions concurrently and see whether a single bot process is saturating CPU or outbound bitrate.

  4. Latency: add artificial delay in your agent code before it emits audio or video.


When a failure appears only under load, it is often a capacity issue rather than a correctness issue. Watch for CPU starvation, event loop lag, and a rising backlog in the media pipeline. When a failure appears only after a network change, suspect ICE restarts or an implementation that does not handle reconnection cleanly.


Check candidate gathering, TURN reachability, and timeouts


Most real-world WebRTC problems are NAT traversal problems in disguise. Browsers can usually connect directly in ideal conditions, but enterprise networks, mobile carriers, and restrictive firewalls often force traffic through TURN. If your session works on a home network and fails on corporate Wi-Fi, that is a clue, not a mystery.


Useful checks:


  • ICE gathering completeness: make sure the browser actually collected host, srflx, and relay candidates when expected.

  • TURN availability: verify the relay path is reachable and credentials are valid for the lifetime of the session.

  • Timeout values: overly aggressive startup or reconnect timeouts can kill sessions that would have recovered a second later.

  • Region mismatch: if your agent, avatar, and media relay are far apart geographically, setup time and jitter get worse.


For a quick browser-side sanity check, inspect the selected candidate pair after the connection establishes. If you always end up on relay traffic in production, that is normal on constrained networks; if you never get past host candidates on a network that requires TURN, then your relaying path is probably misconfigured.


Also pay attention to what happens after recovery. A session that reconnects at the transport layer may still lose the media track binding. In that case the room is technically alive, but the avatar face and audio stream are no longer synchronized.


Use the API to inspect session state, not just create sessions


One of the fastest ways to debug drops is to treat the session object as first-class operational data. If your app creates avatars or realtime sessions programmatically, inspect their lifecycle state from your backend instead of relying only on frontend events.


For example, a simple authenticated request against the REST API can confirm whether a session exists, whether it was torn down, and what metadata is attached. Exact fields depend on the endpoint, but the pattern looks like this:


curl -H "Authorization: Bearer sk_live_..." \
https://api.protoface.com/v1/sessions/<session_id>
curl -H "Authorization: Bearer sk_live_..." \
https://api.protoface.com/v1/sessions/<session_id>
curl -H "Authorization: Bearer sk_live_..." \
https://api.protoface.com/v1/sessions/<session_id>


If you are creating sessions from Python, keep the response object around and log the identifiers you will need during incident response. The exact SDK methods are documented in the docs, but the operational principle is simple: persist the session ID, avatar ID, and any room/token identifiers in your app logs so you can correlate them later.


from protoface import ProtofaceClient

print("session_id:", session.id)
from protoface import ProtofaceClient

print("session_id:", session.id)
from protoface import ProtofaceClient

print("session_id:", session.id)


That may look trivial, but in practice it prevents a lot of guesswork. If the session disappeared server-side before the client noticed, you can stop blaming ICE. If the session is still active but the client disconnected, the problem sits on the transport side or in the browser.


How Protoface fits into this debugging workflow


Protoface is useful here because it gives you a clean place to separate avatar/session management from your own voice-agent logic. In particular, the LiveKit Agents plugin and the developer-facing APIs let you bind an avatar to an agent while keeping session identifiers and lifecycle events visible enough to debug. The plugin itself is documented in the public repo and package metadata, and the REST API plus dashboard make it easier to inspect active sessions, avatars, and usage when a customer reports a drop.


If you are using the LiveKit plugin path, instrument the agent before and after avatar attachment. That lets you answer two questions quickly: did the agent continue processing audio, and did the avatar session remain bound to the same conversation? If one side kept working while the other stopped, the fix is usually in your integration glue, not in the model or the browser.


For implementation details, the docs are the right source of truth: docs.protoface.com. When you need a known-good integration to compare against, the quickstart repository is also handy: github.com/protoface-ai.


Practical debugging checklist


When a session drops, work through this order:


  1. Confirm whether the peer connection failed or only the avatar stopped moving.

  2. Log WebRTC state transitions, not just the final failure state.

  3. Correlate client logs with server-side session IDs and timestamps.

  4. Check agent latency, TTS backlog, and event-loop health.

  5. Verify ICE candidate gathering and TURN reachability under the affected network.

  6. Reproduce under controlled conditions before changing multiple variables.


If you do that consistently, most “random” session drops become explainable within one or two iterations.


Conclusion


Debugging a realtime AI avatar session is mostly about disciplined attribution. WebRTC transport, media delivery, and bot runtime are separate failure domains, and you need logs that let you distinguish them. Once you can see connection state, candidate selection, agent latency, and session lifecycle in one timeline, the root cause usually becomes obvious.


If you are building on Protoface, keep the session IDs and logs, verify the transport layer first, and use the dashboard plus API to inspect the session when something goes wrong. For implementation specifics and up-to-date examples, start with the docs. Then reproduce the issue in a minimal quickstart and fix the layer that is actually failing.

Add a face to your AI.

No credit card needed.

Add a face to your AI.

No credit card needed.

Add a face to your AI.

No credit card needed.