Header Logo

What Is a Realtime Avatar Receptionist? How Streaming Voice and Lip Sync Work in the Browser

What Is a Realtime Avatar Receptionist? How Streaming Voice and Lip Sync Work in the Browser

Explains realtime avatar receptionists, streaming voice, browser lip sync, WebRTC transport, and common sync/latency pitfalls.

Introduction


A realtime avatar receptionist is, in practical terms, a browser-deliverable face attached to a streaming voice agent. The agent hears audio, produces text and/or audio responses, and the avatar renders a synchronized talking head with plausible mouth motion while the conversation is still in progress. If you’re building a support bot, sales assistant, game NPC, or a web concierge, the hard part is not “showing a video.” The hard part is keeping speech, lip motion, turn-taking, and network latency aligned well enough that the interaction feels live.


In this post, I’ll explain the core pieces: how streaming voice flows through a browser, how lip sync is typically driven, what the realtime transport looks like, and where the common failure modes are. I’ll also show where Protoface fits if you want to add an avatar layer to an existing voice agent without building the entire media stack yourself.


What “realtime” actually means in an avatar receptionist


People often use “realtime” loosely. For avatar systems, it usually means three separate streams are coordinated:


  • Input: live microphone audio or text from the user.

  • Reasoning / speech generation: an LLM, agent framework, or scripted backend decides what to say.

  • Output: audio playback plus a video track that animates the face in sync with that audio.


The avatar doesn’t need to “understand” the conversation in the human sense. It needs timing data. At a minimum, it needs to know when speech starts and ends, and ideally it gets phoneme- or viseme-level timing so the mouth shapes match the audio. If the video lags the audio by too much, users notice immediately. If the mouth movements start before the voice, it feels broken. If the system waits for the full response before animating, it feels like a static video with a delayed mouth.


In browser-based products, this is usually implemented with streaming media primitives such as WebRTC or chunked audio playback, plus an animation layer that updates on a frame budget. The browser is a good place for the final rendering, but it is not where you want to synthesize everything from scratch unless you are intentionally building a media stack.


How streaming voice and lip sync fit together


The simplest mental model is:


  1. The agent generates speech incrementally.

  2. An audio stream is sent to the client as soon as it is available.

  3. The avatar receives timing cues for the speech stream.

  4. The browser renders the face with mouth shapes aligned to those cues.


There are a few common ways to drive the mouth:


  • Audio-driven: infer mouth openness from short-time audio energy or spectral features. This is lightweight but less exact.

  • Phoneme/viseme-driven: map speech units to mouth shapes. More accurate, but it depends on better alignment information from the speech system.

  • Hybrid: use coarse speech timing plus audio-driven smoothing to hide jitter and packetization artifacts.


For browser delivery, the practical constraint is that your video renderer must stay ahead of the playback clock without drifting. You need buffering, but not too much buffering. A little headroom absorbs network jitter; too much increases perceived latency.


That trade-off is the main reason avatar products tend to expose a higher-level session abstraction instead of asking developers to stitch together raw media tracks. The session can own the clock, the buffers, and the state transitions between “listening,” “thinking,” “speaking,” and “idle.”


Browser transport: why WebRTC is common and where it helps


For true conversational latency, WebRTC is usually the right transport for the browser-facing media path. It gives you:


  • low-latency audio and video delivery,

  • adaptive jitter buffering,

  • codec negotiation across browsers,

  • and a natural fit for interactive sessions rather than static playback.


That said, the avatar stack is still not “just WebRTC.” You typically need a control plane as well:


  • create a session,

  • authorize the client,

  • configure voice and instructions,

  • start media delivery,

  • and tear everything down cleanly when the session ends.


If you skip the control plane and wire media endpoints directly into the browser, you tend to accumulate security problems quickly. API keys should stay server-side. Browser clients should receive ephemeral, scoped credentials or be isolated behind an embed that never exposes the upstream secret.


Common engineering gotchas


A few things routinely go wrong in realtime avatar systems:


  • Clock drift: the audio and animation clocks slowly diverge. You need periodic resynchronization.

  • Over-buffering: large buffers reduce glitches but make turn-taking feel sluggish.

  • Under-buffering: small buffers improve latency but produce stutter under jittery networks.

  • Turn overlap: the agent starts talking before the user has finished, or the avatar keeps “speaking” after the agent has already stopped generating audio.

  • Visual discontinuities: switching expressions or talking states too aggressively makes the face look robotic.


