Entry No. 02 · Case study · Enterprise

A chat widget,
two million times a month.

Dates
May — Aug 2025
Place
Bloomington, IL
Role
SWE Intern
Stack
Angular · AWS · Connect
Live
statefarm.com

The hardest part of writing a chat widget for two million people a month is not the concurrency. It's the 3% of sessions where the user's signal drops for nine seconds in the middle of a sentence, and the widget has to pretend nothing happened.

The brief.

My summer was narrow on paper: rebuild the State Farm customer chat widget in Angular on top of the company's new design system, sit it on Amazon Connect, and don't drop messages. I spent the first two weeks mostly reading — the existing widget, the design system source, the Amazon Connect SDK, the tickets people had been filing about dropped messages for the last eighteen months.

FIG. 01 — Live widget on statefarm.com/customer-careAug 2025 · Mux stream

Three screens do most of the work.

A welcome screen that has to promise confidentiality without sounding like a compliance warning. A conversation view that has to stay readable one-handed on a phone in a parking lot. An end-chat dialog that has to be kind to someone who might have been frustrated for nine minutes already.

Virtual assistant welcome screen with confidentiality notice and greeting
01 · Welcome
Conversation view with quote flow and quick-reply chips
02 · Conversation
End-chat confirmation dialog with Yes and No options
03 · End chat
FIG. 02 — Welcome · Conversation · End chat. Captured from statefarm.com.Apr 2026
The concurrency isn't the hard part. The lost nine seconds are.

Why WebSockets, really.

The existing widget polled. Two seconds on, two seconds off, cheerful about it. It worked, in the sense that messages eventually arrived. The reason we moved to a persistent WebSocket wasn't latency — it was that polling hides disconnections. A dropped poll looks identical to an empty poll. With a socket, a disconnect is an event; the widget can see it, hold outgoing messages, and reconnect with exponential backoff up to thirty seconds. A dropped poll is a mystery. A dropped socket is a problem you can solve.

The offline queue.

The piece I'm proudest of is also the one nobody will ever notice. Outgoing messages go into a local queue the instant they're typed, optimistically rendered, tagged with a client ID. They drain to the socket when it's open; they sit when it isn't. On reconnect, the queue replays in order and deduplicates on the server by delivery ID. The effect is that a nine-second signal drop mid-sentence feels like a half-second pause. The user never gets the "message failed" red icon that every other support widget I've used seems to love.

What I got wrong.

I spent a week convinced persistent sockets would never pass the security review — then sat in the review, heard the actual objection (connection limits on a specific firewall tier, not the socket itself), and walked out with a fix that took an afternoon. The lesson I keep re-learning: when something seems blocked, find the person who would know, ask them directly, and spend less time arguing with the wall in your head.

Written April 2026. Published under the State Farm Summer 2025 internship. All code and systems described were shipped to production; screenshots are from the live widget on statefarm.com/contact-us.

← Back to the journal