Header Logo

Building a Realtime Hotel Front-Desk AI Avatar in Flutter

Building a Realtime Hotel Front-Desk AI Avatar in Flutter

Build a realtime hotel front-desk AI avatar in Flutter with LiveKit, Protoface, low-latency media, auth, and sync tips.

Introduction


Adding a “face” to a voice agent is not just a UI flourish. In a front-desk flow, the avatar carries turn-taking, attention cues, and a bit of social presence that makes short, transactional conversations feel much more natural. The hard part is keeping the video face synchronized with live audio, while also dealing with the usual production concerns: session lifecycle, low-latency delivery, auth, and safe browser embedding.


In this post, I’ll show the architecture you need for a realtime hotel front-desk avatar in Flutter: how the media pipeline works, how to wire it to a voice agent, what to watch out for in mobile/web rendering, and how Protoface fits into the stack when you want a synchronized talking face without building the avatar system yourself.


What “realtime avatar” actually means in this setup


A realtime avatar is not a prerecorded video clip stitched onto TTS output. It is a streaming system that accepts a conversational turn, generates speech, and renders a lip-synced video face with enough latency budget left for the user to perceive it as interactive. In practice, the pipeline usually looks like this:


  1. User speaks into the app.

  2. Audio is sent to a voice agent or speech pipeline.

  3. The agent produces text or structured intent, then synthesized speech.

  4. The avatar layer renders a video face synchronized to that speech.

  5. The client displays the face in a low-latency player alongside the audio stream.


The important engineering constraint is that the audio and face must share the same conversational clock. If the avatar lags behind the audio by even a few hundred milliseconds, the illusion breaks quickly. That means buffering strategy, transport choice, and turn boundaries matter more than “pretty video” features.


Flutter client architecture for a front desk assistant


For a hotel front desk, I’d keep the Flutter app thin. Let it handle UI state, local audio permissions, and the video container, while pushing conversational logic to a backend or agent service. That gives you a cleaner separation:


  • Flutter UI: check-in flow, room lookup, booking summaries, fallback buttons.

  • Voice agent: intent handling, tool calls, policy, knowledge retrieval.

  • Avatar layer: realtime talking face tied to the agent’s spoken output.


If you’re embedding the avatar in Flutter on the web, you can often use an iframe-based surface. If you’re building a native app, you’ll typically consume a video stream or web view component depending on how the avatar product is exposed. The key design choice is to treat the avatar as a media endpoint, not as business logic. Don’t put hotel workflow rules into the rendering layer.


Managing turns, latency, and user perception


In front-desk interactions, latency tolerance is lower than in long-form support chats. Guests expect a brief pause while the desk “looks up” a reservation, but not long dead air. A good target is to keep visible response time under a second for acknowledgements, then stream the substantive answer as soon as it is ready.


A practical pattern is:


  1. Immediately show a listening/processing state when the user stops talking.

  2. Emit a short acknowledgment from the agent if the backend work is nontrivial.

  3. Only start the avatar speech when you have a complete turn boundary.

  4. Avoid interrupting the avatar mid-utterance unless you support barge-in cleanly.


For a hotel front desk, barge-in matters. Users will interrupt when they realize they gave the wrong confirmation number or want to ask about parking. That means your voice agent should support turn cancellation, and your client should be able to stop rendering the current speaking segment without showing visual desync.


Flutter implementation notes


In Flutter, the main pitfalls are usually not the avatar itself, but audio/video lifecycle and platform differences. A few things that come up in production:


  • App lifecycle: pause streams cleanly when the app backgrounds, and reconnect deterministically when it resumes.

  • Audio focus: on mobile, make sure the agent can hold or release audio focus predictably so system sounds and call-style interruptions behave correctly.

  • Layout stability: reserve the avatar’s aspect ratio up front so your UI does not jump as the stream initializes.

  • Network resilience: treat reconnects as normal, not exceptional. Realtime media sessions will occasionally renegotiate.


Here is a simple shape for a Flutter-side state model, regardless of the avatar provider:


enum AgentState { idle, connecting, listening, thinking, speaking, error }

}
enum AgentState { idle, connecting, listening, thinking, speaking, error }

}
enum AgentState { idle, connecting, listening, thinking, speaking, error }

}