From a product perspective, the most important metric is usually not raw FPS or peak bitrate. It is perceived responsiveness: how long after the user stops speaking does the avatar start responding, and how stable does the speech-to-mouth sync feel during the answer?


If you are using an LLM-based agent, also remember that text streaming and audio streaming are related but not identical. A system can stream partial text fast and still sound bad if the corresponding audio arrives in chunks that are too coarse or are not aligned to the animation state. In other words, “token streaming” is not a substitute for media synchronization.


Short example: adding an avatar face to a voice agent


If your voice agent already runs in LiveKit, the least invasive integration is usually to add an avatar plugin on the media side rather than reworking the agent logic. The goal is to keep your agent as the source of truth for conversation state while the avatar layer consumes the speech stream and renders the face.


A minimal Python setup looks like this in spirit:


from livekit.agents import Agent, JobContext

await agent.start(ctx.room)
from livekit.agents import Agent, JobContext

await agent.start(ctx.room)
from livekit.agents import Agent, JobContext

await agent.start(ctx.room)


The important point is architectural, not syntactic: the avatar should be attached where your agent already produces speech, so the audio and the mouth animation share the same conversation lifecycle. For the exact integration details, the plugin repository and docs are the right reference points; don’t guess at session parameters from memory.


If you want to inspect the integration surface directly, the LiveKit plugin examples are in the relevant GitHub repo, and the broader usage docs are at docs.protoface.com.


Where Protoface fits in the stack


The place this gets interesting is when you want the avatar layer without building a custom media backend. That is where the REST API and SDK are useful: create avatars and realtime sessions from your server, keep API keys out of the browser, and bind the avatar session to your application’s agent lifecycle.


A typical server-side flow is: create a session, hand the client an ephemeral session reference, then start streaming audio/video over the approved transport. The exact request shape depends on the endpoint, but the pattern is standard bearer-token auth over HTTPS.


curl -X POST https://api.protoface.com/v1/sessions \
}'
curl -X POST https://api.protoface.com/v1/sessions \
}'
curl -X POST https://api.protoface.com/v1/sessions \
}'


That control-plane model matters because it lets you keep the browser simple. The client gets a session to connect to; the backend retains the secret; rate limits, origin allowlists, and session duration limits can be enforced without trusting the frontend. For developers shipping customer-facing embeds, that separation is usually the difference between something you can safely deploy and something that becomes an auth liability.


If you prefer programmatic access, the Python SDK is the same idea from code rather than raw HTTP:


from protoface import Client

)
from protoface import Client

)
from protoface import Client

)


Again, treat field names as illustrative unless you are copying directly from the docs. The key takeaway is that the API is for session lifecycle and avatar management, while the media experience stays realtime in the browser.


Practical guidance on when to use an iframe embed


If you do not want to maintain any backend integration at all, a customer-managed iframe embed is the most operationally straightforward option. It keeps the secret off the page entirely, which is the main security win. The parent page can be allowlisted by origin, and the embed can enforce per-IP and duration rate limits. That makes it viable for marketing sites, lightweight support flows, and internal demos where you want an avatar quickly but do not want to wire up your own session backend.


The trade-off is control. An iframe is easy to ship, but it constrains how deeply you can integrate the avatar into your product’s own state machine. If your app needs to coordinate the avatar with a custom room model, an existing voice agent, or internal telemetry, the API or SDK route is usually a better fit.


Conclusion


A realtime avatar receptionist is mostly a synchronization problem: get voice, animation, and browser playback clocks aligned closely enough that the face feels attached to the speech. Once you understand that, the architecture gets simpler. You need a transport for low-latency media, a control plane for session and auth management, and an animation layer that can consume timing information without drifting.


If you are implementing this yourself, start by deciding where your source of truth lives: voice agent, media server, or browser. Then choose the integration surface that matches it. For docs, examples, and the relevant SDKs and plugins, see docs.protoface.com and the linked quickstarts in the Protoface GitHub organization.

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.