Escalation
Sometimes the agent can't finish what the user asked for, or the user just wants to talk to a person. Appilots' escalation flow hands the conversation to a human operator without the user leaving your app.
Built into <AppilotsChat/>
<AppilotsChat/> ships this flow out of the box — you don't need to build anything to get it:
- A headset icon in the header lets the user request a human at any time.
- The chat automatically offers a "talk to a human" chip when the agent gives up and can't complete the user's request.
- While an escalation is open, the user's messages route to the human operator instead of the AI.
- The operator's replies appear inline in the transcript as a distinct "human agent" bubble style (message role
human_agent). - When the operator resolves the escalation, the AI resumes normally and a system message marks the transition back.
EscalationState
interface EscalationState {
id: string;
status: 'pending' | 'active';
operatorName?: string;
}
pending— the escalation was requested and is waiting for an operator to pick it up.active— an operator has claimed the conversation and is replying.operatorNameis set once this happens.
There's no client-visible resolved status. Resolution simply clears the escalation state (escalation becomes null again) after a system message is appended to the transcript.
Building a custom chat surface
If you're not using <AppilotsChat/> directly, the escalation surface lives on useAppilotsChat():
import { useAppilotsChat } from '@appilots/sdk';
const { escalation, requestHuman } = useAppilotsChat({
escalationStrings: {
requested: 'Connecting you with a human…',
connected: "You're now chatting with {{operatorName}}.",
resolved: 'Back to the assistant.',
offer: 'Want to talk to a person instead?',
},
});
| Field | Type | Description |
|---|---|---|
escalation | EscalationState | null | The open escalation, or null if none. |
requestHuman | (reason?: 'user_requested' | 'agent_gave_up') => Promise<void> | Requests a human operator. |
requestHuman is idempotent — calling it again while an escalation is already pending or active is a no-op, so you can wire it to a button without guarding against double-taps yourself.
escalationStrings lets you localize the system messages shown at each transition: when the escalation is requested, when an operator connects, when it resolves back to the AI, and the copy shown on the auto-offered "talk to a human" chip.
Example: header button + status banner
function SupportButton() {
const { escalation, requestHuman } = useAppilotsChat();
return (
<>
<Pressable onPress={() => requestHuman('user_requested')}>
<HeadsetIcon />
</Pressable>
{escalation && (
<Banner>
{escalation.status === 'pending'
? 'Waiting for a human agent…'
: `Connected to ${escalation.operatorName ?? 'support'}`}
</Banner>
)}
</>
);
}
Reliability
The live channel that carries operator replies reconnects automatically if the connection drops while an escalation is open — your app doesn't need to do anything to handle that.
Operator side
Claiming an escalation, replying, and resolving it back to the AI is done by your support team from the Appilots dashboard, not from the SDK. See Dashboard: Human Escalation Ops for that side of the flow — this page only covers the client.
Next steps
- Hooks —
useAppilotsChat's full return shape. - Dashboard: Human Escalation Ops — how operators claim, reply to, and resolve escalations.
- Troubleshooting — common integration issues.