React Native
React Native bridge over the same native chat SDKs, with the native chat screen presented from JS. RN 0.74+ (0.85+ recommended); runs on both the new TurboModule architecture and the old bridge. iOS 15.1+.
Install and quick startlink
npm install react-native-newinstance-chat@^0.5.0
cd ios && pod installAndroid needs mavenCentral() in settings.gradle.kts.
Your backend mints a customer token (see Session tokens (REST API)) and hands it to the app:
import { NewinstanceChat } from 'react-native-newinstance-chat';
const chat = new NewinstanceChat({ customerToken: tokenFromYourBackend });
await chat.ready;
await chat.initialize();
chat.openChat();Config: { apiKey?, customerToken?, baseUrl?, transport?: 'sse' | 'ws', initialMessage?, theme? } with exactly one of customerToken or apiKey (keyId:secret), otherwise ready rejects with E_CONFIG; user: { customerName required, customerEmail?, customerId? }. ready resolves once native configuration completes. initialize() and attachFile() return promises; setUser, setUserToken, openChat, closeChat, sendMessage, retryMessage, removeAttachment, clearAttachments and destroy return void.
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:
chat.setUserToken(freshTokenFromYourBackend);Key mode (trusted internal apps only). This ships your secret inside the app bundle, so never use it in an app distributed to the public.
const chat = new NewinstanceChat({ apiKey: 'sk_live_abc123:YOUR_SECRET_KEY' });
await chat.ready;
chat.setUser({ customerName: 'Ada', customerEmail: 'ada@example.com', customerId: 'usr_123' });
await chat.initialize();setUserToken throws synchronously with code E_CONFIG in key mode. See Authentication and identity.
Local themelink
const chat = new NewinstanceChat({
customerToken: tokenFromYourBackend,
theme: { 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. Full rules in Theming.
Eventslink
addListener(event, handler) returns an unsubscribe function; call it on unmount. Events: messageReceived, messageSent, agentTypingChanged, connectionStateChanged (idle, connecting, connected, disconnected, offline), unreadCountChanged, error, attachmentUpdated, chatClosed. ChatMessage carries clientId, seq, sentAt and totalMessages.
The error eventlink
error 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.
const off = chat.addListener('error', (e) => {
if (e.code === 'INVALID_IDENTITY_TOKEN') return refreshChatToken();
if (!e.recoverable) reportToYourMonitoring(e.code, e.message);
});NewinstanceChatError carries code (NewinstanceChatErrorCode, the vocabulary shared with every other chat SDK), the broad type (network, validation, auth, system), a developer-facing message, an optional developerMessage, and recoverable. code is undefined only when talking to a native SDK older than the release that introduced coded errors, so existing 0.2.x handlers that read type keep working. The full code list is in Authentication and identity -> Diagnosing problems.
Programmatic attachmentslink
attachFile({ source, sourceType?, name, mimeType?, size?, metadata? }) accepts base64, data URIs, local file paths, content:// and file:// URIs (document and image picker outputs), and remote URLs when the native SDK enables them; sourceType: 'auto' (default) safely detects string inputs, and the legacy { uri, name, mimeType } form keeps working. The promise resolves with the attachment id as soon as the request is queued; validation and upload run in the background and stream through attachmentUpdated (status: queued, uploading, uploaded, failed, cancelled; progress: real 0..1 byte progress). Validation covers base64 decoding, URI readability, empty files, the 25 MB cap, the png/jpeg/webp/gif/pdf MIME allowlist, size mismatches and extension/MIME disagreement. removeAttachment(id) cancels an in-flight upload; a message is never sent with an attachment that has not finished uploading.
The chat close eventlink
chatClosed fires exactly once per chat presentation: the in-chat X (close_button), Android back navigation (back_navigation), an iOS dismissal gesture (gesture), closeChat() (programmatic), destroy() (session_ended), or the host navigating the screen away (host_navigation). Payload: reason, initiator (user/host/sdk), timestamp, conversationId, assignmentId, channel, previousState, unreadCount, hasDraft, pendingAttachmentCount, metadata. It never contains message contents, credentials or attachment data.
Gotchaslink
- Handoff and typing indicators are driven by the native screen; there is no host API for them.
- Multiple instances reconfigure the same native instance; the last configure wins. After
destroy(), construct a new instance. - Same auth rule as every chat client: exactly one of
customerToken(recommended) orapiKeyaskeyId:secret(trusted internal apps only). From 0.4.0 a bare key ID is rejected withE_CONFIG. - iOS build fails with
'NewinstanceChat-Swift.h' file not found: you are on 0.1.0, which only resolved the generated Swift header in static-library Podfiles. Upgrade to 0.1.1 or later (npm install react-native-newinstance-chat@latest, thencd ios && pod install); it supports both default static-library builds anduse_frameworks!with any linkage. - The multi-source
attachFile,attachmentUpdated,chatClosedand a workingunreadCountChangedrequire 0.2.0 of this package and of the underlying native SDKs;pod installafter upgrading. 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;pod installafter upgrading.- 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.
pod installafter upgrading.