# 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 start

```bash
npm install react-native-newinstance-chat@^0.5.0
cd ios && pod install
```

Android needs `mavenCentral()` in `settings.gradle.kts`.

Your backend mints a customer token (see [Session tokens (REST API)](/session-tokens-rest-api)) and hands it to the app:

```ts
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 modes

**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:

```ts
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.

```ts
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](/authentication-and-identity).

## Local theme

```ts
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](/theming).

## Events

`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 event

`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.

```ts
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 attachments

`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 event

`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.

## Gotchas

- 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) or `apiKey` as `keyId:secret` (trusted internal apps only). From 0.4.0 a bare key ID is rejected with `E_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`, then `cd ios && pod install`); it supports both default static-library builds and `use_frameworks!` with any linkage.
- The multi-source `attachFile`, `attachmentUpdated`, `chatClosed` and a working `unreadCountChanged` require 0.2.0 of this package and of the underlying native SDKs; `pod install` after upgrading.
- `theme` and coded errors require 0.3.0 of this package and of the underlying native SDKs. The two exclusive auth modes, `customerToken` in the config and the reworked `setUserToken` require 0.4.0; `pod install` after 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](/mcp-servers). `pod install` after upgrading.
