Telemetry
Last updated: 31 May 2026
What StreamView sends to LTC Labs, when, and why. Short version: two anonymous events per session — app_launched and app_closed (with a session_summary blob of counts, feature flags, and config) — plus crash reports if the app blows up, plus an update check at most once a day. No personal data, no terminal content, no commands. Every category is independently opt-out-able in Settings → Data → Privacy (and Updates).
What gets sent today
Per app session — one request
StreamView posts once per session to https://www.ltclabs.dev/api/app/update-check at startup. That request carries:
app_launched— the new session is starting (sent immediately on init).- The previous session's
app_closedevent with itssession_summaryblob (below) — queued locally on shutdown and flushed at the next startup.
app_closed.session_summary
A single metadata dictionary attached to app_closed. Counts, enums, booleans only — never names, paths, or content.
| Field | Type | What it is |
|---|---|---|
session_minutes |
int | How long the app was running |
streams_opened |
int | Streams launched this session |
streams_open_at_close |
int | Open at shutdown |
workspaces_count |
int | How many workspaces existed |
most_used_layout |
enum | Grid / MainSidebar / Rows / Single |
used_tail_file |
bool | Did you open a Tail File stream? |
used_screenshot_paste |
bool | Did the screenshot paste fire? |
used_ctrl_tab |
bool | Did the round-robin shortcut fire? |
used_history_search |
bool | Did you search history? |
custom_icon_uploaded |
bool | Any workspace has a custom uploaded image icon? |
mcp_enabled |
bool | Is MCP integration on? |
custom_data_dir_set |
bool | Is the data dir pointing somewhere other than the default? |
theme |
enum | Dark / Light / HighContrast |
default_layout |
enum | The configured default |
default_shell |
enum | PowerShell / Cmd / WSL / Git Bash |
buffer_size |
enum bucket | Scrollback setting (one of four) |
idle_timeout |
enum bucket | Idle threshold (one of four) |
auto_save_sessions |
bool | History recording on/off |
startup_ms |
int | Time from OnStartup to MainWindow shown |
memory_mb_at_close |
int | GC.GetTotalMemory(false) in MB |
template_count |
int | How many saved stream templates |
pty_process_failures |
int | Failed shell launches this session |
tokens_today |
int | Estimated tokens seen in AI-pane badges today (0 if none). No prompts or names. |
Crash reports — only on a crash
Posted to /api/app/crash with the exception type, message, and stack trace. No terminal output, no file paths from your machine, no commands. Gated by Send crash reports.
Update check — at most once per 24 hours
Posted to /api/app/update-check with a random per-machine stagger. Returns the latest version + a support token. Gated by Check for updates automatically.
Support tickets — only when you press Help → Contact Support
Submitted to /api/app/support with what you typed plus the recent app log (no terminal output). You see exactly what's submitted.
What's deliberately not running
- No heartbeat. Earlier builds pinged
/api/app/telemetryevery 5 minutes (~12 req/hour per running user). Disabled in 2026.5.25 — the timer is configured but never started. - No per-action events.
workspace_added/workspace_deleted/stream_added/stream_closed/layout_changedwere removed in 2026.5.25; their useful signal lives in thesession_summaryblob as aggregates instead.
What is never sent
Not in any payload, not in crash reports, not in update checks:
- Terminal output or scroll-back history
- Commands, environment variables, command-lines, working directories, file paths
- Workspace names, stream names, template names, custom-icon filenames
- Window contents, screenshots, keystrokes
- Your email, account info, or anything you typed (outside a support ticket you compose)
How "anonymous" works
The machine is identified by a SHA-256 hash of Windows' MachineGuid (HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuid). The raw GUID never leaves your machine. There is no user account, no login, and no personal info stored on the LTC side.
The hash gives a stable per-machine identifier so distinct machines (DAU / retention) can be counted without revealing whose machine. Different machines = different hashes; reinstalling Windows = a new hash.
Why we send anything at all
- Is anyone using it? Counting distinct hashed machine IDs per day = daily / weekly / monthly active users.
- Do they come back? First-seen vs last-seen of each hash = retention.
- Does the app stay up? Crash reports +
pty_process_failuressurface regressions across releases. - Are we shipping the right defaults?
most_used_layout,theme,default_shell, etc. tell us when the shipped default is wrong (e.g. if everyone changes Theme to Dark, Dark should be default). - Which features matter? The
used_*flags tell us which features earn their keep so we know where to invest next.
Opt-out
Three independent toggles, all on by default, all in Settings:
- Send anonymous usage data (Settings → Data → Privacy) — when OFF, suppresses
app_launched,app_closed, and thesession_summaryblob, and drops any already-queued usage events without transmitting them. The startup/api/app/update-checkrequest still happens (it's how the app gets its support token and license status), but itsTelemetrypayload is null. - Send crash reports (Settings → Data → Privacy) — when OFF, suppresses
/api/app/crash. - Check for updates automatically (Settings → General → Updates) — when OFF, suppresses the periodic update check.
Turning all three off leaves only the startup /api/app/update-check request (no event payload) and the support-ticket endpoint (only fires when you submit a ticket).
Related
Developer notes
Internal implementation reference. The canonical contract lives in ltc-website/srcDotNet/docs/TELEMETRY_CONTRACT.md; this section is the StreamView-specific wiring.
App identifier in payloads: streamview
Wire model (current)
| When | Endpoint |
|---|---|
| Once at startup | POST /api/app/update-check — carries app_launched and any queued events (including the previous session's app_closed + session_summary) |
| On unhandled exception (gated) | POST /api/app/crash |
| At most once per 24h, gated | POST /api/app/update-check (update-check path) |
| When the user submits a support ticket | POST /api/app/support |
No heartbeat. Expect ~1 POST per app session per machine, plus rare crash / update / support requests.
Event vocabulary (current implementation)
| Event | Status |
|---|---|
app_launched |
✓ Required. Plain (no metadata). |
app_closed |
✓ Required. Carries the session_summary metadata blob built by LtcLabsService.EmitAppClosed. |
layout_changed, stream_added, stream_closed, workspace_added, workspace_deleted |
— Removed in 2026.5.25 (replaced by session_summary aggregates) |
probe_nested, probe_direct |
— Removed (internal smoke-test events) |
Implementation checklist
- Trim event vocabulary to
app_launched+app_closed(2026.5.25) - Stop the 5-minute heartbeat (timer remains configured but never started; 2026.5.25)
- Implement
app_closed.session_summary(2026.5.25): counters inLtcLabsService.NoteXxx, snapshot built inEmitAppClosed, MainWindow'sOnClosedfills in workspace/stream/custom-icon extras, App'sOnStartupfeedsstartup_msvia aStopwatch. - Settings → Data → Privacy: Send anonymous usage data + Send crash reports. Check for updates automatically lives under General → Updates. (2026.5.25)
- On-close flush is batched — events queue to disk via
SaveQueuedEventsand flush on nextInitAsync(one POST).
File locations
| Thing | Path |
|---|---|
| Event queue (offline buffer) | %APPDATA%\StreamView\telemetry_queue.json |
| Last update-check timestamp | %LOCALAPPDATA%\StreamView\.last-update-check |
| Logs | %LOCALAPPDATA%\StreamView\streamview.log |
About-dialog disclosure
Standard paragraph from the LTC contract:
StreamView sends diagnostic and service-improvement data to LTC Labs to help us detect and fix bugs, improve stability, and understand which features are working. This data is anonymous — no personal files, content, names, or account identifiers are transmitted. You can opt out of optional usage data in Settings → Data → Privacy. Crash reports are togglable separately so you can keep stability reporting on while opting out of usage data.
Still stuck? In the app, use Help → Contact support, or open a ticket here.