Appearance
Behavior & limits
How the SDK behaves at runtime — worth understanding before you ship. For the full “not a bug” list see Limitations. For storage split (Intercom vs Postgres) see Data model.
Message delivery (polling)
There is no WebSocket. The SDK polls the backend (default every 4s, pollingInterval). On failure the interval backs off (4s → 8s → 16s → max 30s) and resets on success. Tickets poll less often (~20s). Comment threads poll ~5s while open.
Message statuses
User messages show delivery ticks:
| Tick | Meaning |
|---|---|
| 🕓 | sending |
| ✓ | sent / accepted by the backend |
| ✓✓ (tinted) | seen — an operator replied after this message |
| ⚠ (red) | failed — tap to retry (chat only) |
"Seen" and "typing" caveat
Intercom does not expose real read-receipts or operator typing, and there is no WebSocket:
sent/ delivered-to-backend are real.seenis inferred when an operator message follows.- Live typing is not a real presence signal (mock mode fakes it for demos).
Error states
The SDK never shows a blank screen. Localized panels cover:
- Session expired (401) →
onSessionExpired, re-login. - Offline (web:
navigator.onLine) → recovers on reconnect. - Support unavailable (backend / Intercom down) → retry.
Resilience (backend)
- Circuit breaker on Intercom (opens after consecutive failures, then probes).
- Rate limit per user on
/api/*(429 +Retry-After). - Read coalescing cache so concurrent polls share one Intercom call (in-process — see scale notes).
Scale
Intercom allows on the order of ~10k API calls/min per app. With 4s polling that is roughly a ~660 concurrent active-user ceiling before caching and ticket-poll decoupling matter. Beyond one API instance, move cache + rate limits to Redis — Deployment.
Request lifecycle
The user sees one continuous thread; each support request is its own Intercom conversation (open / closed / snoozed):
- No continuable request → pick a topic (admin-managed reasons) → request starts.
- Open or snoozed → composer replies into that conversation (a reply unsnoozes in Intercom).
- Closed within the reopen window (default 5 days,
INTERCOM_REOPEN_WINDOW_DAYS; mirrors Intercom Messenger) → the next message is a reply that reopens the same conversation, and the canned first-message acknowledgement is posted again. CSAT stays visible until that reply succeeds. - Closed after the window → pick a topic; a new Intercom conversation appends below; history remains.
- Stars persist in Postgres (
csat_ratings) — one row per close-cycle (a reopen + later close asks again).
State updates arrive on the next message poll (~4s) without reload.
Single thread, many tickets
One ongoing support thread per user (sequential requests) and any number of tickets (also Intercom). Replying to a resolved ticket reopens it. A chat that support converts into a ticket keeps its history in the support thread, followed by a system line with the ticket number. Conversion does not close the request: the user keeps chatting until an admin closes the conversation in Intercom, and only then CSAT is asked.
Hub Archive
The Archive shortcut opens a Coming soon placeholder — not a defect.