Building a Multi-Channel Inbox: Email, Chat, and Widget in One Thread

Building a Multi-Channel Inbox: Email, Chat, and Widget in One Thread

TL;DR

Customers treat widget, email, and chat as one conversation; most tools store three. The architecture that fixes it: channel-agnostic conversations with channel-tagged messages, identity stitching on explicit signals only, two timestamps per message for stable ordering, and provider-ID deduplication — so the AI reads the whole relationship before answering.

A customer starts in the website widget, follows up by email that evening, and replies to your answer two days later from their phone. To them it is one conversation. Most support tools store it as three.

Unifying channels is mostly a data-model problem, and the decisions you make early are expensive to reverse. Here is how we modeled it.

Conversations are channel-agnostic; messages are not

The core split: a conversation belongs to a contact and a topic, while each message carries its own channel, direction, and delivery metadata. The inbox renders the conversation; the send path looks at the last inbound message to decide how a reply should go out.

This means an agent never chooses a channel. They type a reply, and it returns the way the customer last wrote in — widget message if they are still on the site, email if they left. The channel chip on each message keeps the history legible.

Identity stitching without creepiness

Merging threads requires knowing that widget-visitor 4821 and jane@acme.com are the same person. We stitch on explicit signals only:

  • The visitor authenticates in your product and your frontend passes a signed user hash.
  • The visitor types their email into the widget's email-capture step.
  • They click a magic link from an email notification back into the conversation.

We deliberately do not fingerprint devices to guess identity. A wrong merge shows one customer another customer's history — a category of bug you want to make structurally impossible, not just unlikely.

Ordering is harder than it looks

Email arrives out of order: a reply can beat the original through your pipeline, retries duplicate webhooks, and clock skew across providers is real. Every message gets two timestamps — provider-reported and received-at — and the thread renders on provider time with a monotonic tiebreaker so the UI never reshuffles after first paint.

Deduplication runs on provider message IDs with a content-hash fallback. The fallback matters: some mail servers rewrite IDs on retry, and a duplicated apology email makes your team look asleep.

What the AI sees

The payoff of one thread is that the AI agent reads the whole relationship before answering. It knows the customer already tried the reset flow yesterday in the widget, so it does not suggest it again by email today. Channel-siloed tools force the customer to repeat that context; unified ones make the second answer smarter than the first.

The unified thread is also why escalation summaries stay short — one conversation to summarize, not three fragments to reconcile.

If your team is juggling a chat tool, a shared mailbox, and a form backend, the fix is structural. See how the inbox works, or open one on the free plan and email yourself through it.

Frequently asked questions

How does a reply know which channel to use?

Agents just type; the reply goes out on the channel of the customer's last inbound message — widget if they're still on the site, email if they've left.

How are visitor and email identities merged?

Only on explicit signals: a signed user hash from your frontend, an email typed into the widget, or a magic-link click from an email notification. No device fingerprinting.

What stops duplicate emails from showing twice?

Deduplication runs on provider message IDs with a content-hash fallback for servers that rewrite IDs on retry.

Does the AI see the full cross-channel history?

Yes — the AI reads the unified thread, so it never re-suggests what the customer already tried in another channel.

Keep reading

Answer it once. Chattering remembers.

Free trial · no credit card required