Building a Voice-and-Video Real Estate Assistant in Nuxt with LiveKit

Build a Nuxt real-estate assistant with LiveKit WebRTC, secure token minting, agent routing, and synchronized Protoface avatars.
Introduction
If you are building a real-estate assistant, the hard part is not “getting a chatbot to answer questions.” The hard part is making the experience feel immediate, trustworthy, and operationally safe while it handles the stuff buyers and renters actually ask: availability, neighborhood context, scheduling, financing basics, and handoff to a human when the conversation crosses a boundary.
A voice-only agent can work, but in real estate the lack of a face is a disadvantage. People are already making a high-consideration decision; they want something that feels present, not just responsive. In this post, we’ll build the architecture for a Nuxt-based web experience that streams audio and video over WebRTC via LiveKit, while keeping the AI side modular enough to swap providers and agent logic later. We’ll also show where Protoface fits when you want the agent to have a synchronized talking face without inventing your own lip-sync pipeline.
What the system needs to do
For this use case, the core interaction loop is straightforward:
The browser captures microphone input and renders a live avatar/video surface.
Your voice agent transcribes the user, reasons over property-specific context, and streams a response.
The assistant speaks back over WebRTC with low latency, and the video face stays synchronized with the generated speech.
The app can escalate to a human, schedule a showing, or capture a lead without leaking secrets to the browser.
Nuxt is a good fit because you can keep the frontend reactive, isolate privileged server logic in server routes, and let the client join a LiveKit room only after your backend has minted a short-lived token. That pattern matters: the browser should never hold your API keys or long-lived agent credentials.
Nuxt, LiveKit, and the basic data flow
At a high level, you want three layers:
Frontend: Nuxt page that requests a room token, connects to LiveKit, and renders remote audio/video tracks.
Backend: server routes that authenticate the user, create or join a room, and return a scoped token.
Agent process: the voice agent that joins the room, listens to the user, generates responses, and publishes audio/video back into the same session.
This separation gives you the usual WebRTC benefits: media streams stay peer-to-peer or SFU-routed instead of being proxied through your app server, and your backend only handles control-plane concerns. It also makes the application easier to reason about when you add retries, room lifecycle management, or agent failover.
Nuxt client: join a room and render the assistant
In Nuxt, the client side mostly needs to do three things: fetch a token, connect to the room, and subscribe to tracks. The exact UI is up to you, but the underlying shape looks like this:
That snippet is intentionally minimal. In a real app you’ll also want to handle disconnects, device selection, reconnect state, and cleanup on route changes. If you plan to support mobile browsers, test audio autoplay behavior early; browser policies around user gestures are still a common source of “it works locally, but not on Safari” bugs.
Backend token minting and room security
Do not generate LiveKit access tokens in the browser. Keep that logic server-side and scope tokens to the minimum required room and identity. In Nuxt, a server route is usually enough:
The token should be short-lived, and room naming should be predictable enough for your backend to manage, but not guessable by other users. If the assistant is joining on behalf of the system, issue a separate identity for the agent side and revoke or rotate it if the session is abandoned.
Agent behavior: keep the conversation useful, not just fluent
In real estate, the model prompt matters less than the surrounding product logic. A useful assistant should:
Answer from a constrained property dataset when the question is factual.
Ask clarifying questions when the request is ambiguous, especially around budget, move-in date, and location.
Escalate to a human or create a follow-up task when it is asked for legal, financial, or policy-sensitive advice.
Keep a short-term memory of the current conversation, but avoid inventing property details it has not been given.
That usually means your agent stack needs retrieval or tool calls, not just a prompt. For example, if the user asks “Is the unit pet-friendly and what’s the monthly total with parking?”, the agent should query your listing database rather than guess. The better your tool boundaries, the more trustworthy the agent feels.
Where Protoface fits: giving the agent a synchronized face
Once the voice loop is working, the next step is often the visible avatar. That is the piece docs.protoface.com covers well: you create or manage avatars and realtime sessions, then attach the avatar output to your existing voice agent. For LiveKit-based systems, the relevant integration is the livekit-plugins-protoface plugin, which drops a Protoface avatar into the agent so the face tracks the spoken audio in sync.
The important architectural point is that you do not need to contort your Nuxt app around the avatar service. Your browser still connects to LiveKit; the agent still owns the conversational logic; the avatar layer just subscribes to the agent’s speech and produces a synchronized talking video face.
If you are building a pipeline in Python, this is often the cleanest place to put the integration: close to the agent runtime, not in the web client. That keeps the browser free of avatar credentials and lets you swap the frontend independently of the avatar provider.
Alternative: create sessions or avatars from your backend
When you need to provision avatars dynamically — for example, one avatar per brokerage brand, or separate sessions for each active lead — the REST API and Python SDK are the right surfaces. You can create and manage sessions programmatically from trusted server code, then hand the resulting identifiers to your agent process.
If you want to inspect the raw control-plane behavior, the same idea works over HTTP. Keep the API key on the server and send it as a bearer token:
That pattern is especially useful when you need deterministic provisioning, auditability, or per-tenant isolation. It also keeps the browser completely out of your avatar control plane, which is the right default for anything customer-facing.
Operational details that matter in production
Realtime avatar systems fail in predictable ways, so it helps to design for them up front:
Latency budget: speech-to-text, LLM reasoning, and text-to-speech all add up. Keep your prompt and tool path short.
Media sync: the avatar should follow the agent’s actual audio timing, not a guessed animation loop.
Fallbacks: if the avatar session fails, the assistant should still be able to continue voice-only.
Rate limiting: protect session creation and room join endpoints, especially on public landing pages.
Privacy: do not log raw microphone audio unless you have a clear reason and consent flow.
One subtle but important issue is conversational state drift. If your agent and avatar session get out of sync, users notice immediately. The fix is usually to make the agent the source of truth for turn boundaries and to keep avatar/session lifecycle tied to that same state machine.
Conclusion
The practical path for a voice-and-video real estate assistant is to keep each layer narrow: Nuxt for the UI, LiveKit for realtime transport, and a separate agent process for reasoning and speech. That gives you low-latency media, a clean security boundary, and enough flexibility to add retrieval, scheduling, or human handoff later.
When you want the assistant to feel like a coherent conversational presence instead of a voice floating in a browser tab, add the avatar layer at the agent boundary, not in the frontend. For implementation details, integration examples, and the current API shape, start with the docs and the relevant quickstart repository, then adapt the pattern to your own listings and workflow.
