ringg_flutter 0.1.2
ringg_flutter: ^0.1.2 copied to clipboard
Ringg AI widget for Flutter — drop-in widget and headless controller for voice/text AI agents.
ringg_flutter #
Embeddable chat + voice-call widget for Ringg AI agents —
the Flutter implementation. Drop RinggWidget over your app for text chat,
Meet-style voice calls, interactive components (forms, calendars, quick
replies, Block Kit) and a post-call feedback screen — or drive the headless
core yourself without the bundled UI.
Install #
dependencies:
ringg_flutter: ^0.1.2
Then flutter pub get. Requires Dart ≥ 3.6 · Flutter ≥ 3.27.
Platform setup (required for voice) #
Voice calls need microphone + audio permissions.
iOS — ios/Runner/Info.plist:
<key>NSMicrophoneUsageDescription</key>
<string>Voice calls use the microphone.</string>
<key>UIBackgroundModes</key>
<array><string>audio</string></array>
Android — android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
Integrate in 3 steps #
Create a transport, build a controller with your agent config, then mount the
widget. Hold the transport + controller in a State so you can dispose them.
1 · Get your credentials #
From the Ringg dashboard you need: your agent id, a widget API key
(xApiKey) or a bearer authorization token, and the environment URLs
(backend + LiveKit) for your account.
2 · Wire up a controller + widget #
import 'package:flutter/material.dart';
import 'package:ringg_flutter/ringg_flutter.dart';
class RinggSupport extends StatefulWidget {
const RinggSupport({super.key});
@override
State<RinggSupport> createState() => _RinggSupportState();
}
class _RinggSupportState extends State<RinggSupport> {
late final LiveKitTransport _livekit;
late final RinggWidgetController _controller;
// Environment URLs for your account (from the Ringg dashboard).
static const _urls = <EnvironmentMode, EnvironmentUrls>{
EnvironmentMode.prod: EnvironmentUrls(
backendUrl: 'https://<your-backend-host>/ca/api/v0',
livekitUrl: 'wss://<your-livekit-host>',
),
};
@override
void initState() {
super.initState();
_livekit = createLiveKitTransport();
_controller = RinggWidgetController(
const RinggWidgetConfig(
agentId: '<your-agent-id>',
xApiKey: '<your-widget-api-key>',
mode: EnvironmentMode.prod, // selects the URL set above
title: 'Support',
description: 'How can we help?',
defaultTab: MediaType.text, // or MediaType.voice
),
ControllerPorts(
transport: _livekit.transport,
urlResolver: const StaticUrlResolver(_urls),
),
);
}
@override
void dispose() {
_controller.destroy();
_livekit.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => RinggWidget(
controller: _controller,
transport: _livekit, // powers the voice-call audio visualizer
);
}
3 · Mount it over your app #
RinggWidget places its own floating trigger + panel, so give it the full
screen on top of your content:
Stack(
children: const [
YourApp(),
RinggSupport(),
],
)
Tap the trigger → the chat/voice panel opens. That's the whole integration.
Native platforms & the
Originheader. Browsers attach anOriginheader automatically; native HTTP does not. If your Ringg backend allow-lists widget keys by domain, the webcall request will fail without it. Pass anhttpClient(frompackage:http) that stamps the origin your key accepts:ControllerPorts( transport: _livekit.transport, urlResolver: const StaticUrlResolver(_urls), httpClient: _originClient('https://your-allowed-origin'), ); // where _originClient wraps http.Client and sets request.headers['Origin']. // A ready-made version ships in the example (example/lib/origin_client.dart).
Configuration #
RinggWidgetConfig — only agentId is required; everything else is optional:
| Field | Type | Purpose |
|---|---|---|
agentId |
String |
your Ringg agent (required) |
xApiKey |
String? |
widget API key |
authorization |
String? |
bearer token (alternative to xApiKey) |
mode |
EnvironmentMode? |
dev / stage / prod — picks the URL set |
title / description |
String? |
panel header text |
defaultTab |
MediaType? |
open in text or voice |
hideTabSelector |
bool? |
hide the text/voice switch |
defaultExpanded |
bool? |
open the panel on load |
bypassStartScreen |
bool? |
jump straight into a call |
variables |
Map<String, Object>? |
values for {{placeholders}} in agent prompts |
logoUrl / theme / widgetPosition / legalDisclaimer / buttons |
… | branding, placement & styling |
Headless use (no UI) #
Skip RinggWidget and drive the core directly — every piece of state is a
Store<T> with snapshot + subscribe:
final unsubscribe = controller.messages.subscribe(
(snap) => debugPrint('${snap.messages.length} messages'),
);
await controller.startCall(MediaType.text);
await controller.sendMessage('Hello!');
// later:
unsubscribe();
controller.destroy();
Example app #
A full, runnable harness — real backend + LiveKit (credentials via
--dart-define), with a live config panel to try themes, tabs and interactive
components — ships in the Example tab (the example/ directory), with its
own README.md covering how to run it.
Platform support #
Android · iOS · macOS · Windows · Linux. Web is not supported.
Known issue — iOS 26.x simulators have no call audio #
On iOS 26.x simulator runtimes the audio engine has neither a working input (mic) nor output (playout) device — calls connect and transcripts stream, but you will not hear the agent or be able to unmute. This is an Apple simulator defect + upstream LiveKit limitation, not fixable app-side: client-sdk-swift#795, #849, Apple forums 738346, 803364. The widget degrades gracefully (listen-only attempt, no error). Test voice on a real device, an Android emulator, or macOS.