Kafka
Web Browser
Real-Time Data
Event-Driven Architecture
JavaScript

Receiving Kafka event on web browser real time

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Browsers cannot talk to Kafka directly in the usual way because Kafka clients expect the Kafka wire protocol over TCP, and browsers do not expose that kind of raw socket access. The standard architecture is to consume Kafka on the server side and then push events to the browser through a web-friendly channel such as WebSocket or Server-Sent Events.

So the real answer is not “connect the browser to Kafka,” but “bridge Kafka to the browser through a backend service that handles protocol translation, authorization, and fan-out.”

The Usual Architecture

A common real-time path looks like this:

  • Kafka producers write events to a topic.
  • A backend consumer reads the topic.
  • The backend forwards selected events to connected browsers.
  • Browsers receive updates over WebSocket or SSE.

That backend layer is not optional. It is where you handle authentication, filtering, rate limiting, topic mapping, and replay policy.

WebSocket Bridge Example

A small Node.js example with kafkajs and ws illustrates the idea.

javascript
1import { Kafka } from "kafkajs";
2import { WebSocketServer } from "ws";
3
4const kafka = new Kafka({
5  clientId: "browser-bridge",
6  brokers: ["localhost:9092"],
7});
8
9const consumer = kafka.consumer({ groupId: "browser-bridge-group" });
10const wss = new WebSocketServer({ port: 8080 });
11const clients = new Set();
12
13wss.on("connection", (ws) => {
14  clients.add(ws);
15  ws.on("close", () => clients.delete(ws));
16});
17
18async function main() {
19  await consumer.connect();
20  await consumer.subscribe({ topic: "orders", fromBeginning: false });
21
22  await consumer.run({
23    eachMessage: async ({ topic, message }) => {
24      const payload = message.value?.toString() ?? "";
25      for (const client of clients) {
26        if (client.readyState === 1) {
27          client.send(payload);
28        }
29      }
30    },
31  });
32}
33
34main().catch(console.error);

And the browser side is simple:

html
1<script>
2  const ws = new WebSocket("ws://localhost:8080");
3  ws.onmessage = (event) => {
4    console.log("Kafka event forwarded to browser:", event.data);
5  };
6</script>

This is the basic pattern most real implementations follow.

WebSocket Versus SSE

WebSocket is a good fit when the browser also needs to send messages back to the server, such as acknowledgments, filters, or chat-style interaction.

If the flow is strictly server-to-browser, Server-Sent Events can be simpler.

javascript
1import express from "express";
2
3const app = express();
4const clients = new Set();
5
6app.get("/events", (req, res) => {
7  res.setHeader("Content-Type", "text/event-stream");
8  res.setHeader("Cache-Control", "no-cache");
9  res.setHeader("Connection", "keep-alive");
10  res.flushHeaders();
11
12  clients.add(res);
13  req.on("close", () => clients.delete(res));
14});

Kafka events can then be written to each SSE client as text frames. The architecture is the same even though the browser transport changes.

What the Backend Should Do

The backend bridge should almost never forward raw Kafka topics to every browser client. Usually it should:

  • authenticate the user
  • decide which topic or tenant data that user may see
  • transform the event into browser-safe JSON
  • possibly buffer or debounce noisy event streams

This is where the real application design lives. Kafka is the transport backbone; the backend bridge is the policy and delivery layer.

Common Pitfalls

A common mistake is trying to expose Kafka brokers directly to browsers. Even ignoring protocol limitations, that is a bad security boundary.

Another issue is sending every Kafka event to every connected browser without filtering. That does not scale and quickly becomes a data-leak risk in multi-tenant systems.

Developers also sometimes forget that browser clients disconnect often. The bridge service should treat connections as ephemeral and tolerate reconnects naturally.

Finally, be explicit about replay behavior. Real-time dashboards often want only live updates, while notification UIs may need a recent event backlog as well.

Summary

  • Browsers do not consume Kafka directly in the normal architecture.
  • Use a backend consumer to bridge Kafka events into WebSocket or SSE.
  • Put authentication, filtering, and fan-out logic in that backend layer.
  • Choose WebSocket for bidirectional flows and SSE for simple server-to-browser streams.
  • Design reconnect and replay behavior intentionally instead of treating live delivery as purely a transport problem.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.