Add a talking avatar to your Flutter app
What the plugin does
On Android the plugin runs the same engines as the bitHuman Android SDK, so the avatar renders on the phone. Your app's speech audio goes in, and a lip-synced picture comes out as a Flutter Texture in your widget tree.
It runs on Android phones (arm64), and on iPhone, iPad and Mac with Apple silicon after one bootstrap step that fetches the engines.
What you need
For Android:
- Dart 3.11.5 or newer, with the Android toolchain (JDK 17 and the Android SDK).
- A physical Android phone, arm64, on Android 10 (API 29) or newer. Emulators cannot load the engines.
- A bitHuman API secret.
Install
The plugin is published as a tag in the public homebrew-bithuman repository on GitLab. Pin it in pubspec.yaml, run flutter pub get, and set the plugin's Android floor in android/app/build.gradle.kts. The current tag is on the docs' downloads page.
dependencies:
bithuman:
git:
url: https://gitlab.com/bithuman/sdk/homebrew-bithuman.git
path: packages/flutter-plugin
ref: flutter-plugin-v2.6.40android {
defaultConfig {
minSdk = 29 // the plugin's floor, whichever model you use
ndk { abiFilters += "arm64-v8a" } // the engines ship arm64-v8a only
}
packaging { jniLibs { useLegacyPackaging = true } } // required
}Show the avatar and play your speech
Load the avatar with your API secret, put its texture in your layout, and play your speech through it chunk by chunk as 24 kHz mono PCM16: you hear it, and the lips follow. A shipped app fetches the secret from your backend.
import 'package:bithuman/bithuman.dart';
final avatar = await BithumanAvatar.load(
'A23WJF0199', // on Android, the agent code
engine: 'expression2', // required: 'expression2' or 'essence2'
apiSecret: secret,
);
Texture(textureId: avatar.textureId); // the avatar in your layout
await avatar.audioStart(enableMic: false); // the speaker; required on iOS and macOS
await avatar.playSpeakerPCM(chunk); // Uint8List, 24 kHz mono PCM16: heard, and the lips follow
await avatar.notifyTurnEnd(); // after the reply's last chunk
await avatar.interrupt(); // cut the current reply
await avatar.dispose(); // release the engineA voice conversation
Instead of your own audio, BithumanRealtimeSession connects the avatar to bitHuman's realtime relay with your API secret. The avatar_chat example app is a complete voice conversation with idle motion and interruption: it asks for your API secret once, downloads the avatar and answers when you speak.
git clone https://gitlab.com/bithuman/sdk/bithuman-examples.git
cd bithuman-examples/app/avatar_chat
flutter pub get
flutter run --release --dart-define=AGENT_CODE=A23WJF0199Before you ship
The engines check your API secret when an avatar loads, so every copy of an app you distribute carries it. Treat that secret as exposed.
- Fetch the secret from your backend when the app starts. Never compile it into a build you ship.
- Give each app its own secret, so you can rotate one without touching the others.
- Call
BithumanAvatar.clearCredentials()when an account signs out, so the engines forget the secret.
Choose a model
Pass the model as engine: on every load, as in the snippet above. Essence 2 renders a photoreal person from one portrait. Expression 2 renders any character, from people to animals and cartoons, from one portrait. On Apple devices, Expression 2 needs iOS 18 or macOS 15, and Essence 2 needs iOS 26 or macOS 26.
What it costs
From 12 October 2026, API and SDK use requires the Creator plan or higher.
Usage bills per second while the avatar runs, talking or idle; the relay's voice session is billed in credits with the avatar included.
Every step, with troubleshooting, is in the docs. Flutter guide in the docs
