Skip to main content

engagive_flutter_sdk 1.0.2 copy "engagive_flutter_sdk: ^1.0.2" to clipboard
engagive_flutter_sdk: ^1.0.2 copied to clipboard

Native in-app support chat SDK for Engagive AppChat visitor messaging.

engagive_flutter_sdk #

Native Flutter SDK for Engagive AppChat visitor messaging. Embed in-app support chat in your Flutter app without a WebView.

Version: 1.0.0 · pub.dev · Changelog

Your Flutter app  →  Engagive SDK (signs identify JWT)  →  Engagive API  →  Agents / AI

This guide is for developers integrating the package from pub.dev.


Table of contents #

  1. What the SDK does
  2. Prerequisites (Engagive portal)
  3. Install from pub.dev
  4. Identify tokens
  5. Common setup (every app)
  6. Use cases
  7. API reference
  8. Message types
  9. Security checklist
  10. Example application setup
  11. Troubleshooting
  12. License

What the SDK does #

Area Capability
UI EngagiveChatScreen, Engagive.openChat, theme from portal Mobile SDK → Flutter
Identity Trusted, anonymous guest, guest→trusted upgrade
Messaging Text, image, video, audio, document, location, interactive, template, sticker
Composer Attach menu, camera/gallery, voice note, captions, location
Thread Replies, reactions, ticks, date separators, markdown, retry, offline banner
Realtime WebSocket messages, status, reactions, AI typing/stream
Session Secure persistence + restore
Push Optional FCM for identified users (Android + iOS)
Recovery Portal recovery rules via EngagiveRecoveryRequirements

Identity is host-driven (what you pass to identify APIs). It is not gated by the website widget’s portal identity_mode.


Prerequisites (Engagive portal) #

