docker run -d --name kafka-rest --network host \
-e KAFKA_REST_BOOTSTRAP_SERVERS=localhost:9092 \
-e KAFKA_REST_LISTENERS=http://0.0.0.0:8082 \
-e KAFKA_REST_ACCESS_CONTROL_ALLOW_ORIGIN=https://geekychris.github.io \
-e KAFKA_REST_ACCESS_CONTROL_ALLOW_METHODS=GET,POST,PUT,DELETE,OPTIONS,HEAD \
-e KAFKA_REST_ACCESS_CONTROL_ALLOW_HEADERS=origin,content-type,accept,authorization \
confluentinc/cp-kafka-rest:7.7.1
Kafka client
Work with a real Kafka cluster from the browser through a REST proxy (Confluent REST Proxy or Redpanda): brokers and configs, topics with partitions, ISR and offsets, produce single records or batches, consume by group or partition with live tail, consumer group lag and offset resets — and a log of every HTTP call, with copy as curl.
Added
How to use it
A browser cannot speak the Kafka protocol: it has no raw TCP sockets. So this tool talks to an HTTP gateway that sits next to your cluster — the Confluent REST Proxy (its v3 cluster API, plus v2 for consuming) or Redpanda’s HTTP Proxy (pandaproxy, v2-compatible), with the Redpanda Admin API for what the proxy leaves out. Enter the proxy’s URL, press Connect, and the tool works out which one it is. Every request it makes is listed on the Requests tab, so the page doubles as a way to learn the REST APIs.
To learn how Kafka works without a cluster, use the Kafka simulator instead; it animates partitions, replication, consumer groups and delivery guarantees.
How to use it
Cluster shows the proxy type, cluster id, controller and brokers. Configs lists a broker’s settings (v3), or the cluster config from the Redpanda Admin API.
Topics lists topics with partition counts and replication factors. Click one to see each
partition’s leader, replicas, in-sync replicas (out-of-sync ones in red), earliest and latest
offsets and how many records it holds, then its configs — key ones such as cleanup.policy,
retention.ms and min.insync.replicas first, explained, with durations and sizes in plain
units. With the v3 API you can edit a config, create a topic (partitions, replication factor,
configs) and delete one (you type its name to confirm).
Produce sends one record: a key and a value as text, JSON (validated) or base64 bytes,
headers (name: value per line), and a partition — or leave it empty to let the key choose.
Null (tombstone) sends a null value, which deletes the key from a compacted topic. The
result shows the partition and offset the record was written at. Batch produce takes pasted
lines — one value per line, key:value lines, or NDJSON records such as
{"key": "order-1", "value": {"qty": 1}, "partition": 0, "headers": {"source": "web"}} —
checks them, sends them, and lists where each one landed.
Consume reads a topic two ways. Consumer group subscribes a consumer in a named group:
the group starts from its committed offsets, Earliest/Latest apply only where it has
none, and nothing is committed until you press Commit. Partitions reads chosen partitions
(all, 0, or 0,2) from the earliest offset, the latest, or an offset you give, without
joining a group. Without Live tail, reading stops once it has caught up (Resume reads
more); with it, new records keep arriving until you pause or stop. The table shows
partition, offset, key, value and size; click a row for the pretty-printed JSON, copy
buttons and Re-produce…. Search keys, values and headers (plain text or a regular
expression), filter by partition, sort, and export what is shown as NDJSON or CSV. The tool
keeps the newest 500, 2,000 or 10,000 records.
Groups lists consumer groups and their state; click one for its members and their assignments, and each partition’s committed offset, log-end offset and lag (the v3 lag API). Reset offsets moves a group to the earliest or latest offset, a given offset, or shifts it by a number of records, for a whole topic or some partitions. Preview it, then apply. Kafka only accepts new offsets while the group has no active members, so stop its consumers first. With Redpanda, which cannot list groups, enter a group and a topic to read its committed offsets and lag.
Requests lists every HTTP call: time, method, URL, status and duration. Click one to see
its headers and bodies. Copy as curl gives a command you can run in a terminal, with
$KAFKA_USER, $KAFKA_PASSWORD or $KAFKA_TOKEN in place of your credentials, and
Download as script saves them all.
History keeps the topics you used and the messages you produced (up to 50) in this browser only; Load into producer sends one again.
Running a proxy
The page is served over HTTPS from https://geekychris.github.io, so the proxy must answer
that origin with CORS headers. Chrome, Edge and Firefox let an HTTPS page call
http://localhost; any other plain http:// address is blocked, so use https:// there.
Safari may refuse http://localhost too. Chrome may ask whether this site may reach devices on
your local network: allow it.
Confluent REST Proxy next to a Kafka on localhost:9092 (Linux, where --network host
shares the host’s network):
On macOS and Windows use -p 8082:8082 and KAFKA_REST_BOOTSTRAP_SERVERS=host.docker.internal:9092
instead. That only works if the broker advertises an address the container can reach. A broker
that advertises localhost:9092 hands the proxy an address inside its own container. Add a
listener advertised as host.docker.internal, or run the REST proxy from the Confluent
Platform download (kafka-rest-start kafka-rest.properties) with these lines in its properties
file:
bootstrap.servers=localhost:9092
listeners=http://0.0.0.0:8082
access.control.allow.origin=https://geekychris.github.io
access.control.allow.methods=GET,POST,PUT,DELETE,OPTIONS,HEAD
access.control.allow.headers=origin,content-type,accept,authorization
access.control.allow.origin takes a comma-separated list (add http://localhost:1313 for a
local preview of this site), and access.control.allow.headers must include authorization
if you use credentials.
A throwaway Kafka (KRaft, no ZooKeeper) and REST proxy, nothing exposed but the proxy on 8082:
docker network create kafka-lab
docker run -d --name kafka --network kafka-lab \
-e KAFKA_NODE_ID=1 -e KAFKA_PROCESS_ROLES=broker,controller \
-e KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092 \
-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
-e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT \
-e KAFKA_CONTROLLER_QUORUM_VOTERS=1@kafka:9093 \
-e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
-e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1 -e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1 \
apache/kafka:3.8.0
docker run -d --name kafka-rest --network kafka-lab -p 8082:8082 \
-e KAFKA_REST_BOOTSTRAP_SERVERS=kafka:9092 -e KAFKA_REST_LISTENERS=http://0.0.0.0:8082 \
-e KAFKA_REST_ACCESS_CONTROL_ALLOW_ORIGIN=https://geekychris.github.io \
-e KAFKA_REST_ACCESS_CONTROL_ALLOW_METHODS=GET,POST,PUT,DELETE,OPTIONS,HEAD \
-e KAFKA_REST_ACCESS_CONTROL_ALLOW_HEADERS=origin,content-type,accept,authorization \
confluentinc/cp-kafka-rest:7.7.1
Remove it with docker rm -f kafka kafka-rest && docker network rm kafka-lab.
Redpanda, single node, with its HTTP Proxy on 8082 and Admin API on 9644 (its Kafka API is on 19092, so it does not clash with a Kafka on 9092):
docker run -d --name redpanda -p 19092:19092 -p 8082:8082 -p 9644:9644 \
redpandadata/redpanda:latest redpanda start --mode dev-container --smp 1 \
--kafka-addr internal://0.0.0.0:9092,external://0.0.0.0:19092 \
--advertise-kafka-addr internal://localhost:9092,external://localhost:19092 \
--pandaproxy-addr 0.0.0.0:8082 --advertise-pandaproxy-addr localhost:8082
With the gitwebsite app. If the gitwebsite app (or gw serve) is running, set your proxy URLs once
in its Companion settings (kafka_rest, redpanda_proxy, redpanda_admin), choose ⚡ gitwebsite
app above the proxy URL and Connect: the app relays the REST proxy and the Admin API (and turns POST
X-Method-Override: GET into the GET-with-body Redpanda needs), so no CORS relay is needed. Basic or
bearer credentials you enter still go to the proxy, beside the app’s own token.
Not needed if the gitwebsite app is running — otherwise: Redpanda’s HTTP Proxy and Admin API send no CORS headers, so run this small relay beside them
(Node.js, no packages). It adds CORS for https://geekychris.github.io and serves the Admin
API under /admin. Then connect to http://localhost:8090 with Admin API
http://localhost:8090/admin, or open this preset.
The tool also offers the script under Admin API and authentication → Download the relay.
node kafka-cors-relay.js 8090 http://localhost:8082 http://localhost:9644
// kafka-cors-relay.js: CORS in front of a Kafka REST proxy (and the Redpanda Admin API).
// Not needed when the gitwebsite app is running: its companion relays the proxy and the Admin API.
// node kafka-cors-relay.js [port] [proxy URL] [admin URL] [allowed origins, comma-separated]
const http = require('http'), https = require('https');
const [port = 8090, proxy = 'http://localhost:8082', admin = '',
origins = 'https://geekychris.github.io'] = process.argv.slice(2);
const allowed = origins.split(',');
http.createServer((req, res) => {
const origin = req.headers.origin;
if (origin && (allowed.includes(origin) || allowed.includes('*'))) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Vary', 'Origin');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type, Accept, X-Method-Override');
res.setHeader('Access-Control-Expose-Headers', 'Server');
res.setHeader('Access-Control-Allow-Private-Network', 'true');
}
if (req.method === 'OPTIONS') return res.writeHead(204).end();
const toAdmin = admin && req.url.startsWith('/admin/');
const target = new URL(toAdmin ? req.url.slice(6) : req.url, toAdmin ? admin : proxy);
const headers = { ...req.headers, host: target.host };
delete headers.origin; delete headers.referer; delete headers['x-method-override'];
const method = req.headers['x-method-override'] || req.method;
const up = (target.protocol === 'https:' ? https : http).request(target, { method, headers }, r => {
res.writeHead(r.statusCode, r.headers);
r.pipe(res);
});
up.on('error', e => res.writeHead(502, { 'Content-Type': 'application/json' })
.end(JSON.stringify({ error_code: 502, message: 'relay: ' + e.message })));
req.pipe(up);
}).listen(+port, '127.0.0.1', () => console.log('CORS relay on http://localhost:' + port + ' -> ' + proxy + (admin ? ', /admin -> ' + admin : '')));
The relay also helps with any proxy you cannot reconfigure. It listens on 127.0.0.1 only.
Credentials. Basic auth (user and password) and bearer tokens are sent in an
Authorization header to the proxy and nowhere else. They stay in the page’s memory unless
you tick Remember credentials in this browser, which keeps them in local storage. They are
never put in links, the request log or copied curl commands. The Confluent REST Proxy does
basic auth with authentication.method=BASIC and a JAAS realm. Redpanda’s HTTP Proxy
authenticates with its SASL users when authentication_method: http_basic is set on the
listener.
Limits
-
Neither proxy returns a record’s timestamp or headers when consuming (their v2 consumer API has no such fields), so those columns appear only if a proxy sends them, and reading from a timestamp is not possible.
-
Record headers can only be produced through the Confluent v3 API.
-
Creating, deleting and configuring topics, listing consumer groups and their members, and the lag API need the Confluent v3 API. Redpanda’s HTTP Proxy has none of them: use
rpk. -
Redpanda’s HTTP Proxy answers a batch with the first offset of each partition it wrote to, not where each record went, and does not place records by key the way Kafka clients do. Tick One request per record to see every record’s partition and offset.
-
Redpanda only accepts
earliestas a new consumer’s starting point. To start a new group at Latest, the tool first commits each partition’s current end for that group (this needs the Admin API URL). Its partition offsets come from the Admin API’s debug view (Raft offsets less its configuration entries), checked with one read; treat them as estimates. -
Confluent’s v2 commit stores the offset after the one given; the tool allows for this, so offsets shown and entered are always the next record to read, as Kafka means them.
-
A consumer instance lives on the proxy. The tool deletes it when you stop or leave the page, and the proxy drops idle ones after about five minutes.
-
Values are shown as text, JSON or hex. Avro and Protobuf records (Schema Registry) are shown as raw bytes.
-
The tool talks only to the proxy you enter; nothing passes through this site.
Related: Kafka simulator (how Kafka works, no cluster needed), HTTP client, WebSocket tester, JSON formatter.
Linking to an example
Share link copies a link with the tool’s settings: the topic, consume and produce settings,
and the proxy URL and Admin API URL with any user:password@, query string and fragment
removed. Credentials and history are never included. A link never connects by itself. Put
the tab after #: cluster, topics, produce, consume, groups, log (requests) or
history.
| Parameter | Meaning | Example |
|---|---|---|
|
one of the presets below; parameters written beside it override it |
|
|
the REST proxy URL (credentials and query strings are dropped) |
|
|
the Redpanda Admin API URL |
|
|
|
|
|
the topic used by every tab |
|
|
consume by |
|
|
consumer group (Consume and Groups) |
|
|
partitions to read: |
|
|
|
|
|
the offset to start from |
|
|
|
|
|
search text for the records table |
|
|
the key to produce and its format: |
|
|
the value to produce and its format |
|
|
the partition to produce to (empty: by key) |
|
|
headers to produce, |
|
|
lines for batch produce and how to read them: |
|
Presets:
example= |
Opens |
|---|---|
|
the connection set to a Confluent REST Proxy on |
|
the connection set to Redpanda through the relay on |
|
a JSON order keyed by order id, with a header, ready to produce to |
|
three NDJSON records for batch produce; two share a key, so they land in one partition (open) |
|
live tail of new records on |
|
partition 0 of |
|
every partition of |
|
members, committed offsets and lag of group |
|
the partitions, offsets and configs of |
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser — network requests go only to the services named on this page.