Wireshark for Kafka. A desktop app that speaks the Kafka protocol natively, intercepts the traffic between your client and the broker, and shows you what's really going through the wire.
Most engineers building apps on Kafka have no good way to see what their clients actually do. Logs and dashboards don't show protocol exchanges, and topic browsers (Conduktor Console, Redpanda Console, AKHQ, Kafdrop) show data at rest, not the wire.
That's where the trouble hides — both the bad patterns in your code and the silent drift bugs in your SDK:
OffsetCommitafter every single record. [example]- A fresh producer (full
ApiVersions+Metadata+InitProducerIdhandshake) per record. [example] - Tiny Produce batches behind a high message rate (
linger.ms=0+ tinybatch.size). [example] - A consumer group rebalancing every few seconds because the heartbeat config is wrong. [example]
- A producer pinned to a stale leader after a broker restart —
Metadatasays leader is broker 50,Producestill goes to broker 34. [example] - A rolling upgrade where the client locks in the seed broker's
api_versionand breaks against older brokers. [example] - A SASL re-auth that dies on a clock-like cadence —
Session too shorton the second 2h hop. [example]
Invisible from logs. Obvious once you see the protocol.
If you debugged HTTP with Fiddler ten years ago, this is the same idea, for Kafka.
Two capture modes, one decoder. Pick what fits your setup — and combine them if you have a polyglot fleet.
Attach a ByteBuddy agent to your Java Kafka client at startup:
java -javaagent:kapture-jvm-agent.jar -jar your-app.jarThe Java 17+ agent hooks SslTransportLayer.read/write and PlaintextTransportLayer.read/write inside the client JVM and streams plaintext Kafka bytes to Kapture over a Unix domain socket (/tmp/kapture-tap.sock, owner-only 0600). The TLS connection stays end-to-end with the real broker — real cert, real handshake, real mTLS / SASL / pinning. There is no second TLS session, no fake cert to install, no client config change.
your Java client ─────────TLS────────▶ real broker
│
└─ in-process agent ──▶ /tmp/kapture-tap.sock ──▶ Kapture
Works against Confluent Cloud, MSK, Azure Event Hubs, your local docker — anything the Java client can talk to. SSL and PLAINTEXT listeners both covered.
Caveats: tap mode requires Kapture and the client on the same host. JVM clients
use the resident agent; Linux processes exposing OpenSSL can use the PID-scoped
eBPF tap. Static Go crypto/tls and Rust rustls clients are not yet covered.
Point your client at 127.0.0.1:9092, Kapture forwards every byte upstream and copies a decoded view to the inspector.
your client ──▶ 127.0.0.1:9092 ──▶ real broker
│
▼
Kapture inspector (live)
No instrumentation, no SDK swap, no broker plugin. Kapture can establish TLS upstream and authenticate to Kafka with SASL/PLAIN or SASL/SCRAM-SHA-256/512. When Kapture uses configured upstream credentials, Kafka sees that service account and applies its ACLs.
Pick proxy mode when the client runtime has no compatible tap, or when changing its local Kafka connection is acceptable.
Today the local client → Kapture listener is plaintext on 127.0.0.1; the
application must change its bootstrap and local security protocol. Incoming TLS
and an explicit choice between forwarding the client's SASL identity or using a
Kapture-managed service account are roadmap items. Client-certificate identity
(mTLS) cannot be delegated without making its private key available to Kapture.
- Live wire view. Every Kafka API request/response decoded —
corr_id, RTT, payload size, full body tree. Apache Kafka 4.x compatible (including KIP-516 topic IDs and KIP-932 Share Groups). - Messages tab. Decoded records flattened from Produce requests and Fetch responses. Each record back-links to the frame it rode on so you jump from the message to the wire in one click.
- Filter DSL. Wireshark-style:
topic == "orders" && envelope.size > 1024 && headers.tenant == "acme". Compose, autocomplete, save. - Connection profiles. Bootstrap, TLS, SASL — saved locally; passwords in the OS keychain. Last-used profile is pre-selected on launch.
- Expert info — 26 detectors. Kapture flags client + cluster anti-patterns on the wire as you go: overcommit, producer-per-record, tiny batches, rebalance loop, stale-leader producing, mixed
api_version, SASL session-too-short,acks=0, compression-off, non-idempotent producer, producer-instance leak (PagerDuty 2025 shape), transactional zombie, auto-commit cadence, tight fetch polling,INVALID_FETCH_SESSION_EPOCHcascade, throttle pressure (KIP-219), metadata storm, classic rebalance on a KIP-848-ready cluster,MESSAGE_TOO_LARGE,OFFSET_OUT_OF_RANGE, cooperative-sticky churn, commit-during-rebalance, ACL deny storm,UNKNOWN_TOPIC_OR_PARTITIONpoll loop, coordinator churn, and slow consumer poll stall. - Bonus: agent-driven. A local MCP server (
http://127.0.0.1:7878/mcp) exposes capture / filter / inspect tools so an IDE agent (Claude Code, Cursor, Windsurf) can drive Kapture for you. SASL frames redacted before they cross the boundary.
The app self-updates on each launch on every platform.
macOS (Homebrew) — Apple Silicon only:
brew tap conduktor/kapture https://github.com/conduktor/kapture
brew install --cask kapturemacOS will refuse to open the app the first time with a "Kapture is damaged" warning. The app is not yet codesigned with an Apple Developer ID, so Gatekeeper rejects the quarantine attribute. Strip it once and the app launches normally:
xattr -cr /Applications/Kapture.app
macOS (manual) — download Kapture_<version>_aarch64.dmg from Releases, open it, drag Kapture.app to /Applications. Same xattr -cr workaround applies.
Linux — Kapture_<version>_amd64.AppImage (chmod +x and run) or Kapture_<version>_amd64.deb (sudo apt install ./Kapture_*.deb). x86_64 only.
Windows — Kapture_<version>_x64-setup.exe (NSIS installer) or Kapture_<version>_x64_en-US.msi. SmartScreen will warn on first run because the binary is not yet codesigned — click More info → Run anyway.
In the Connection dialog: point Kapture's listener (default 127.0.0.1:9092) at your upstream broker (Confluent Cloud, MSK, your local docker, …). Configure SASL/TLS if needed. Hit Start. Then point any Kafka client at 127.0.0.1:9092 and watch.
The installed macOS/Linux application includes the agent: start a tap session,
pick a local JVM, then click Inject & tap. The same JAR is attached to each
GitHub release for explicit -javaagent startup. When building from source,
build it once with:
cd agents/jvm-tap && mvn -q -DskipTests package
# produces agents/jvm-tap/target/kapture-jvm-agent.jarThen launch your Kafka client with
-javaagent:agents/jvm-tap/target/kapture-jvm-agent.jar (plus
--add-opens java.base/java.nio=ALL-UNNAMED on Java 17+). The agent connects to
Kapture's UDS automatically; frames appear in the same Protocol / Messages /
Expert tabs as proxy mode.
Linux packages also include the OpenSSL eBPF loader. Use Tap eBPF to select a local process; attaching requires root or an equivalent CAP_BPF/CAP_PERFMON policy.
pnpm install && pnpm tauri devThe repository includes a real Apache Kafka Java-client harness with deliberately bad and fixed producer/consumer implementations. It runs outside Kapture and can be observed through either proxy or JVM tap mode:
pnpm stack:up:kafka
pnpm demo:client:build
pnpm demo:client:setup
# Point Kapture's proxy at localhost:29092 first.
pnpm demo:client -- producer-lifecycle bad
pnpm demo:client -- producer-lifecycle fixed
pnpm demo:client -- offset-commit bad
pnpm demo:client -- offset-commit fixedSee the harness README for the expected wire shapes and JVM tap invocation.
- More eBPF taps. OpenSSL/
librdkafkaprocesses are supported on Linux; static Gocrypto/tlsbinaries would require a separate RET-scan tap. - Chaos. Inject latency, error codes, connection drops at the proxy layer to validate client behaviour under adversarial conditions. Toxiproxy, but Kafka-aware.
- Incoming proxy TLS + auth identity. Serve TLS on Kapture's local listeners, then either forward the client's Kafka SASL exchange or authenticate upstream with a configured service account whose ACLs apply.
- Time-travel debugger. Breakpoints by predicate against Kafka Streams / Flink consumers; step through messages; inspect state stores.
Full backlog with shirt sizes in docs/ROADMAP.md. Background and design notes on the JVM tap in the five-part blog series.
See CHANGELOG.md for the full feature inventory grouped by area, plus what's brewing on main.
- Email: kapture@conduktor.io
- Issues: https://github.com/conduktor/kapture/issues
Apache-2.0.
