Header Logo

Building a Realtime Banking Avatar in SvelteKit: FastAPI, LiveKit, and Low-Latency Lip-Sync

Building a Realtime Banking Avatar in SvelteKit: FastAPI, LiveKit, and Low-Latency Lip-Sync

Build a realtime banking avatar in SvelteKit with FastAPI orchestration, LiveKit delivery, and low-latency lip-sync.

Introduction


Adding a realtime avatar to a banking workflow is mostly an exercise in latency management. The hard part is not rendering a face; it is keeping audio, video, and conversational state aligned closely enough that the user perceives one coherent agent instead of a stack of separate systems. If your voice agent takes 300 ms to answer, your lip-sync pipeline adds another 250 ms, and your browser delivery path jitters, the experience starts to feel laggy or uncanny very quickly.


This post shows how to build a realtime banking avatar in SvelteKit, with a FastAPI backend handling session orchestration and a WebRTC-based delivery path for low-latency playback. By the end, you should understand the architecture, the latency budget, the browser integration points, and where a developer-facing avatar platform fits without turning your app into a brittle media stack.


Architecture: separate control plane from media plane


For this kind of application, it helps to split the system into two concerns:


  • Control plane: authentication, session creation, policy, avatar configuration, and agent metadata.

  • Media plane: the live audio/video stream, lip-sync timing, and browser playback.


In practice, SvelteKit owns the UI and user session, FastAPI acts as the backend that creates or authorizes realtime sessions, and the browser joins the live media channel. That separation is useful because the browser should never contain long-lived API credentials, and the media connection should be established only after the backend has decided the session is allowed.


For a banking use case, that boundary matters. You often need to gate the avatar behind authentication, attach an account context, and record a session identifier for auditability. You also want to be able to swap the voice model, avatar identity, or instructions without redeploying the frontend.


Backend orchestration with FastAPI


A minimal backend usually does three things:


  1. Validates the user or customer session.

  2. Creates a realtime avatar session with the correct persona and policy.

  3. Returns short-lived connection details to the frontend.


If your avatar vendor exposes a REST API, keep the API key server-side and never ship it to the browser. A typical request shape looks like this:


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 \
}'


Exact field names and response shapes depend on the API surface in use, but the pattern is stable: your backend requests a session, then hands the frontend only what it needs to connect.


Frontend integration in SvelteKit


On the SvelteKit side, the goal is to keep the UI responsive while the media session initializes asynchronously. A common pattern is:


  • Render a normal banking support UI first.

  • Call your FastAPI endpoint to request a session.

  • Join the live media session when the response arrives.

  • Show connection state explicitly so users can distinguish “loading” from “connected.”


A small Svelte component might look like this:


<script lang="ts">
<script lang="ts">
<script lang="ts">


Two practical notes:


  • Do not block the UI waiting for the avatar. Let the page stay usable even if media takes a second to negotiate.

  • Keep the join logic idempotent. Users will click twice when they think nothing happened.


Low-latency lip-sync: what actually matters


Realistic lip-sync is less about perfect phoneme-to-viseme mapping and more about timing discipline. If audio is the reference signal, the video face has to track that signal with minimal delay and low jitter. The human eye is forgiving of small errors, but very sensitive to mismatched speech onset, delayed mouth closure, and frame drops during fast speech.


There are a few latency sources to manage:


  • Inference latency: how long the model takes to produce audio or animation commands.

  • Transport latency: the time spent moving media from server to browser.

  • Playback latency: buffering, decoding, and rendering in the client.


The usual mistake is optimizing only one layer. For example, a fast avatar model is wasted if the browser is buffering behind an overly conservative jitter buffer. Likewise, a low-latency transport path does not help if the server batches too much text before generating speech.


For conversational banking, a good target is “predictable and consistent” rather than “perfectly cinematic.” Users care more that the assistant starts speaking promptly, stays in sync, and does not visibly glitch when the system is under load.


Where the agent logic belongs


Voice agents are easiest to reason about when the agent brain and the avatar rendering path are loosely coupled. The agent should produce text or speech events; the avatar layer should consume those events and stay synchronized. That separation lets you swap model providers, adjust speech generation, or add compliance checks without rewriting the media layer.


If your stack already uses a LiveKit-based voice agent, this is exactly the sort of integration point where a face can be added without rebuilding the agent. The avatar becomes another synchronized surface on top of the existing conversation flow.


from livekit.plugins.protoface import ProtofaceVideoService<p></p>
from livekit.plugins.protoface import ProtofaceVideoService<p></p>
from livekit.plugins.protoface import ProtofaceVideoService<p></p>


That kind of integration is useful when the agent already exists and you want to add a face with minimal surface area change. If you are assembling a new agent stack, check the plugin documentation and examples first rather than guessing the constructor shape.


Protoface in practice: session control and managed embeds


Protoface is most useful here as the control and delivery layer for the avatar itself. For a custom SvelteKit + FastAPI build, the REST API is the main integration point: your backend creates sessions, stores metadata, and enforces policy before the browser ever connects. If you prefer to stay in Python, the SDK gives you programmatic access to avatar and session management. If your voice agent is already on LiveKit, the plugin path is the shortest way to attach a synchronized talking face.


One operational detail worth calling out: for customer-facing web embeds, you can use a managed iframe approach so no backend logic or API key is exposed in the browser. That is the right choice when you want a tightly scoped, customer-managed avatar surface with origin restrictions, per-embed instructions, and server-side rate limits. For a banking assistant, that can be a good fit for marketing pages or authenticated support portals where you want the avatar isolated from the rest of your app code.


If you want to inspect the API shapes, session flows, or quickstart examples, the docs are the right place to start: https://docs.protoface.com.


Operational gotchas


There are a few failure modes that show up quickly in production:


  • Credential leakage: keep API keys on the server, always.

  • Session churn: do not recreate avatar sessions on every component rerender.

  • Audio/video drift: treat lip-sync as a timing problem, not a styling problem.

  • Overlong responses: banking users prefer concise replies; long monologues are hard to follow and harder to keep in sync.

  • Reconnect behavior: decide whether a dropped media session resumes or starts fresh, and make that explicit in the UI.


Logging is also important. Record session IDs, user IDs, and connection state transitions so you can debug whether a bad experience came from auth, transport, or the avatar pipeline itself. In realtime systems, “it felt slow” is not actionable unless you can attribute the delay.


Conclusion


A realtime banking avatar is mostly a systems integration problem: authenticate in the backend, create a short-lived session, join a low-latency media path in the browser, and keep the voice agent and face synchronized enough that the interaction feels natural. SvelteKit gives you the UI, FastAPI gives you a clean control plane, and a managed avatar layer keeps you from having to build and operate the lip-sync stack yourself.


If you want to implement this pattern, start with the docs, wire up a backend session endpoint, and then test the media path under real network conditions rather than only on localhost. The quickest route to a working prototype is usually to begin with one of the published quickstarts and adapt the session orchestration to your own app. From there, tighten the latency budget, add audit logging, and validate the UX with real users in a realistic network environment.

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.