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 LivecallerApp widget — show it anywhere (bottom sheet, full screen, side panel).
  • Public event bus (LivecallerEvents) for conversationWasStarted, 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

  • conversationMessageReceived is filtered to operator-originated messages — the visitor's own outgoing messages do not re-emit back to you.
  • conversationWasStarted fires 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.