Adding a Voice and Video Concierge Avatar to a Flutter Travel App

Learn how to integrate a voice and video concierge avatar into a Flutter travel app with realtime sessions, LiveKit, and Protoface.
Introduction
Adding a voice-and-video concierge to a Flutter travel app is mostly an integration problem, not a research project. The core pieces are straightforward: your app needs a realtime audio channel, a video surface that can render a talking face, and a way to coordinate session state so the avatar stays synchronized with the agent’s responses.
By the end of this post, you should understand the architecture for a mobile concierge avatar, the trade-offs between embedding the avatar in-app versus hosting it externally, and how to wire a Flutter client into a realtime voice stack without making the UX feel bolted on. I’ll also show where Protoface fits if you want the avatar layer without building the lip-sync and session plumbing yourself.
What “voice and video concierge” actually means in a travel app
In this context, the concierge is not a static video clip. It is a realtime agent that listens to the user, produces speech, and renders a synchronized face that appears to be speaking that speech. Under the hood, the system usually has three moving parts:
Audio capture and playback for the user’s microphone and the agent’s synthesized voice.
Realtime session orchestration so the agent can stream partial responses and keep latency low.
Video synthesis that lip-syncs the avatar to the generated audio and exposes it as a playable stream.
For a travel app, this is useful in places where text chat is too slow or too impersonal: booking changes, baggage questions, itinerary review, airport transfer coordination, or concierge-style recommendations. The avatar gives the agent a face, but the real value is reducing friction in a conversation that would otherwise span multiple screens and backend calls.
Flutter integration: keep the UI simple, keep the media stack explicit
On the Flutter side, the main design decision is whether you want the avatar to feel like a first-class screen or a small component inside an existing flow. In practice, most teams get better results by separating concerns:
Flutter owns the conversation UI, local state, navigation, and error handling.
The realtime voice agent owns dialog, tool calls, and speech generation.
The avatar surface renders whatever the agent is saying, in sync with the audio path.
This matters because media sessions are stateful. If the network blips, or the user backgrounds the app, you need to know whether you are reconnecting the voice channel, pausing the avatar, or tearing down the session entirely. That logic should be explicit, not implicit in a widget tree.
Recommended app flow
A practical flow for a travel concierge looks like this:
User opens the “Ask concierge” screen.
Flutter requests a short-lived session token or session metadata from your backend.
Your backend creates or resumes a realtime avatar session through Protoface’s REST API or SDK.
The client connects to the voice agent transport you use for audio.
The avatar stream is rendered alongside the call controls, itinerary context, and suggested actions.
The important part is that the client never needs long-lived secrets. Keep API keys server-side, and issue only scoped session artifacts to the mobile app.
Media and latency trade-offs
If you are used to traditional mobile video playback, realtime avatar sessions have some differences worth calling out:
Latency matters more than fidelity. A slightly lower-quality face that responds immediately is usually better than a polished one that lags behind the conversation.
Audio is the source of truth. The avatar’s lip sync should follow the synthesized speech stream, not the raw text response, or you will see timing drift.
Reconnect behavior is product behavior. When the session drops, users need a clear state transition: reconnecting, resumed, or ended.
Mobile backgrounding is non-trivial. iOS and Android will suspend media-heavy flows if you do not manage foreground state carefully.
For travel use cases, I would also avoid over-animating the avatar. A clean, readable face with stable eye contact and predictable speaking behavior usually feels more trustworthy than elaborate motion.
Flutter implementation pattern
In Flutter, keep the avatar view isolated behind a small controller class so the rest of the app does not care how the media is delivered. A typical shape looks like this:
The exact avatar rendering widget depends on how you deliver the video stream into Flutter. The design principle is the same either way: treat the avatar as a media endpoint with lifecycle, not as a decorative image.
Using a realtime voice agent with a synchronized avatar
If your concierge is already built as a LiveKit voice agent, the cleanest path is to attach an avatar directly to that agent. That keeps the speech pipeline and the video face synchronized, which is the part that usually takes the most effort to get right.
Protoface provides a LiveKit Agents plugin for this use case: the plugin repository includes the integration surface and examples for dropping an avatar into an agent flow. The important behavior is simple: your agent generates speech as usual, and the plugin handles the synchronized talking face.
A representative shape in Python looks like this:
That snippet is intentionally abstract because the exact constructor fields and wiring depend on your agent stack. The main point is that you do not manually juggle lip-sync timing in your app code. The agent emits speech; the avatar surfaces it as video.
Server-side session management with the REST API
If you prefer to orchestrate sessions yourself, the REST API is the right primitive. This is useful when your travel backend already owns user identity, trip context, and rate limits, and you want the avatar session to inherit that same control plane.
From a backend service, you can create or manage avatars and realtime sessions over HTTPS with an API key in the Authorization header. A minimal request looks like this:
Use the exact endpoints and request fields from the documentation. The important operational rule is to keep the API key on the server, not in Flutter. Your mobile app should only receive ephemeral session data that is safe to expose to the client.
When an iframe embed is the better choice
For some travel products, especially content-heavy or marketing-adjacent flows, the simplest implementation is an embedded concierge widget rather than a full native media integration. An iframe embed can be useful when you want a fast launch, no backend work in the browser, and a hard boundary around the avatar session. Protoface’s customer-managed iframe approach is designed for that model: the browser never sees an API key, and you can scope the embed with origin allowlists and rate limits.
That said, for a native Flutter app, the iframe route is usually a stopgap rather than the final architecture. It can be appropriate for a web view inside Flutter or for internal tools, but if the concierge is part of a core booking experience, you generally want tighter control over lifecycle, analytics, and navigation than an iframe gives you.
Operational details that matter in production
Once the integration works in a demo, the production work is mostly about failure modes:
Session expiry: make sure the app can renew or recreate a session without losing the conversation context.
Network variability: mobile users move between Wi-Fi and cellular; handle reconnects gracefully.
Audio permissions: request microphone access only when needed, and explain why in user-facing copy.
Rate limiting: a concierge screen can become expensive if users repeatedly open and abandon sessions.
Telemetry: log session start, disconnects, and time-to-first-audio so you can see where latency is coming from.
Also decide early whether the avatar is allowed to speak while the user is interacting with booking controls. In travel flows, overlapping speech can be a UX bug, not a feature.
Where Protoface fits
If you already have a voice agent and only need the talking face, Protoface is the layer that keeps you from building avatar timing, session management, and video plumbing from scratch. The integration point depends on your stack, but for a LiveKit-based concierge the plugin is the most direct path; if you are managing sessions from your own backend, the REST API and Python SDK are the natural primitives. The docs at docs.protoface.com are the place to verify exact request shapes, session fields, and current integration details.
Conclusion
A voice-and-video concierge in Flutter is mostly a clean systems integration: isolate the media session, keep secrets server-side, make reconnection behavior explicit, and let the avatar follow the speech pipeline rather than the other way around. If you keep the app architecture disciplined, the user experience feels like a responsive travel expert instead of a stitched-together demo.
For implementation details, start with the docs, pick the integration surface that matches your stack, and then build a thin Flutter wrapper around session lifecycle and media rendering. The quickest next step is to review the quickstarts and adapt one to your concierge flow from there.
