@parlr/react-native
v0.6.0
Published
Official Parlr live chat SDK for React Native
Downloads
698
Maintainers
Readme
Features
| Feature | Description |
|---|---|
| One-line drop-in | <ParlrLauncher workspaceId="..."> — floating bubble + chat modal, zero navigation setup |
| Real-time messaging | WebSocket with automatic reconnection and exponential backoff |
| Optimistic UI | Messages appear instantly, sync in the background (dedup by clientId + server id) |
| Typing indicators & read receipts | Agent typing events; delivery status sending → sent → read |
| Pre-built UI | <ParlrLauncher>, <ParlrChat>, <ParlrConversationList> — or build your own with hooks |
| Pre-chat forms & CSAT | Collect visitor info before the first message; satisfaction rating after resolution |
| File attachments & rich messages | Images/documents; cards, carousels, quick replies rendered natively |
| Push notifications | FCM (Android) / APNs (iOS) via useParlr().registerPushToken(...) |
| Offline queue | Failed messages are queued and replayed on reconnection |
| Speech-to-text | Voice dictation with live volume and accumulated transcription |
| Theming & dark mode | Branding loaded from your dashboard; automatic system dark mode + full overrides |
| User identification & HMAC | email / name / externalId; server-side HMAC to prevent impersonation |
| TypeScript-first | Complete type definitions ship with the package (your editor autocompletes them) |
Works with Expo (managed & bare) and bare React Native. The SDK handles session management, WebSocket connections, message delivery, branding and reconnection for you.
Installation
npm install @parlr/react-native
# or: yarn add @parlr/react-nativeRequired peer dependency
npm install react-native-reanimatedMobile reality: “one line” refers to one line of code. Installing a native SDK still requires
npm install+ a native rebuild (CocoaPods / EAS / dev client).
Optional dependencies
npm install expo-secure-store # encrypted session persistence (recommended)
npm install react-native-svg # vector icons (emoji fallback without it)
npm install expo-image-picker expo-document-picker # file & image attachments
npm install expo-speech-recognition # voice dictationWithout
expo-secure-store, sessions are kept in memory and don't persist across app restarts (users get a new session each launch).
Compatibility
| Package | Min version | Required |
|---|---|---|
| react | 18.0.0 | Yes |
| react-native | 0.72.0 | Yes |
| react-native-reanimated | 3.0.0 | Yes |
| expo-secure-store / react-native-svg / expo-image-picker / expo-document-picker / expo-speech-recognition | see npm | No |
Quick Start
Recommended — one line with ParlrLauncher
A drop-in floating chat bubble + chat modal. No navigation setup required. Only
workspaceId is needed; colors, greeting and placeholder come from your dashboard.
import { ParlrLauncher } from '@parlr/react-native';
export default function App() {
return (
<>
<Navigation />
<ParlrLauncher workspaceId="your-workspace-id" />
</>
);
}Use
ParlrLauncherOR the advancedParlrProvidersetup below — not both nested.
Advanced — controlled integration
For your own navigation, support button and screen, wrap your app with the provider and
render <ParlrChat> where you want; drive it with the hooks.
import { ParlrProvider, ParlrChat, useParlr } from '@parlr/react-native';
export default function App() {
return (
<ParlrProvider workspaceId="your-workspace-id">
<Navigation />
</ParlrProvider>
);
}
// In your support screen:
function SupportScreen({ navigation }) {
return (
<ParlrChat
user={{ email: '[email protected]', name: 'Alice' }}
onBack={() => navigation.goBack()}
/>
);
}
// Show an unread badge anywhere inside the provider:
function SupportButton() {
const { unreadCount } = useParlr();
return <Badge count={unreadCount} />;
}Components
<ParlrLauncher>
All-in-one drop-in: instantiates its own ParlrProvider, renders a floating bubble and
opens the chat in a native modal. workspaceId is the only required prop.
| Prop | Type | Default | Description |
|---|---|---|---|
| workspaceId | string | — | Required. |
| user | ParlrUser | — | Identify the user on mount. |
| position | 'left' \| 'right' | 'right' | Bubble corner. |
| accentColor | string | backend theme | Bubble + chat accent color. |
| hidden | boolean | false | Hide the bubble programmatically. |
| offset | number | 0 | Extra inset (px) from screen edges (safe area). |
| headerTitle, placeholder, locale, theme, identityToken, onError | — | — | Same as ParlrProvider / ParlrChat. |
<ParlrProvider>
Root provider for the advanced integration: bootstraps the session, connects the WebSocket, fetches branding, and exposes everything through the hooks.
| Prop | Type | Default | Description |
|---|---|---|---|
| workspaceId | string | — | Required. |
| apiBaseUrl | string | https://api.parlr.chat/api/v1/widget | REST base URL (self-hosted override). |
| wsUrl | string | wss://ws.parlr.chat/widget-ws | WebSocket endpoint. Pass "" to disable real-time. |
| locale | string | "fr" | BCP-47 locale. |
| theme | Partial<ParlrTheme> | backend | Theme overrides (see Theming). |
| identityToken | string | — | HMAC identity token (see Identity Verification). |
| debug | boolean | false | Verbose logging. |
| onError | (error: ParlrError) => void | — | Global error callback (e.g. Sentry). |
<ParlrChat>
The full chat screen. No required props — user and onBack are recommended.
Key props: user, conversationId, onBack, headerTitle, placeholder, accentColor,
showHeader (default true), showPreChatForm (default false), preChatFields
(default ['name','email']), showSatisfactionSurvey (default true), safeAreaBottom,
allowSpeechToText (default true), onConversationClosed.
<ParlrConversationList>
A list of the contact's conversations with unread badges and last-message previews. Pair
it with <ParlrChat conversationId={...}> for an inbox-style UI. Lower-level building
blocks (ChatBubble, TypingIndicator, EmptyState, PreChatForm, SatisfactionSurvey,
AttachmentPicker, RichMessage, SpeechButton) are exported for custom UIs.
Hooks
useParlr()
Access SDK state and actions from any component inside <ParlrProvider> (or <ParlrLauncher>).
const {
isReady, // true once the SDK has bootstrapped
isConnected, // true when the WebSocket is connected
session, // { token, contactId, workspaceId }
conversations, // all conversations for this contact
unreadCount, // total unread across conversations
identify, // (user: ParlrUser) => Promise<void>
refreshConversations, // force-refresh the conversation list
theme, // resolved theme (light/dark + overrides)
widgetConfig, // backend branding/greeting/team (null until loaded)
trackEvent, // (type, url, props?) => track a behavioral event
registerPushToken, // (token, 'ios' | 'android') => register for push
unregisterPushToken, // (token) => unregister (e.g. on logout)
} = useParlr();
await identify({ email: '[email protected]', name: 'Alice Martin', company: 'Acme' });useChat(conversationId?)
Manage a single conversation with real-time, optimistic updates.
const {
messages, // ordered oldest-first
isLoading, hasError,
conversation,
agentTyping, // auto-clears after 5s
sendMessage, // optimistic: appears instantly, then 'sent' on confirm
retryMessage, // (clientId) => retry a failed message
notifyTyping, // (isTyping) => debounced typing indicator
loadMore, hasMore, // pagination of older messages
closeConversation, reopenConversation,
} = useChat(conversationId);
await sendMessage('Hello, I need help with my order');Optimistic send: the message is inserted locally (sending), sent over REST and
WebSocket, then marked sent (or failed, retryable 3× with backoff). Duplicates are
removed by both clientId and server id. Omitting conversationId creates a new
conversation on the first send.
useSpeechRecognition(options?)
Low-level voice-dictation hook (used internally by <ParlrChat>, exported for custom inputs).
Returns { isRecording, isAvailable, transcript, volumeLevel, error, startRecording,
stopRecording, toggleRecording, clearTranscript }. Options: locale, onResult, onStart,
onStop, onError. The transcript accumulates across final segments; gracefully no-ops if
expo-speech-recognition isn't installed.
User Identification
Identify users through the ParlrUser shape — all fields optional except you'll usually
pass at least an email:
interface ParlrUser {
email?: string;
name?: string; // auto-split into firstName/lastName if those aren't set
firstName?: string;
lastName?: string;
externalId?: string; // your internal user id
phone?: string; // E.164
company?: string;
customAttributes?: Record<string, unknown>;
}// Simple — let the SDK split the name:
await identify({ email: '[email protected]', name: 'Alice Martin' });
// Explicit + custom attributes:
await identify({
email: '[email protected]',
firstName: 'Alice',
lastName: 'Martin',
company: 'Acme Inc',
customAttributes: { plan: 'pro', mrr: 299 },
});You can also pass user directly to <ParlrLauncher> / <ParlrChat> to identify on mount.
Theming
Branding (colors, greeting, placeholder) is loaded from your dashboard automatically — your
theme overrides always win. Dark/light mode is detected from the system.
// Brand color only (most common):
<ParlrProvider workspaceId="..." theme={{ colors: { primary: '#E91E63' } }}>
// Programmatic access:
import { useParlr, defaultLightTheme, defaultDarkTheme, mergeTheme } from '@parlr/react-native';
const { theme } = useParlr();
const custom = mergeTheme(defaultDarkTheme, { colors: { primary: '#FF6B00' } });ParlrTheme covers colors (primary, background, surface, text, agent/contact bubbles…),
borderRadius, spacing and typography. The full type ships with the package — your
editor will autocomplete every field.
Push Notifications
Register the device token via the useParlr() hook (it uses the SDK's authenticated client
internally — you never handle it):
import { useParlr } from '@parlr/react-native';
import { useEffect } from 'react';
import { Platform } from 'react-native';
import messaging from '@react-native-firebase/messaging';
function PushRegistration() {
const { registerPushToken, unregisterPushToken } = useParlr();
useEffect(() => {
messaging()
.getToken()
.then((token) => registerPushToken(token, Platform.OS as 'ios' | 'android'));
// On logout: unregisterPushToken(deviceToken);
}, [registerPushToken]);
return null;
}Must be rendered inside
ParlrProvider(orParlrLauncher).
Behavioral Tracking
Track screen views and custom events for automated triggers configured in the dashboard:
const { trackEvent } = useParlr();
await trackEvent('SCREEN_VIEW', 'checkout');Identity Verification (HMAC)
For production, prevent contact impersonation by signing the user identity server-side.
// Server-side (Node.js) — signs with your workspace secret:
const hmac = require('crypto').createHmac('sha256', WORKSPACE_SECRET);
hmac.update(user.email);
const identityToken = hmac.digest('hex');<ParlrProvider workspaceId="..." identityToken={identityTokenFromYourBackend}>The token is sent as X-Identity-Token on every request and validated server-side.
Error Handling
All SDK errors extend ParlrError: ParlrNetworkError, ParlrAuthError,
ParlrValidationError, ParlrConnectionError. Use the provider's onError callback for
global monitoring:
<ParlrProvider workspaceId="..." onError={(e) => Sentry.captureException(e)}>Self-hosted / development
Point the SDK at your own backend via the advanced provider (these aren't exposed on
ParlrLauncher, which targets production defaults):
<ParlrProvider
workspaceId="..."
apiBaseUrl="https://your-host/api/v1/widget"
wsUrl="wss://your-host/widget-ws"
debug={__DEV__}
>Changelog
0.6.0
<ParlrLauncher>— one-line drop-in. A single component that instantiates its ownParlrProvider, renders a floating chat bubble and opens the chat in a native modal. No navigation setup required. The advancedParlrProvider+ParlrChat+ hooks integration is unchanged. Use one or the other, not both nested.- Push via
useParlr().registerPushToken(token, platform)andunregisterPushToken(token)are now exposed on the hook (which uses the SDK's authenticated client internally). The previous low-levelregisterPushToken(api, ...)top-level exports — which leaked the internal API client — have been removed; migrate to the hook. - Launcher bubble contrast. The bubble icon color is derived from
theme.colors.primaryTextinstead of a hardcoded white, so it stays visible on light brand colors.
0.5.0
- Security: WebSocket token via subprotocol — the session token is carried by the
bearerWebSocket subprotocol (new WebSocket(url, ['bearer', token])) and read server-side before the upgrade, instead of a?token=query parameter (which leaks into logs,Referer, and history). - Real-time enabled by default —
wsUrldefaults towss://ws.parlr.chat/widget-ws. PasswsUrl=""to opt out.
0.4.0
- Offline queue integrated into the send flow (failed messages queue and replay on reconnect, bounded to 100 messages / 24h TTL).
- Error boundary in
ParlrChat, agent avatar images, redacted WebSocket logs, themed colors (no hardcoded hex), and accessibility labels on status indicators.
Older releases (0.1.x–0.3.x) are listed in CHANGELOG.md.
License
MIT © Parlr
