RelayVano

← All postcards

Shipping a Streaming Chat Panel Before Friday

Protocols and gates EN

The chat panel that feels stuck

Your team wants a working support assistant by Friday. The first version sends a question, shows a spinner, and waits for the complete answer. A long reply leaves the page looking frozen for several seconds.

Streaming changes how the answer arrives. Instead of delivering one finished response, the server sends smaller pieces while the model generates them. The browser adds those pieces to the conversation as they arrive. The full answer may take just as long, but the reader can start reading sooner.

Think of it as receiving a letter a few words at a time. Streaming improves the experience of waiting; it does not guarantee that the model finishes faster.

The three connections behind one reply

For a typical web application, the request follows a simple path: browser to your backend, backend to the model API, then streamed output back through your backend to the browser.

Your backend is the server code you control. It checks who is making the request, applies usage limits, and attaches the secret API key when contacting the model service. The browser receives the answer without receiving that key.

This matters because anything delivered to browser code can be inspected. Putting a secret in a frontend environment variable does not protect it if your build includes that value in the downloaded application.

Your backend also gives you a place to record usage and decide which models each account may access. Authenticate the request and validate its size before opening the upstream connection.

A small stream format for the browser

You need an agreement about what the backend sends. Server-sent events, usually called SSE, are one common choice. They carry text events separated by blank lines. Each event can contain a small JSON object describing a piece of text, an error, or completion.

For a chat endpoint, the browser can send a POST request with the Fetch API and read the response body progressively. The browser's built-in EventSource interface is convenient for GET-based streams, but it does not directly support sending a POST body.

Keep your browser-facing event format small and predictable:

  • A text event contains another piece of the assistant's answer.
  • A completion event confirms that generation finished successfully.
  • An error event tells the interface that generation failed.

The backend can translate the provider's stream into these events. That keeps provider-specific response details out of your interface.

The buffer between network bytes and readable text

A network chunk is not necessarily a complete event, word, or character. One read might contain half an event; the next might contain several events together. Even a single character can span multiple bytes.

Use a UTF-8 decoder that preserves state between reads. Keep incomplete event text in a buffer, extract complete events, and leave the unfinished remainder for the next read. Then parse each event and append its text to the current assistant message.

Render incoming content as text. If you later support Markdown, use a renderer configured to handle untrusted content safely. Avoid treating model output as arbitrary HTML.

The deployment settings that can hide streaming

Streaming must work across the whole path. Your application might write each event immediately while a reverse proxy, compression layer, or hosting platform buffers the response until much later.

For SSE, send the text/event-stream content type, configure intermediaries to avoid buffering where supported, and verify your platform's timeout limits. Test the deployed URL with a deliberately long answer. A stream that works locally can still arrive in one big block in production.

Handle stopping as well as starting. When the user presses Stop or disconnects, cancel the upstream request where supported. Track successful completion explicitly: a closed connection alone does not prove the answer finished.

The first production trial through RelayVano

For this setup, I recommend RelayVano as a pay-as-you-go model relay, with https://api.relayvano.com configured as the API base in your backend's compatible SDK. Keep its API key on the server and check the chosen endpoint's streaming format when building your adapter.

Sign up for RelayVano, then test one complete conversation through your deployed backend. Check that text appears progressively, Stop cancels generation, and a connection failure leaves a clear interrupted message. Those checks make the first release useful beyond the happy path.

More postcards from this route