That may look basic, but it keeps the video UI honest. The avatar should reflect the actual conversational phase, not just play a loop because the stream is open.


Backend control plane: session creation and auth


For anything beyond a toy demo, do not expose API credentials in the browser or mobile client. Keep session creation on your backend, then hand the client only the minimum token or session data it needs to join.


The pattern is straightforward: your server creates or configures the avatar/session, then the Flutter app consumes the returned session info. The exact fields depend on the API, but the flow is the important part.


import os

print(session)
import os

print(session)
import os

print(session)


Use the REST API for control plane tasks: create avatars, manage sessions, inspect usage, and automate provisioning. Keep runtime media traffic separate from that control path. That separation makes retries, audits, and key rotation much easier.


How the LiveKit agent path fits in


If your hotel assistant already runs as a LiveKit voice agent, the simplest path is to add a synced face at the agent layer rather than rewriting the agent itself. The livekit-plugins-protoface plugin is designed for exactly that: it drops a talking avatar into the agent so the voice and face stay aligned.


# illustrative only; exact setup depends on your agent stack

cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
# illustrative only; exact setup depends on your agent stack

cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
# illustrative only; exact setup depends on your agent stack

cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))


This is useful when you already have tool calling, transcription, and turn management handled in a LiveKit agent. You keep the agent logic where it belongs and add the visual layer as a plugin. If you want the implementation details or example code, the plugin repo is the right place to start: https://github.com/protoface-ai/protoface-plugin-pipecat. The same general integration model also applies if you are using Pipecat; the Pipecat guide documents the service wrapper and service configuration patterns: https://docs.pipecat.ai/api-reference/server/services/video/protoface.


Customer-managed embeds for browser-based front desks


If your front desk experience is web-first, an iframe embed can be the least invasive way to ship a realtime avatar. It avoids exposing API keys in the browser, and it keeps the embedding contract simple for product teams. The trade-off is that you give up some direct control over transport and rendering internals, so you should be deliberate about sizing, allowed origins, and per-embed behavior.


The operational features that matter here are the ones that reduce abuse and accidental exposure:


  • Parent-origin allowlisting, so only your site can host the embed.

  • Per-embed voice and custom instructions, so each property or brand can have its own front-desk tone.

  • Per-IP and duration rate limits, which are important for public-facing widgets.


For teams that need the simplest possible integration, this is often the fastest way to get a production-safe avatar onto a website without building a bespoke backend session flow.


Production gotchas for hotel workflows


A hotel front desk is not a generic chatbot. The assistant usually touches reservation systems, identity checks, and policy-sensitive information. A few practical guardrails help:


  • Do not let the avatar imply certainty it does not have. If the PMS lookup is pending, say so clearly.

  • Keep tool responses short. The avatar is most useful when it speaks concise confirmations, not verbose system logs.

  • Separate public and authenticated flows. Pre-check-in questions can be handled in a public session; booking changes should be gated.

  • Instrument the whole turn. Measure time-to-first-audio, turn duration, reconnection count, and fallback rates.


Also remember that the visual layer can amplify mistakes. If the agent says “I’ve updated your reservation” before the backend write actually succeeds, the mismatch is more noticeable when a human face delivers the line. Make the agent and UI wait on the same source of truth.


Where Protoface fits in


Protoface is the piece you reach for when you want the avatar layer to be a solved problem instead of a custom media project. In this hotel front-desk setup, that usually means one of two things: add a synchronized face to an existing LiveKit voice agent, or create a controlled browser embed for a web-based concierge. The control plane sits behind the REST API and the Python SDK, while the developer dashboard is useful for inspecting sessions, keys, and usage during development. If you want to validate the flow before wiring it into Flutter, the public docs are the right starting point: https://docs.protoface.com.


Conclusion


The core idea is simple: keep the voice agent, media transport, and avatar rendering loosely coupled, but synchronized at the turn level. In Flutter, that means building a stable UI shell around a realtime media session, not trying to simulate realtime media in widgets. For a hotel front desk, the winning implementation is the one that stays responsive, handles interruptions cleanly, and fails gracefully when the network or backend is slow.


If you are building this today, start with the docs, decide whether your agent belongs behind LiveKit or a browser embed, and prototype the smallest possible conversational loop first: greeting, one lookup, one response. Once that is stable, the rest is mostly engineering discipline.

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.