kplay

GitHub Actions Workflow Status Stars Top Language Last Commit Latest Release

kplay (short for “kafka-playground”) lets you inspect messages in a Kafka topic in a simple and deliberate manner. Using it, you can pull one or more messages on demand, decode them based on a configured encoding format, peruse them in a list, persist them to your local filesystem, or forward them to S3.

tui

web

Install

homebrew:

brew install dhth/tap/kplay

go:

go install github.com/dhth/kplay@latest

Or get the binaries directly from a release. Read more about verifying the authenticity of released artifacts here.

⚡️ Usage

kplay offers 4 commands:

  • tui: browse messages in a kafka topic via a TUI
  • serve: browse messages in a kafka topic via a web interface
  • scan: scan a topic for messages, and optionally save them to your local filesystem
  • forward: consume messages from a topic, and forward them to a remote destination

TUI

This will start a TUI which will let you browse messages on demand. You can then browse the message metadata and value in a pager. By default, kplay will consume messages from the earliest possible offset, but you can modify this behaviour by either providing an offset or a timestamp to start consuming messages from.

Usage:
  kplay tui <PROFILE> [flags]

Flags:
  -o, --from-offset string      start consuming messages from this offset; provide a single offset for all partitions (eg. 1000) or specify offsets per partition (e.g., '0:1000,2:1500')
  -t, --from-timestamp string   start consuming messages from this timestamp (in RFC3339 format, e.g., 2006-01-02T15:04:05Z07:00)
  -h, --help                    help for tui
  -O, --output-dir string       directory to persist messages in (default "$HOME/.kplay")
  -p, --persist-messages        whether to start the TUI with the setting "persist messages" ON
  -s, --skip-messages           whether to start the TUI with the setting "skip messages" ON

Global Flags:
  -c, --config-path string   location of kplay's config file (can also be provided via $KPLAY_CONFIG_PATH)
      --debug                whether to only display config picked up by kplay without running it

⌨️ TUI Keymaps

General

KeymapAction
?Show help view
q / <esc>Go back/quit
<ctrl+c>Quit immediately

Message List and Details View

KeymapAction
<tab> / <shift-tab>Switch focus between panes
j / <Down>Select next message / scroll details down
k / <Up>Select previous message / scroll details up
GSelect last message / scroll details to bottom
gSelect first message / scroll details to top
<ctrl+d>Scroll details half page down
<ctrl+u>Scroll details half page up
]Select next message
[Select previous message
nFetch the next message from the topic
NFetch the next 10 messages from the topic
}Fetch the next 100 messages from the topic
sToggle skipping mode
pToggle persist mode
PPersist current message to local filesystem
yCopy message details to clipboard

Serve

This will start kplay’s web interface which will let you browse messages on demand. By default, kplay will consume messages from the earliest possible offset, but you can modify this behaviour by either providing an offset or a timestamp to start consuming messages from.

Usage:
  kplay serve <PROFILE> [flags]

Flags:
  -o, --from-offset string      start consuming messages from this offset; provide a single offset for all partitions (eg. 1000) or specify offsets per partition (e.g., '0:1000,2:1500')
  -t, --from-timestamp string   start consuming messages from this timestamp (in RFC3339 format, e.g., 2006-01-02T15:04:05Z07:00)
  -h, --help                    help for serve
  -O, --open                    whether to open web interface in browser automatically
  -S, --select-on-hover         whether to start the web interface with the setting "select on hover" ON

Global Flags:
  -c, --config-path string   location of kplay's config file (can also be provided via $KPLAY_CONFIG_PATH)
      --debug                whether to only display config picked up by kplay without running it

tui

Scan

This command is useful when you want to view a summary of messages in a Kafka topic (ie, the partition, offset, timestamp, and key of each message), and optionally save the message values to your local filesystem.

Usage:
  kplay scan <PROFILE> [flags]

