A drop-in chat and support SDK, running inside other companies' apps
Most companies bolt support on: a separate portal, a different login, an email address that goes somewhere nobody watches. This platform does the opposite. It gives an organisation the machinery — agents, tickets, chat history, supervisors, broadcast messaging — and then ships an SDK so all of it appears inside their own app and website.
That distribution model is what makes it interesting to build. The product is not a website people visit. It is a component that lives inside other people's software, and it is now running inside large fintech and logistics products where a support outage is not a quiet problem.
I worked on the web side: the console agents and supervisors sit in all day, and the real-time layer underneath it.
Software that ships inside somebody else's product is held to a standard ordinary software never is.
It runs on their release schedule, not yours. It sits next to their code, so it cannot conflict with their versions or their global state. It has to be small, because the host's bundle size is their problem and your SDK is a line item in it. And when anything goes wrong, the sequence is always the same: the customer blames the host app, the host blames the SDK, and you are explaining yourself to someone whose users are already unhappy.
The console has a different problem. An agent under load is not browsing — they are holding several conversations at once, each with its own history and its own waiting customer. A layout that is merely complete is a layout that costs them seconds per conversation, and those seconds are the whole product.
I built the web front end — the agent and supervisor console — and worked on the real-time layer underneath it: the socket connection, message delivery, presence, and the reconnection behaviour that decides whether a chat feels reliable or not.
The design question for a support console is not what the data model contains, it is what the agent's next action is. Everything else follows from that.
So the layout is organised by conversation rather than by record: what is waiting, what is mine, what needs an answer now. History is present without being asked for, because the first thing an agent does is work out what happened before. And the state of the connection is shown honestly — an agent who cannot tell whether their reply sent will send it twice, and the customer receives it twice.
A React console over a persistent WebSocket connection, with OpenTok carrying audio and video where a conversation needs to escalate past text.
The split matters and is the same lesson that shows up in every real-time product: messages and media are different problems. Sockets are excellent at ordered, reliable, small payloads — chat, presence, typing, ticket state. They are the wrong tool for a live stream, which needs a transport that tolerates loss rather than retrying it. Handing media to a specialist stack kept the socket layer simple enough to reason about.
The console is ours; the surface the customer sees belongs to the host application.
↳ Their release cycle, their bundle
↳ A different problem from messaging
The reconnection behaviour took the most care, because it is where chat products quietly lose trust. A socket on a real network drops constantly — a tunnel, a lift, a laptop sleeping — and the naive handling produces the two worst outcomes: messages that vanish, and messages that arrive twice.
So sending is treated as intent rather than as an event. A message is held until it is acknowledged, retried on reconnect, and de-duplicated on the way in, so an agent who hits send during a two-second outage gets exactly one message delivered rather than none or two.
The console itself is built to keep several conversations open without re-rendering the whole workspace when one of them receives a message. Under load that difference is the difference between a tool and an obstacle.
The console is organised by conversation, not by table. What is waiting, what is assigned to me, and what needs an answer now are visible without navigating. Connection state is shown honestly rather than optimistically, because an agent who cannot tell whether a reply sent will send it again.
Stated qualitatively on purpose. Invented percentages are the easiest thing in the world to write and the fastest way to lose a technical reader.
The integration standard for those environments is high, and support failures there are visible to a lot of people at once.
Messages sent during a brief outage arrive exactly once, which is what makes a chat product feel trustworthy.
Keeping media on a specialist stack meant the socket layer did messaging and did it well.
A support platform that reaches its users as a component inside other companies' products — where the engineering standard is set by the host, and where the difference between a good chat product and a bad one is entirely in how it behaves when the network misbehaves.
If this sounds familiar
Building something similar?
Most of these problems show up again in different clothes. Describe yours and I will tell you what I would look at first.