Handoff — escalate a conversation to a human
Handoff is how a visitor says "I want a real person" and you hear about it. When it's enabled, the widget shows a discreet "Contact a human" affordance. When a visitor clicks it, Wilow delivers the full conversation transcript to wherever you send it — email, or a ticketing webhook, or both.
When to enable it
Turn handoff on if your customers occasionally ask questions Wilow can't answer — pricing edge cases, account-specific billing, lawyer-only questions. Leaving them with "I don't have that information" and no next step is where trust leaks out.
If your product is genuinely self-serve and nobody should be emailing you, leave it off. The widget stays cleaner without the extra affordance.
How to enable it
- Admin → Widget → Handoff.
- Toggle Enable handoff on.
- Set at least one delivery channel:
- Handoff email — the transcript lands in your inbox as plaintext plus an HTML-formatted summary.
- Ticket webhook — we POST the transcript to your URL as signed JSON. Use this if you already run a helpdesk (Zendesk, Front, Freshdesk, custom).
- Hit Save.
- Use the Test button next to each channel to verify delivery before a real visitor triggers it.
Screenshot placeholder — the Widget → Handoff panel with the email field filled and the Test button highlighted. Tracked in #115.
What the visitor sees
When handoff is enabled, a thumb-sized "Contact a human" button appears at the bottom of the chat pane. The visitor clicks it, optionally leaves their email, optionally adds a reason, and submits. They get a "Thanks — someone will be in touch" confirmation inside the widget. The chat stays open so they can keep talking to Wilow while waiting.
Wilow also detects escalation intent from chat messages themselves ("can I speak to someone?", "I need a real person"). When that fires, it offers the handoff CTA inline — the visitor doesn't have to hunt for the button.
Email delivery
The email arrives at the address you set (one address per account; use a distribution list if multiple people need to see it). Content:
- Your account name + timestamp
- Visitor's email if they provided one
- Visitor's reason if they provided one
- Full conversation transcript, oldest message first
- Deep link to the admin Conversations page for this thread
Delivery is best-effort. If our email provider is temporarily down, the widget still completes the handoff from the visitor's perspective; we retry email asynchronously. Failures surface on the admin's Handoffs page so you can see what never made it through.
Ticket webhook delivery
Point to your own HTTPS endpoint and we POST JSON:
{
"event": "handoff.created",
"tenantId": "…",
"conversationId": "…",
"handoffId": "…",
"visitorEmail": "[email protected]",
"reason": "I want pricing for 500 seats",
"transcript": [
{ "role": "user", "content": "…", "createdAt": "…" },
{ "role": "assistant", "content": "…", "createdAt": "…" }
],
"adminConversationUrl": "https://usewilow.com/admin/conversations?id=…"
}Every request is signed with HMAC-SHA256 in the X-Wilow-Signature header. The signing secret is shown once when you first set the webhook — store it somewhere safe. See Ticket webhook for the verification snippet.
Following up
Every handoff lands on admin → Handoffs. The list shows visitor email, status, delivery results per channel, and a link into the full conversation. Mark it resolved when you've replied to the visitor — the state only exists for your own tracking.
Pitfalls
- Both channels off — handoff enabled with neither email nor webhook set gets a 412 rejection at send time. The widget shows an error. Always configure at least one.
- Webhook not responding — failures on your endpoint are logged but don't break the visitor UX. Check the Handoffs page for errors.
- Handoff disabled on your workspace — the endpoint returns 403. The widget doesn't show the button and the visitor sees a friendly "we're not taking new chats right now" message if they somehow reach the endpoint.