Livecaller Flutter SDK
Embed the Livecaller live-chat widget in your Flutter app with real-time messaging and a persistent event bus so host screens can react to operator messages even when the chat UI is closed.
Features
- Drop-in
LivecallerAppwidget — show it anywhere (bottom sheet, full screen, side panel). - Public event bus (
LivecallerEvents) forconversationWasStarted,conversationMessageReceived,conversationWasClosed,conversationAuthFailed. - Persistent background listener that keeps emitting events on any host screen — survives the chat UI being dismissed and survives cold restarts.
- Reply-to-message, attachments, audio, and locale-aware relative timestamps.
Install
dependencies:
livecaller_flutter_sdk: ^1.1.5
flutter pub get
1. Boot the background listener in main
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:livecaller_flutter_sdk/livecaller_flutter_sdk.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Resumes from the persisted session if one exists. Safe to call before
// the user has ever logged in — it just no-ops.
await LivecallerApp.startBackgroundEvents();
runApp(const ProviderScope(child: MyApp()));
}
Once the user opens chat the first time, the SDK persists everything it
needs (token, conversation id, connection config). On every subsequent cold
start startBackgroundEvents() with no args is enough — events keep flowing
on every host screen.
Note: wrap your app in a
ProviderScope— the SDK uses Riverpod internally.
2. Authenticate the visitor
Call once after the visitor signs in to your system, passing a JWT issued by your backend:
await LivecallerApp.userLogin(context, yourBackendIssuedJwt);
And on logout, clear both the chat session and the persisted background session:
await LivecallerApp.userLogout(context);
await LivecallerApp.stopBackgroundEvents();
3. Show the chat widget
Mount LivecallerApp wherever you want the chat to live — full-screen
route, bottom sheet, modal, etc.
LivecallerApp(
widgetId: 'YOUR_WIDGET_ID', // from the Livecaller dashboard
language: 'en',
)
A common pattern is a draggable bottom sheet — see example/main.dart.
4. Subscribe to events from any screen
final sub = LivecallerEvents.instance.on(
LivecallerEventType.conversationMessageReceived,
(message) {
// message is the raw Map<String, dynamic> from the server.
debugPrint('Incoming: ${message['content']}');
},
);
// In dispose():
sub.cancel();
Event reference
| Event | Fires when… | Payload keys you'll typically use |
|---|---|---|
conversationWasStarted |
A conversation becomes active | id, plus the full conversation object |
conversationMessageReceived |
An operator sends a message | content, sender, created_at, attachments |
conversationWasClosed |
The conversation is closed by either party | id |
conversationAuthFailed |
The persisted token can no longer authorize Pusher | conversationId |
Notes
conversationMessageReceivedis filtered to operator-originated messages — the visitor's own outgoing messages do not re-emit back to you.conversationWasStartedfires once per conversation id per process lifetime. Re-opening the chat against an existing conversation does not re-fire it.- A short dedupe window (~3 s) prevents double-emits when the chat UI and the background listener both observe the same Pusher channel.
5. Handle conversationAuthFailed
If the visitor's JWT expires while the chat UI is closed, the background
listener will fail Pusher auth (HTTP 403) and emit
conversationAuthFailed. The SDK has already dropped that conversation
from its persisted session — the host just needs to refresh the token
(call userLogin again with a fresh JWT) or prompt the user to sign in.
LivecallerEvents.instance.on(
LivecallerEventType.conversationAuthFailed,
(data) async {
final freshJwt = await myBackend.refreshLivecallerJwt();
if (!mounted) return;
await LivecallerApp.userLogin(context, freshJwt);
},
);
Lifecycle cheat-sheet
| Moment | Call |
|---|---|
App boot (main) |
LivecallerApp.startBackgroundEvents() |
| After your own user login | LivecallerApp.userLogin(context, jwt) |
| Open chat | mount LivecallerApp(widgetId: ...) |
| Subscribe on a screen | LivecallerEvents.instance.on(type, listener) |
| Screen disposed | sub.cancel() |
| App-wide logout | userLogout + stopBackgroundEvents() |
Full example
A complete reference integration — background listener boot, login/logout, chat bottom sheet, and a separate host screen that reacts to events — lives in example/main.dart.
License
See LICENSE.