Share a terminal as a browser URL, or record a local terminal command to MP4/WebM.
ttyl gives you:
- live terminal streaming with read-only and read-write links
- a browser viewer that keeps the source terminal grid stable
- a small dashboard/admin console for managing viewers
- optional password protection
- local terminal recording without browser automation
- self-hosted Node relay or Cloudflare Worker deployment
npm install -g @rcx86/ttylThis installs the ttyl CLI.
Run a local relay:
ttyl serveIn another terminal, save that relay as your default:
ttyl init --server http://localhost:8080Start sharing your terminal:
ttyl streamttyl stream prints:
- a read-write URL
- a view-only URL
- a dashboard URL
Start a normal interactive stream:
ttyl streamStart a view-only stream:
ttyl stream --view-onlyAdd a password prompt:
ttyl stream --passwordPin the terminal grid instead of following your local terminal size:
ttyl stream --size 100x30By default, the source terminal owns the PTY size. Browser viewers do not resize the command; they can switch between readable, fit, and 1:1 viewing modes.
If you lose the URLs, print active session links from another terminal:
ttyl linksStop a running stream:
ttyl stop
ttyl stop <session-id>Record a local command to MP4:
ttyl record --output demo.mp4 -- npm testRecord a shell session:
ttyl record --output demo.mp4 -- bashUse a built-in preset:
ttyl record --preset presentation --output demo.mp4 -- npm testAvailable presets:
ttyl: default ttyl viewer stylepresentation: larger text and higher FPScompact: smaller outputclassic: plain black terminal style
Recording uses your current terminal size by default. Pin the recorded grid when you need stable dimensions:
ttyl record --preset presentation --size 100x30 --output demo.mp4 -- npm testUseful recording flags:
ttyl record --preset compact --fps 24 --font-size 14 --output demo.webm -- bash
ttyl record --font-family "JetBrains Mono" --output demo.mp4 -- npm testMP4 output uses ffmpeg with H.264. WebM output uses VP9.
Ttylvault archives contain the recording manifest, raw PTY event log, and searchable transcript:
ttyl record --vault --output demo.mp4 -- npm test
ttyl record --vault --vault-redact 'token=[^ ]+' --output demo.mp4 -- npm testArchive a live stream:
ttyl stream --vaultVault commands:
ttyl vault list
ttyl vault info <vault-id-or-path>
ttyl vault search "failed" --before 120 --after 120
ttyl vault replay <vault-id-or-path> --speed 2
ttyl vault export <vault-id-or-path> --format asciicast --output demo.cast
ttyl vault rm <vault-id-or-path>Share, protect, and revoke a vault through a relay:
ttyl vault share <vault-id-or-path> --server https://relay.example --lifetime 8h
ttyl vault share <vault-id-or-path> --server https://relay.example --private
ttyl vault revoke '<share-admin-link>'Encrypt a local vault export:
ttyl vault encrypt <vault-id-or-path> --output demo.ttylvault.enc --passphrase '<passphrase>'
ttyl vault decrypt demo.ttylvault.enc --output - --passphrase '<passphrase>'Run the relay with Node:
ttyl serve
ttyl serve --port 9000 --host 127.0.0.1
PORT=9000 HOST=127.0.0.1 ttyl serveDeploy the relay to Cloudflare Workers:
git clone https://github.com/rcx86/ttyl.git
cd ttyl
npm install
npx wrangler login
npm run deployWhen running behind a TLS reverse proxy, set TRUST_PROXY=1 so rate limiting
uses X-Forwarded-For correctly.
ttyl init --server <url> writes the default relay URL to:
~/.config/ttyl/config.json
You can also set recording defaults there:
{
"server": "http://localhost:8080",
"record": {
"preset": "presentation",
"output": "demo.mp4",
"size": "100x30",
"fps": 24,
"fontSize": 15,
"fontFamily": "JetBrains Mono"
}
}Command-line flags override config values for that run.
Open the dashboard URL in a browser, or use the CLI admin console:
ttyl admin '<dashboard-url>'Admin commands include kick, lock, unlock, password, password clear,
and quit.
npm install
npm run dev # Cloudflare Worker dev server
npm run dev:node # Node relay with auto-reload
npm test
npm run typecheckRun end-to-end tests against a running relay:
node test/e2e.mjs http://127.0.0.1:8787npm publishing is tag-driven. Bump package.json, commit the change, then push
a matching tag:
git tag v0.1.5
git push origin HEAD v0.1.5The GitHub workflow checks that the tag matches package.json before publishing
to npm. A version bump without the tag does not publish.