Flags:
  -b, --batch-size uint         number of messages to fetch per batch (must be greater than 0) (default 100)
  -d, --decode                  whether to decode message values (false is equivalent to 'encodingFormat: raw' in kplay's config) (default true)
  -o, --from-offset string      scan messages from this offset; provide a single offset for all partitions (eg. 1000) or specify offsets per partition (e.g., '0:1000,2:1500')
  -t, --from-timestamp string   scan messages from this timestamp (in RFC3339 format, e.g., 2006-01-02T15:04:05Z07:00)
  -h, --help                    help for scan
  -k, --key-regex string        regex to filter message keys by
  -n, --num-records uint        maximum number of messages to scan (default 1000)
  -O, --output-dir string       directory to save scan results in (default "$HOME/.kplay")
  -s, --save-messages           whether to save kafka messages to the local filesystem

Global Flags:
  -c, --config-path string   location of kplay's config file (can also be provided via $KPLAY_CONFIG_PATH)
      --debug                whether to only display config picked up by kplay without running it

Forward

This command is useful when you want to consume messages in a kafka topic as part of a consumer group, decode them, and forward the decoded contents to a remote destination (AWS S3 is the only supported destination for now).

This command is intended to be run in a long running containerised environment; as such, it accepts configuration via the following environment variables.

Environment VariableDescriptionDefault ValueRange
KPLAY_FORWARD_CONSUMER_GROUPConsumer group to usekplay-forwarder-
KPLAY_FORWARD_FETCH_BATCH_SIZENumber of records to fetch per batch501-1000
KPLAY_FORWARD_NUM_UPLOAD_WORKERSNumber of upload workers501-500
KPLAY_FORWARD_SHUTDOWN_TIMEOUT_MILLISGraceful shutdown timeout in ms3000010000-60000
KPLAY_FORWARD_POLL_FETCH_TIMEOUT_MILLISKafka polling fetch timeout in ms100001000-60000
KPLAY_FORWARD_POLL_SLEEP_MILLISKafka polling sleep interval in ms50000-1800000
KPLAY_FORWARD_UPLOAD_TIMEOUT_MILLISUpload timeout in ms100001000-60000
KPLAY_FORWARD_UPLOAD_REPORTSWhether to upload reports of the messages forwardedfalse-
KPLAY_FORWARD_REPORT_BATCH_SIZEReport batch size50001000-20000
KPLAY_FORWARD_RUN_SERVERWhether to run an HTTP server alongside the forwarderfalse-
KPLAY_FORWARD_SERVER_HOSTHost to run the server on127.0.0.1-
KPLAY_FORWARD_SERVER_PORTPort to run the server on8080-

If needed, this command can also start an HTTP server which can be used for health checks (at /health).

Usage:
  kplay forward <PROFILE>,<PROFILE>,... <DESTINATION> [flags]

Examples:
kplay forward profile-1,profile-2 arn:aws:s3:::bucket-to-forward-messages-to/prefix

Flags:
  -h, --help   help for forward

Global Flags:
  -c, --config-path string   location of kplay's config file (can also be provided via $KPLAY_CONFIG_PATH)
      --debug                whether to only display config picked up by kplay without running it

🔧 Configuration

kplay’s configuration file looks like the following:

profiles:
  - name: json-encoded
    authentication: none
    encodingFormat: json
    brokers:
      - 127.0.0.1:9092
    topic: kplay-test-1

  - name: proto-encoded
    authentication: aws_msk_iam
    encodingFormat: protobuf
    protoConfig:
      descriptorSetFile: path/to/descriptor/set/file.pb
      descriptorName: sample.DescriptorName
    brokers:
      - 127.0.0.1:9092
    topic: kplay-test-2

  - name: raw
    authentication: none
    encodingFormat: raw
    brokers:
      - 127.0.0.1:9092
    topic: kplay-test-3

🔤 Message Encoding

kplay supports decoding messages that are encoded in two data formats: JSON and protobuf. It also supports handling the message bytes as raw data (using the encodingFormat “raw”).

Decoding protobuf encoded messages

For decoding protobuf encoded messages, kplay needs to be provided with a FileDescriptorSet and a descriptor name. Consider a .proto file like the following:

// application_state.proto
syntax = "proto3";

package sample;

message ApplicationState {
  string id = 1; // required
  string colorTheme = 2;
  string backgroundImageUrl = 3;
  string customDomain = 4;
}

A FileDescriptorSet can be generated for this file using the protocol buffer compiler.

protoc application_state.proto \
    --descriptor_set_out=application_state.pb \
    --include_imports

This descriptor set file can then be used in kplay’s config file, alongside the descriptorName “sample.ApplicationState”.

Read more about self describing protocol messages here.

🔑 Authentication

By default, kplay operates under the assumption that brokers do not authenticate requests. Besides this, it supports AWS IAM authentication.

🔐 Verifying release artifacts

In case you get the kplay binary directly from a release, you may want to verify its authenticity. Checksums are applied to all released artifacts, and the resulting checksum file is signed using cosign.

Steps to verify (replace A.B.C in the commands listed below with the version you want):

  1. Download the following files from the release:

    • kplay_A.B.C_checksums.txt
    • kplay_A.B.C_checksums.txt.pem
    • kplay_A.B.C_checksums.txt.sig
  2. Verify the signature:

    cosign verify-blob kplay_A.B.C_checksums.txt \
        --certificate kplay_A.B.C_checksums.txt.pem \
        --signature kplay_A.B.C_checksums.txt.sig \
        --certificate-identity-regexp 'https://github\.com/dhth/kplay/\.github/workflows/.+' \
        --certificate-oidc-issuer "https://token.actions.githubusercontent.com"
    
  3. Download the compressed archive you want, and validate its checksum:

    curl -sSLO https://github.com/dhth/kplay/releases/download/vA.B.C/kplay_A.B.C_linux_amd64.tar.gz
    sha256sum --ignore-missing -c kplay_A.B.C_checksums.txt
    
  4. If checksum validation goes through, uncompress the archive:

    tar -xzf kplay_A.B.C_linux_amd64.tar.gz
    ./kplay
    # profit!
    

Acknowledgements

kplay is built using the awesome TUI framework bubbletea.


Changelog

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

v3.1.0 - Sep 26, 2025

Added

  • Keymaps to scroll details pane from the list pane
  • Keymaps to scroll details pane to the top/bottom

Changed

  • Show raw decoded message when protobuf decoding fails
  • kplay’s TUI won’t be rendered if terminal dimensions are below the required minimum
  • Pressing Ctrl+C will immediately exit the TUI, regardless of the current context

v3.0.0 - Sep 21, 2025

Added

  • A command for scanning messages in a kafka topic, and optionally writing them to the local filesystem
  • A command for consuming messages using one or more profiles, and forwarding them to a remote destination

Changed

  • A starting offset or timestamp can be provided in TUI/web mode, allowing kplay to begin consuming from arbitrary starting points
  • Messages get persisted to $HOME/.kplay by default; this can be overridden via a flag
  • Message details are shown in the TUI/web view regardless of whether decoding is successful

Removed

  • The ability to consume messages as part of a consumer group in TUI and web mode

v2.0.0 - Apr 23, 2025

Added

  • Add web interface

v1.1.0 - Jan 27, 2025

Added

  • Allow consuming messages without committing them
  • Allow persisting a single message

v1.0.0 - Jan 26, 2025

Added

  • Allow dynamic parsing of protobuf encoded messages
  • Allow setting up of “profiles” for various Kafka topics, each with its own details related to brokers, message encoding, authentication, etc.
  • Allow authentication via AWS MSK IAM
  • Show topic and consumer group info in the footer

Changed

  • Message metadata and value are now shown in a single viewport
  • The command line interface; most of the configuration is now taken from the config file

Removed

  • Keymaps to maximize message metadata or value viewport

v0.1.0 - Mar 6, 2024

Added

  • A TUI that allows pulling messages from a kafka topic on demand, and viewing their metadata and value
  • Allow persisting messages to the local filesystem
  • Allow skipping messages