engagive_flutter_sdk 1.0.2
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 #
- What the SDK does
- Prerequisites (Engagive portal)
- Install from pub.dev
- Identify tokens
- Common setup (every app)
- Use cases
- API reference
- Message types
- Security checklist
- Example application setup
- Troubleshooting
- 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:
- Active AppChat channel for your business.
- Portal → Mobile SDK → Flutter: enable in-app chat / SDK access.
- Copy the widget public key and widget secret key into
EngagiveConfig. - Keep the secret out of git. Pass it through environment, remote config, or a build flavor.
- Note your Engagive API base URL (e.g.
https://api.engagive.ioor your brand host). - Add your app’s package / bundle id to the Flutter app identifier allowlist (e.g.
com.yourcompany.app). - (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
- User signs into your app.
- Call
Engagive.identifyUserwithEngagiveUser(id: …). The SDK signs the trusted JWT. - Open chat (
openChatorEngagiveChatScreen). - 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
- Call
Engagive.identifyAnonymous. The SDK creates or reuses a guest id and signs the anonymous JWT. - Open chat.
- 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
- Complete Use case B and keep the guest id.
- User logs into your app.
- Call
Engagive.upgradeUserwith the trusted user id. The SDK signs an upgrade JWT that links that id to the stored guest id. - 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
- Keep
restoreSessionOnInit: true(default). - Call
Engagive.initon startup. - If
Engagive.isIdentifiedis true, you may open chat directly. - 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
- Optionally prefetch settings before your profile form.
- Ensure
EngagiveUserincludes the fields recovery requires. - Identify as usual.
- 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
- Configure Firebase in Engagive portal for the business.
- Ship
google-services.json(Android) /GoogleService-Info.plist(iOS) + APNs key in Firebase. - Enable push in
EngagiveConfig. - Identify a trusted or upgrade user (guests are not push-eligible).
- Provide
navigatorKeyso taps can open chat. - 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,EngagivePushDiagnosticsEngagiveMediaPicker,EngagiveMediaPolicy,EngagiveMediaUrlEngagiveTheme,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
publicKeyandsecretKeyonEngagiveConfig - ❌ Do not commit the widget secret (use environment, remote config, or a build flavor)
- ❌
appIdentifiermatches 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.