Before coding:

  1. Active AppChat channel for your business.
  2. Portal → Mobile SDK → Flutter: enable in-app chat / SDK access.
  3. Copy the widget public key and widget secret key into EngagiveConfig.
  4. Keep the secret out of git. Pass it through environment, remote config, or a build flavor.
  5. Note your Engagive API base URL (e.g. https://api.engagive.io or your brand host).
  6. Add your app’s package / bundle id to the Flutter app identifier allowlist (e.g. com.yourcompany.app).
  7. (Optional push) Configure Firebase in the portal and ship client config in the host app.

Install from pub.dev #

dependencies:
  engagive_flutter_sdk: ^1.0.0
flutter pub get

Requires Flutter 3.44.2 and Dart 3.12.2.

import 'package:engagive_flutter_sdk/engagive_flutter_sdk.dart';

Platform notes:

  • Android / iOS are the primary targets (chat + optional FCM).
  • Add platform permissions as needed for camera, mic, location, notifications (same as any chat app).
  • For push: apply Google Services (Android) and add GoogleService-Info.plist + Push capability (iOS).

Identify tokens #

The SDK signs the identify JWT. The host passes the widget public key and secret on EngagiveConfig, then calls identify with a user id (or starts a guest).

Flow Method What you pass
Trusted Engagive.identifyUser EngagiveUser(id: userId)
Anonymous Engagive.identifyAnonymous Optional profile. The SDK creates or reuses the guest id
Upgrade Engagive.upgradeUser Trusted user id. The SDK links storedAnonymousUserId

The signed token is an HS256 JWT (typ: appchat_sdk_identify, about 5 minutes). identifyToken is optional if you already have one.


Common setup (every app) #

Step 1 — Init once at startup #

final rootNavigatorKey = GlobalKey<NavigatorState>();

await Engagive.init(
  EngagiveConfig(
    publicKey: yourWidgetPublicKey,
    secretKey: yourWidgetSecretKey,
    apiBaseUrl: 'https://api.engagive.io',
    appIdentifier: 'com.yourcompany.app', // must match portal allowlist
    navigatorKey: rootNavigatorKey,       // needed for notification → chat
    restoreSessionOnInit: true,
    connectRealtimeOnIdentify: true,
    enableNotifications: true,
    enablePushNotifications: false,       // set true when FCM is ready
  ),
);

Wire navigatorKey into your MaterialApp / CupertinoApp.

Step 2 — Identify before opening chat #

Call one of the identify APIs (see use cases). Check:

Engagive.isInitialized; // true after init
Engagive.isIdentified;  // true after successful identify / restore

Step 3 — Show chat #

Either push a route or embed a screen (use cases D and E).


Use cases #

Use case A — Trusted login only #

When: Support is only for logged-in users.

Steps

  1. User signs into your app.
  2. Call Engagive.identifyUser with EngagiveUser(id: …). The SDK signs the trusted JWT.
  3. Open chat (openChat or EngagiveChatScreen).
  4. On logout, call Engagive.logout().
Future<void> onHostLogin(AppUser user) async {
  await Engagive.identifyUser(
    EngagiveUser(
      id: user.id,
      name: user.name,
      email: user.email,
      phoneNumber: user.phone,
      countryCode: user.countryCode, // required if phone is set
    ),
  );
}

// Later
await Engagive.openChat(context);

Use case B — Anonymous guest chat #

When: Users can chat before signing in.

Steps

  1. Call Engagive.identifyAnonymous. The SDK creates or reuses a guest id and signs the anonymous JWT.
  2. Open chat.
  3. The same guest id is kept across restarts so history continues.
Future<void> startGuestChat() async {
  await Engagive.identifyAnonymous(
    EngagiveUser(
      name: optionalName,
      email: optionalEmail,
      phoneNumber: optionalPhone,
      countryCode: optionalCountryCode,
    ),
  );

  await Engagive.openChat(context);
}

Helpers:

Engagive.storedAnonymousUserId;
await Engagive.getOrCreateAnonymousUserId();

Use case C — Guest then upgrade after login #

When: Guest chats first; after login you want the same thread under the trusted user.

Steps

  1. Complete Use case B and keep the guest id.
  2. User logs into your app.
  3. Call Engagive.upgradeUser with the trusted user id. The SDK signs an upgrade JWT that links that id to the stored guest id.
  4. Continue using the same chat UI — history merges.
// Before login — guest (Use case B)
await Engagive.identifyAnonymous(const EngagiveUser());

// After your login
await Engagive.upgradeUser(
  EngagiveUser(
    id: user.id,
    name: user.name,
    email: user.email,
  ),
);

Equivalent, if you already have the guest id:

await Engagive.identifyUser(
  EngagiveUser(id: user.id, anonymousUserId: guestId),
);

Use case D — Open chat as a pushed route #

When: A “Contact support” button should push a full-screen chat (back button pops).

ElevatedButton(
  onPressed: () => Engagive.openChat(context),
  child: const Text('Contact support'),
);

// Optional chrome
await Engagive.openChat(
  context,
  showBackButton: true,
  showAppBarMenu: true,
  appBarMenuIconAsset: 'assets/icons/chat-menu.png',
);
Parameter Default Purpose
showBackButton true Shows back; pops the route
showAppBarMenu true Restart-conversation menu
appBarMenuIcon null Custom menu widget
appBarMenuIconAsset null Asset for menu icon
visible inferred Override when host controls visibility / mark-read

Use case E — Embed chat in a tab / panel #

When: Chat is a bottom-nav tab or side panel (host owns navigation).

BottomNavigationBar(
  // …
);

// Tab body
const EngagiveChatScreen(
  showBackButton: false, // host handles back / tab switch
  showAppBarMenu: true,
);

If the chat tab can be covered or backgrounded, pass visible: so mark-read stays correct.

EngagiveChatBubble is deprecated — build your own launcher and call openChat or embed EngagiveChatScreen.


Use case F — Session restore on cold start #

When: Returning users should not re-identify every launch (within session validity).

Steps

  1. Keep restoreSessionOnInit: true (default).
  2. Call Engagive.init on startup.
  3. If Engagive.isIdentified is true, you may open chat directly.
  4. If restore fails (expired / invalid), identify again. The SDK signs a fresh token.
await Engagive.init(config);

if (!Engagive.isIdentified) {
  // Your login / guest bootstrap → identify…
}

Use case G — Logout #

await Engagive.logout();                     // clear Engagive session
await Engagive.logout(clearAnonymous: true); // also wipe persisted guest id

Use clearAnonymous: true when the host account fully signs out and you do not want the next visitor to resume the previous guest thread.


Use case H — Chat history recovery #

Portal website-widget recovery rules (require_email / require_phone) apply to SDK sessions as recovery_mode.

Steps

  1. Optionally prefetch settings before your profile form.
  2. Ensure EngagiveUser includes the fields recovery requires.
  3. Identify as usual.
  4. Handle recovery errors (e.g. prompt trusted login).
final settings = await Engagive.prefetchSettings(
  externalUserId: user.id,
);
final recovery = settings.recoveryRequirements;

if (recovery.canAttemptRecovery &&
    !recovery.credentialsCompleteForRecovery(
      email: user.email,
      phoneNumber: user.phone,
    )) {
  // Ask user for missing email / phone before identify
}

try {
  await Engagive.identifyUser(
    EngagiveUser(id: user.id, email: user.email, /* … */),
  );
} on EngagiveException catch (e) {
  if (e.errorCode == EngagiveErrorCode.userIdRequiredForRecovery) {
    // Prompt: sign in with app account to continue
  }
  rethrow;
}

Also available after identify: Engagive.settings?.recoveryRequirements.


Use case I — Visitor push (FCM) #

When: Identified users should get agent/AI replies while the app is backgrounded or killed.

Steps

  1. Configure Firebase in Engagive portal for the business.
  2. Ship google-services.json (Android) / GoogleService-Info.plist (iOS) + APNs key in Firebase.
  3. Enable push in EngagiveConfig.
  4. Identify a trusted or upgrade user (guests are not push-eligible).
  5. Provide navigatorKey so taps can open chat.
  6. QA with Engagive.pushDiagnostics.
await Engagive.init(
  EngagiveConfig(
    publicKey: yourWidgetPublicKey,
    secretKey: yourWidgetSecretKey,
    apiBaseUrl: yourApiBaseUrl,
    appIdentifier: 'com.yourcompany.app',
    navigatorKey: rootNavigatorKey,
    enablePushNotifications: true,
    firebaseProjectId: optionalFirebaseProjectId,
    // pushIntegration: MyCustomPushIntegration(), // optional
  ),
);

await Engagive.identifyUser(
  EngagiveUser(id: user.id),
);

debugPrint('${Engagive.pushDiagnostics}');

Use case J — Unread badge #

ValueListenableBuilder<int>(
  valueListenable: Engagive.unreadCount,
  builder: (context, count, _) {
    return Badge(
      isLabelVisible: count > 0,
      label: Text('$count'),
      child: IconButton(
        icon: const Icon(Icons.chat),
        onPressed: () => Engagive.openChat(context),
      ),
    );
  },
);

Realtime streams (optional host wiring):

Engagive.realtimeEvents;
Engagive.realtimeConnectionStates;
Engagive.realtimeConnectionState;

API reference #

EngagiveConfig #

Field Required Default Notes
publicKey yes — Widget public key
secretKey for SDK signing empty Widget secret used to sign the identify JWT
apiBaseUrl yes — Origin, no trailing slash
wsBaseUrl no from API URL WebSocket override
appIdentifier recommended — Portal allowlist
restoreSessionOnInit no true Secure session restore
connectRealtimeOnIdentify no true Connect /ws after identify
enableNotifications no true Local notifications from WS
enablePushNotifications no true FCM path for identified users
firebaseProjectId no — Sent on token register
navigatorKey no — Notification → open chat
pushIntegration no built-in FCM Custom EngagivePushIntegration

EngagiveUser #

Field Notes
id Trusted logged-in user id
anonymousUserId Host-owned guest id
name / email Optional profile
phoneNumber Optional; if set, countryCode is required
countryCode E.164 prefix, e.g. +92

Identity methods #

Method Typical EngagiveUser
Engagive.identifyUser id and/or anonymousUserId
Engagive.identifyAnonymous anonymousUserId
Engagive.upgradeUser id + anonymousUserId
Engagive.logout optional clearAnonymous
Engagive.getOrCreateAnonymousUserId persists guest id
Engagive.prefetchSettings recovery / theme before identify

State getters #

Engagive.isInitialized;
Engagive.isIdentified;
Engagive.config;
Engagive.session;
Engagive.user;
Engagive.settings;
Engagive.storedAnonymousUserId;
Engagive.unreadCount;
Engagive.pushDiagnostics;
Engagive.pushIntegration;

UI #

  • Engagive.openChat(context, …)
  • EngagiveChatScreen(…)
  • EngagiveChatController (advanced)

Push / media helpers #

  • EngagivePushIntegration, EngagivePushPayload, EngagivePushDiagnostics
  • EngagiveMediaPicker, EngagiveMediaPolicy, EngagiveMediaUrl
  • EngagiveTheme, EngagiveRecoveryRequirements, EngagiveSession

Message types #

Receive: text, image, video, audio, document, location, interactive, template, sticker, contacts

Send: text, image, video, audio, document, location, interactive reply, template quick-reply

Default media limits: 10 MB (most types), 25 MB (video).


Security checklist #

  • ❌ Pass publicKey and secretKey on EngagiveConfig
  • ❌ Do not commit the widget secret (use environment, remote config, or a build flavor)
  • ❌ appIdentifier matches portal allowlist
  • ❌ No secrets in git, CI logs, or pub package source

Example application setup #

The package ships a full host demo under example/. It mirrors a real product: login, guest, upgrade, and an embedded chat tab.

1. Get credentials #

From Engagive portal → Mobile SDK / widget:

  • Widget public key
  • Widget secret (passed to EngagiveConfig; the SDK signs the identify JWT)
  • API base URL
  • App id allowlisted (example default: com.engagivestudio.demo)

2. Fetch and run #

# After: flutter pub get in the package (or clone from GitHub / pub cache)
cd example
flutter pub get

flutter run \
  --dart-define=ENGAGIVE_PUBLIC_KEY=YOUR_PUBLIC_KEY \
  --dart-define=ENGAGIVE_WIDGET_SECRET_KEY=YOUR_SECRET_KEY \
  --dart-define=ENGAGIVE_API_BASE_URL=https://api.engagivestudio.com \
  --dart-define=ENGAGIVE_APP_IDENTIFIER=com.engagivestudio.demo
Dart-define Required Default
ENGAGIVE_PUBLIC_KEY yes empty
ENGAGIVE_WIDGET_SECRET_KEY yes empty
ENGAGIVE_API_BASE_URL no https://api.engagivestudio.com
ENGAGIVE_APP_IDENTIFIER no com.engagivestudio.demo
ENGAGIVE_ENABLE_PUSH no false
ENGAGIVE_FIREBASE_PROJECT_ID no empty

3. Try each flow in the example #

Flow What to do in the UI
Trusted Enter a user id (e.g. studio_demo_customer_1) → Continue → open Chat tab
Guest Skip — continue as guest → Chat
Upgrade Start as guest → chat → Sign in with a user id → history merges
Embedded UI Chat tab uses EngagiveChatScreen(showBackButton: false)

4. Debug APK (optional) #

cd example
flutter build apk --debug \
  --dart-define=ENGAGIVE_PUBLIC_KEY=YOUR_PUBLIC_KEY \
  --dart-define=ENGAGIVE_WIDGET_SECRET_KEY=YOUR_SECRET_KEY \
  --dart-define=ENGAGIVE_APP_IDENTIFIER=com.engagivestudio.demo

APK: example/build/app/outputs/flutter-apk/app-debug.apk

5. Map example → production #

Example Production
Public key + widget secret on EngagiveConfig Same EngagiveConfig fields in your app
Login screen user id field Your auth system’s stable user id
Guest continue Engagive.identifyAnonymous
Studio API URL / app id Your brand API URL + production package name

More detail: example/README.md.


Troubleshooting #

Symptom Check
Identify fails / 401 Wrong secret? appIdentifier allowlisted?
“Public key required” in example Pass ENGAGIVE_PUBLIC_KEY
Chat empty / not loading Engagive.isIdentified? Network / API base URL?
Guest history lost after reinstall New guest id — use recovery email/phone or sign in (upgrade)
Push never arrives Trusted/upgrade only; Firebase configs; enablePushNotifications; pushDiagnostics
Mark-read wrong in tabs Pass visible: on EngagiveChatScreen when tab is hidden
WS drops with auth error Call identify again so the SDK signs a fresh token
} on EngagiveException catch (e) {
  debugPrint('${e.errorCode} ${e.message}');
}

License #

MIT — see LICENSE.