Lifecycle and limits
Background and foreground behaviour, reconnects, errors, rate limits, and what the SDK leaves to you.
Connection lifecycle
- Boot. The provider loads the visitor id, mints a session token, fetches
the widget config and opens the session in parallel, then connects the
socket and joins the widget's channel.
statusonuseSupportConfig()goesloading→ready, orerrorwith areload()to retry. - Heartbeat. A ping every 30 seconds keeps the session marked as connected in the workspace, which is what the agent inbox uses to show the visitor as online.
- Websockets only. Long polling is not reliable in React Native, and the server allows either transport.
- Reconnects. Socket.IO reconnects on its own after a drop; the SDK re-joins the channel on every connect.
Background and foreground
When the app goes to the background the SDK closes the socket, stops the
heartbeat, and marks the session disconnected. When it comes back to the
foreground it pings, reconnects, re-joins, and re-fetches history so anything
that arrived while the app was away is shown. useConversations refreshes its
list at the same time.
Brief interruptions on iOS, such as the app switcher or a permission dialog, do not count as backgrounding and leave the connection alone.
Set manageAppState={false} on the provider to handle all of this yourself.
AI replies
When the widget has AI auto-reply on, a reply streams in over the socket
after each visitor message and appears as aiStream on useConversation()
while in progress. If the stream stops and never finishes, the SDK gives up
after 60 seconds (streamTimeoutMs on the provider) and clears the
placeholder. If the AI produces an error, error on the hook carries it and a
"Talk to a human" escalation is the natural next step.
Errors
Every failure is a SupportApiError with:
| Field | Meaning |
|---|---|
code | network, rate_limited, unauthorized, forbidden, not_found, validation, server, or client |
status | The HTTP status, or null for network failures and local validation |
message | The server's message when it sent one, otherwise a short description |
body | The parsed response body |
client means the SDK refused to make the call at all, for example sending
before the session was ready. The hooks also expose the last error as error.
Rate limits
| Action | Limit |
|---|---|
| Messages | 20 per minute, per widget, per IP address |
| Uploads | 10 per minute, per widget, per IP address |
| Email tickets | 10 per hour, per widget, per IP address |
| AI replies | 5 per minute per widget, shared by all visitors |
A rate-limited send or upload is retried once after three seconds and then
surfaces as a SupportApiError with code rate_limited. Set
rateLimitRetryDelayMs: 0 on a SupportClient you construct yourself to
disable the retry.
The message limit is per IP address, and mobile carriers put many subscribers behind one address. A busy app can see unrelated users count against each other's limit. Keep the composer disabled while a send is in flight and avoid sending programmatically.
What the SDK does not do
- Push notifications. Agent replies reach the app only while it is open. Nothing in the workspace registers device tokens yet.
- The hub landing. On the web, hub mode shows a grid of cards before the
chat. The SDK exposes
config.hubCardsand the client methods behind them (knowledge base search, feature requests, email tickets) so you can build your own landing, but does not render one. - A file picker. Pass one in; see Chat screen.
- Offline queueing. A send while offline fails with
code: 'network'; the screen restores the draft so the user can retry.