<!-- AI agents: this is the Markdown version of a Reception documentation page. Index: /llms.txt -->

# Chat features & behavior

ReceptionKit provides a native support conversation with text, photos, review and paywall cards, automatic read updates, and recovery from connection failures. This guide describes what the built-in chat does, its limits, and how to verify it in your app.

For entry-point designs, placement, and presentation code, see [Open & close the chat](/docs/entry-point#entry-examples).

Sending, photos, typing, and read updates are built into the chat. Use the [SDK reference](/docs/sdk-reference) for the supported host-app APIs.

## Text messages

Users type in the multiline composer and tap the send arrow. The chat accepts text alone, photos alone, or both in one message. Text is trimmed before sending; whitespace alone is not a message.

Messages can contain up to 4,000 characters, including spaces. Some emoji and other characters count as more than one toward this limit. Longer drafts show an explanation and cannot be sent; they are not shortened automatically.

Messages render as plain text, with text selection available after sending. There is no Markdown or HTML message renderer, custom message component API, message editing, or individual message deletion in the SDK chat.

### Sending status

A send appears immediately as a local message. While delivery is pending, the chat shows its sending state. Server confirmation changes the message to **Sent**. A failed message shows **Not delivered**. Use **Retry** when available, or follow the waiting notice. Some waits show an automatic resend countdown with **Cancel**. When retrying is available, tapping the failure indicator or failed bubble also retries it.

**Sent** means the server accepted the message. It does not mean an agent has opened or read it. Status labels are grouped in the conversation and need not appear below every successful message.

![Outgoing chat message with Sending state](/docs/images/ios-message-sending.webp "Sending: native UI shown with a pending example message.")

![Failed outgoing message with Retry action](/docs/images/ios-message-failed.webp "Not delivered: the same native UI in a simulated failure state.")

### Conversation scope

Support conversations belong to the current device registration. Identifying the same user on two devices does not merge their histories; see [Identity](/docs/accounts#metadata).

Marking a conversation resolved in the inbox leaves the iOS chat, composer, and draft in place. The next new customer message reopens that conversation.

Initial history loading returns the latest 50 messages. New messages appear as they arrive. There is no built-in “load older messages” control or public pagination API, so do not treat the chat as a complete archive.

### Team photos and names

Agent replies can show the teammate's uploaded profile photo and first name. Both are off by default. An owner enables **Show team photos** and **Show team names** per app under **Chat appearance**. See [Team photos and names](/docs/remote-appearance#team-photos-and-names) for setup and an example.

## Photos

The photo button opens the system Photos picker, restricted to images. Users can attach up to five photos per message, remove selections before sending, and send photos with or without text. Loading a selection temporarily disables sending. An unreadable selection shows **Could not load this photo.**

### Image preparation and upload

ReceptionKit converts selected photos to compressed JPEGs before uploading them to Reception’s attachment storage. Transparency becomes white, and original files and animations are not preserved.

The composer displays upload progress and keeps failed messages available to retry.

Reception manages attachment storage. A working text conversation alone does not verify photo uploads.

### Viewing photos

User and agent photos appear in the transcript. Tapping a confirmed attachment opens a full-screen viewer with pinch zoom, double-tap zoom, and a close control. Pending local previews are not confirmed attachments; tapping a failed photo retries its message when retrying is available.

The SDK has no camera capture UI, document picker, video or audio message support, arbitrary file attachments, or public upload API.

## Review cards

An agent sends a review card from the dashboard after an App Store ID has been configured for the app. The button uses the agent's chosen label or the localized **Rate on the App Store** default. Card text is optional: without text, the card shows only its button. If a review message has no review URL, the SDK displays its text without the button.

Tapping the button opens the supplied App Store review URL through the system URL action. This is a link to the App Store, not a StoreKit in-app rating prompt. The SDK emits `.reviewOpened` and reports the tap for the dashboard’s click receipt.

> **Note:** A review tap records intent to open the review page. Neither the local event nor the dashboard click receipt confirms a submitted review, a star rating, or even successful URL opening.

The host app cannot send review cards through ReceptionKit. Dashboard configuration, eligibility, and agent instructions are covered in [Reviews](/docs/reviews). Use [Events](/docs/events) to observe the supported local callbacks.

## Paywall cards

An agent can send a card for a paywall your app has registered. Tapping it calls your app’s `onPaywall` handler; your app presents the purchase screen and handles purchases. An open event does not confirm a purchase. See [Paywall cards](/docs/paywalls) for setup.

The button uses the agent's chosen label or the localized **View offer** default. As with review cards, a card without text shows only its button.

## Read state and unread counts

When an activated chat is visible and the app is active, ReceptionKit loads messages and automatically reports loaded messages as read. Message refreshes also report read state. After synchronization, `Reception.shared.unreadCount` reflects the remaining unread replies. Replies that arrive after the loaded messages remain unread until a later refresh processes them.

This is conversation-level behavior. It does not wait for every bubble to enter the viewport, and it is not evidence that the user read every word. Merely displaying cached history offline does not confirm a read to the server.

Agents can see delivery and read status for their replies in the dashboard. The user's outgoing SDK bubbles show **Sent**; this does not indicate whether an agent has read the message.

When the chat closes, ReceptionKit refreshes the unread count. Foreground unread monitoring and forwarded support pushes can update the count without displaying or marking the conversation read. App icon badge synchronization is enabled by default and can be disabled when the host manages its own badge. See [Unread messages](/docs/unread-messages) and [Push notifications](/docs/push-notifications).

## Activation and live updates

### Before the first send

Configuring ReceptionKit prepares support without registering a device. For an unused support session, opening chat, drafting text, selecting photos, and supplying identity, metadata, or a push token do not register a device.

The configured SDK or a visible chat can fetch public project appearance before activation. This request uses the App ID and does not register a device. See [Remote appearance](/docs/remote-appearance).

### First valid send attempt

The first valid send attempt starts device registration. Registration can succeed even if the message later fails. A conversation appears in the dashboard once Reception accepts the message.

Support remains active across launches.

### While chat is open

ReceptionKit keeps an existing conversation updated while the chat is visible and the app is active. Your app does not need its own refresh timer.

ReceptionKit shows when an agent is typing. It reports customer typing to the dashboard while an open conversation allows sending. Your app does not need to implement typing updates.

Leaving the chat or backgrounding pauses live updates and automatic retries. An already-running send can still finish. Use APNs integration for notifications about replies while the app is not active.

The dashboard’s **In chat** signal reflects a live chat connection. **Last active in chat** records recent chat activity. Neither proves someone is currently reading, and a missing live signal does not prove the device is offline.

## Offline behavior, cache, and retries

### Local persistence

The SDK keeps recent chat history and pending or failed messages with their photos for the current support session. Use **Retry** on a failed message to try sending it again.

Text drafts are stored separately and restored. Photos selected in the composer but not yet sent remain in memory and are not persisted as draft photos across relaunch. Once Send is tapped, their persistence is part of the pending-message cache.

Local storage is best effort and the history cache is excluded from backups. Previously received photos may be unavailable offline; reopen the chat online to load them again.

### Connection status

Connection status appears above the composer for an activated chat:

| Status | Meaning |
| --- | --- |
| No connection | The device reports no available network path. |
| Connecting | The device has network access and is reconnecting to the conversation. |
| Connected | The chat connection recovered after an interruption. |
| Live updates paused | Live chat updates are temporarily paused. Follow any waiting notice in chat. |

An unused chat keeps connection status hidden. Check each message’s sending status to confirm delivery.

### Automatic and manual retries

ReceptionKit retries eligible failed sends while the chat is visible and the app is active. If a message still shows **Not delivered**, restore connectivity and tap **Retry**. Temporary sending limits may require waiting before a retry can proceed.

Pending messages and drafts can survive relaunch. Closing or backgrounding the chat can pause automatic retries; check the message’s visible status when returning. There is no guaranteed background delivery.

### Restrictions and reset behavior

A blocked device can continue reading its conversation, but cannot send messages or upload photos. Once ReceptionKit learns about the block, it replaces the composer with a sending-disabled notice and stops automatic retries. A send rejected as blocked stays **Not delivered** with its text and photos. After the team unblocks the device, return to the app or use **Retry** to refresh its state. Any unsent draft stays available and is not sent automatically.

If your app accepts only verified users, an unverified session can read existing messages but cannot send. The chat shows **Sign in to send messages.** when it learns verification is required; failed messages keep **Retry**. Pass a new signed token to `identify(token:)`. The notice clears when the SDK accepts it locally; Reception must verify it before sending succeeds. Token expiry alone does not undo existing verification. See [Identity verification](/docs/accounts#only-verified).

Reception may temporarily limit frequent sends or photo uploads. Follow the chat’s waiting notice, then use **Retry** if needed. A photo-only restriction can still allow text messages.

Logout clears the local session, including activation, cache, drafts, and pending work. A server support reset, or a session that Reception no longer accepts (for example because the device was deleted in the dashboard), also resets chat state; the next send starts support again. Temporary connection failures do not reset the session. An offline device learns about a server reset on its next contact. Integrate [Login and logout](/docs/accounts#sign-out) and [Delete data](/docs/accounts#delete-data) deliberately so pending work is not carried between users.

## Verify in your app

Use a development app and synthetic messages. These checks verify observable behavior rather than only successful compilation:

1. Open an unused chat, enter a draft, and select a photo without sending. Confirm that no device or conversation is created. Public appearance requests may occur.
2. Send a short text such as “Hello from support verification.” Confirm **Sent** in the app and exactly one matching message in the dashboard. Reply from the dashboard and confirm it appears while chat stays open.
3. Send a photo-only message and a text message with five photos. Confirm thumbnails, upload progress when observable, and the full-screen viewer. Verify that an over-limit text draft disables sending.
4. Close the chat, send an agent reply, and verify unread state through automatic unread checks or your push integration. Reopen the foreground chat and confirm the unread count clears after server synchronization and the dashboard shows the reply as read.
5. After activation, disable networking and send another message. Confirm connection and failure state, then restore networking. If automatic attempts have expired, tap **Retry**. Confirm one server message, not a duplicate.
6. With networking still unavailable, relaunch with a pending or failed message and an unsent text draft. Confirm both restore. Selected photos that were never sent need to be selected again.
7. Keep a test conversation open while blocking and unblocking the device in the dashboard. Confirm reading stays available, sending updates, and the draft remains unsent.
8. Send an eligible review card from the dashboard and tap it. Verify the App Store action and, once networking succeeds, the dashboard click receipt. Do not label this as a completed review.

For presentation and visual checks, also exercise long text, Dynamic Type, dark mode, keyboard appearance, and your chosen [Language](/docs/language) and [Appearance](/docs/appearance). See [Troubleshooting](/docs/troubleshooting) for connection and configuration problems.
