A portable command-line client for the JoystickTV bot API — think gh, for
your stream. Authenticate once, then read stream state, post and moderate chat,
and tail the realtime event gateway as JSON so you can wire tips, follows,
and chat into anything that speaks stdin/stdout: jq, a Stream Deck, cron, OBS,
a webhook, or five lines of shell.
It ships as a single self-contained binary — no runtime, no dependencies — for macOS, Linux, and Windows.
# Homebrew (macOS / Linux)
brew install joysticktv/tap/jtv
# Or grab a binary from Releases, or build from source:
go install github.com/joysticktv/jtv@latestexport JTV_CLIENT_ID=<your public bot's OAuth client id>
jtv auth login # opens a browser, does PKCE, saves the session
jtv whoami # who am I + which scopes
jtv say "hello chat 👋"
jtv events tail # live event feed; Ctrl-C to stop| Command | What it does |
|---|---|
jtv auth login / status / logout / introspect |
PKCE login, session info, revoke, RFC 7662 introspection |
jtv whoami |
bot identity + granted scopes |
jtv stream show / set --title|--welcome|--tag |
read / update stream (stream:read / stream:manage) |
jtv say <message> / jtv whisper <user> <message> |
post a chat message / whisper |
jtv mod delete|mute|ban <message-id> / unban <username> |
moderate chat |
jtv followers / subscribers |
username lists |
jtv moderators list|add|remove <username> |
manage channel moderators |
jtv words list|add|remove |
manage banned words |
jtv events tail [--json|--raw] |
stream realtime gateway events |
jtv api <path> [-X METHOD] [--input -] |
call any endpoint, print the raw response |
Each command is one endpoint and one scope — the tool is a thin, honest wrapper over the API.
jtv events tail --json emits one JSON object per event (JSON Lines). That's the
seam where JoystickTV meets the rest of your machine. It speaks both the legacy
v1 and the v2 event envelope (PR #6706) and stays connected across the
token's lifetime, refreshing in the background.
# Read every tip aloud (macOS `say`)
jtv events tail --json | jq -r 'select(.type=="tip") | "\(.username) tipped \(.amount)"' \
| while read -r line; do say "$line"; done
# Flash your smart lights on a tip (any webhook)
jtv events tail --json | jq -c 'select(.type=="tip")' \
| while read -r _; do curl -s "$HUE_WEBHOOK" -d @flash.json; done
# A chat auto-responder in five lines of shell
jtv events tail --json | jq -r 'select(.type=="chat") | .text' \
| while read -r msg; do
[ "$msg" = "!discord" ] && jtv say "Join us: discord.gg/…"
done
# Desktop notification on every follow (Linux)
jtv events tail --json | jq -r 'select(.type=="follow") | .username' \
| while read -r u; do notify-send "New follower" "$u"; done
# Log the whole stream, then get an end-of-stream recap with jq
jtv events tail --json > stream.jsonl
jq -rs 'map(select(.type=="tip")) | "Tips: \(length), Tokens: \(map(.amount)//empty | add)"' stream.jsonl
# Poke any endpoint directly
jtv api api/v1/me/stream | jq .| Variable | Default | Purpose |
|---|---|---|
JTV_CLIENT_ID |
— | your public bot's OAuth client id (or --client-id) |
JTV_BASE_URL |
https://joystick.tv |
target deploy (or --base-url) |
JTV_EVENT_VERSION |
v2 |
gateway envelope version (v1/v2) |
JTV_INSECURE |
off | skip TLS verification for a self-signed dev cert (or auth login --insecure) |
The bot's registered redirect URL must be a loopback: http://127.0.0.1/callback
(http, host 127.0.0.1, path /callback). jtv binds a random loopback port at
runtime, which the server allows per RFC 8252 §7.3.
After jtv auth login, the base URL and client id are saved in the session
(~/.config/jtv/session.json, mode 0600) — later commands need no environment.
go build -o jtv .
go test ./...public-bot-example-pythonandpublic-bot-example-swiftare reference examples — read the source to learn the API.- jtv is a tool — install it and get things done; build on top of it.
{"type":"tip","username":"BusTester","amount":50,"note":"Hydrate"} {"type":"follow","username":"BusTester"} {"type":"chat","username":"nightowl","text":"gg","message_id":"…"} {"type":"follower_count","count":101}