Flutter
Flutter bridge over the native Android and iOS chat SDKs; the native chat screen is presented, so there is no Dart-side UI to compose. Flutter 3.3+, iOS 14+, Android minSdk 24 with JDK 17 and mavenCentral() in your Gradle repositories.
Install and quick startlink
flutter pub add newinstance_chat:^0.5.0Your backend mints a customer token (see Session tokens (REST API)) and hands it to the app:
final chat = NewinstanceChat(NewinstanceChatConfig(customerToken: tokenFromYourBackend));
await chat.ready;
await chat.initialize();
await chat.openChat();NewinstanceChatConfig(apiKey?, customerToken?, baseUrl?, transport?, initialMessage?, theme?) takes exactly one of customerToken or apiKey (keyId:secret); anything else makes ready reject with E_CONFIG. The baseUrl override is honoured by debug builds only. ChatUser(customerName required, customerEmail?, customerId?). ready resolves once native configuration completes.
Auth modeslink
Customer token mode (recommended) is shown above: the token is the identity and setUser fields are not sent. When a fresh token is due, swap it in without destroying the SDK:
await chat.setUserToken(freshTokenFromYourBackend);Key mode (trusted internal apps only). This ships your secret inside the app, so never use it in an app distributed to the public.
final chat = NewinstanceChat(NewinstanceChatConfig(apiKey: 'sk_live_abc123:YOUR_SECRET_KEY'));
await chat.ready;
await chat.setUser(const ChatUser(customerName: 'Ada', customerEmail: 'ada@example.com', customerId: 'usr_123'));
await chat.initialize();setUserToken throws E_CONFIG in key mode. See Authentication and identity.
Local themelink
NewinstanceChatConfig(
customerToken: tokenFromYourBackend,
theme: ChatThemeOverride(mode: 'dark', sentBubble: '#16A34A'),
);Every ChatThemeOverride field is optional and merged token by token, ranked below the merchant's dashboard theme and above the built-in palette. Unset tokens are omitted from the platform-channel payload entirely. Full rules in Theming.
API and eventslink
Methods: setUser, setUserToken, initialize, openChat, closeChat, sendMessage, retryMessage, attachFile(AttachmentInput(uri, name, mimeType)), destroy. Handoff, typing and attachment removal are driven by the native screen, not the Dart surface.
Streams: onMessageReceived, onMessageSent, onAgentTypingChanged, onConnectionStateChanged (NcConnectionState: idle, connecting, connected, disconnected, offline), onUnreadCountChanged, onError. ChatMessage carries seq, sentAt, senderName and totalMessages.
The error streamlink
onError is the channel for "why is my chat not working". Nothing on it reaches the chat interface, and it never carries the API key, the identity token, or customer data.
chat.onError.listen((NewinstanceChatError e) {
if (e.code == NcErrorCode.invalidIdentityToken) {
refreshChatToken();
} else if (!e.recoverable) {
reportToYourMonitoring(e.code, e.message);
}
});NewinstanceChatError carries code (from NcErrorCode, the vocabulary shared with every other chat SDK), the broad type (NcErrorType: network, validation, auth, system), a developer-facing message, and recoverable. code is null only when talking to a native SDK older than the release that introduced coded errors. The full code list is in Authentication and identity -> Diagnosing problems.
Gotchaslink
AttachmentInput.uriis afile://URI on iOS andcontent://orfile://on Android.themeand coded errors require 0.3.0 of this package and of the underlying native SDKs. The two exclusive auth modes,customerTokenin the config and the reworkedsetUserTokenrequire 0.4.0.- Steps from your connected MCP servers (forms and secure pages) require 0.5.0 of this package and of the underlying native SDKs; see MCP servers.
- Multiple
NewinstanceChatinstances reconfigure one native singleton; the last config wins. - After
destroy(), construct a new instance to chat again.