Skip to content

Feat: Anonymous, opt-in exit telemetry & privacy-first diagnostic reporting (#176) - #190

Open
orang3i wants to merge 7 commits into
karansinghgit:mainfrom
orang3i:main
Open

orang3i wants to merge 7 commits into
karansinghgit:mainfrom
orang3i:main

Conversation

@orang3i

@orang3i orang3i commented Oct 3, 2026 •

Copy link
Copy Markdown

Feat: Anonymous, opt-in exit telemetry & privacy-first diagnostic reporting (#176)

Fixes #176

This PR adds opt-in anonymous telemetry for SpeakType, based on the requirements in #176.

The goal is to collect useful compatibility and reliability data without collecting user content. Telemetry is disabled by default, never includes audio or transcripts, and uses a randomly generated UUID that users can reset at any time.

Users can also inspect the exact payload that would be sent from the app.

What changed

Telemetry settings are now included in SettingsStore, with backward-compatible fallbacks for existing installations.

A random UUID v4 is generated for each installation and used only as an anonymous identifier. It does not use hardware IDs, MAC addresses, usernames, or account information.

Users can regenerate this ID from Settings → Privacy & Diagnostics.

The telemetry payload currently includes:

  • OS name and version
  • CPU architecture
  • Kernel version
  • Linux distribution ID
  • Desktop environment / display server on Linux
  • SpeakType app version
  • Active speech model
  • Dictation success count
  • Dictation failure count
  • Aggregated error strings with counts

No audio, transcripts, typed text, app names, window titles, filenames, dictionary entries, or other user content are collected.

Dictation statistics are tracked through TelemetryStats, which keeps aggregate success/failure counts and groups errors by their error string.

A sample payload looks like this:

{
  "anonymous_id": "e1bd5034-dad4-498e-b6db-81ab89c06120",
  "os_name": "Fedora Linux",
  "os_version": "44",
  "arch": "x86_64",
  "kernel_version": "7.1.9-200.fc44.x86_64",
  "distribution_id": "fedora",
  "desktop_env": "GNOME (Wayland)",
  "app_version": "2.0.0",
  "model": "base",
  "stats": {
    "success_count": 0,
    "fail_count": 0,
    "errors": {}
  }
}

Sending telemetry

Telemetry is sent as JSON using an HTTP POST request.

The default endpoint is:

https://telemetry.speaktype.com/api/v1/telemetry

For development or self-hosted testing, it can be overridden using:

SPEAKTYPE_TELEMETRY_ENDPOINT

or

SPEAKTYPE_TELEMETRY_URL

Requests use User-Agent: SpeakType/<version> and have a 3-second timeout.

Telemetry is sent during application shutdown through clean_exit().

The blocking send runs on a separate thread so it can safely wait for the async HTTP request without causing Tokio runtime re-entry issues during Tauri shutdown handling.

If telemetry is disabled, the app exits normally without sending anything.

UI

A new Privacy & Diagnostics section has been added to Settings.

Users can:

  • Enable or disable telemetry
  • See their current anonymous ID
  • Reset the anonymous ID
  • View the exact telemetry payload as formatted JSON
  • Copy the payload to the clipboard

There is also an optional setting to show the telemetry payload before exit.

For development builds, the sidebar also shows whether telemetry is enabled and provides a quick way to test the shutdown flow.

Privacy

The telemetry is intentionally limited to diagnostic information.

Data Collected? Notes
Voice audio No Never sent
Transcripts / dictated text No Never sent
App or window names No Never collected
Hardware serial numbers / MAC addresses No Only general architecture such as x86_64 or aarch64 is collected
Account or user identity No No account or identity information is collected
Random UUID v4 Yes Generated locally and can be reset at any time
OS / desktop environment Yes Used to diagnose platform-specific issues
App version and model Yes Used to understand compatibility and model-specific issues
Dictation success / failure counts Yes Aggregate counts only
Aggregated error strings Yes Error categories and counts only; no transcript or audio content

The anonymous ID is generated locally and can be rotated by the user at any time.

Main files changed

The main backend work is in:

  • desktop/src-tauri/src/telemetry.rs
  • desktop/src-tauri/src/settings.rs
  • desktop/src-tauri/src/dictation.rs
  • desktop/src-tauri/src/commands.rs
  • desktop/src-tauri/src/lib.rs

Linux desktop and display-server detection was also updated in the platform-specific modules.

Frontend changes include:

  • desktop/src/screens/settings/SettingsScreen.tsx
  • desktop/src/components/TelemetryDialog.tsx
  • desktop/src/lib/api.ts
  • desktop/src/lib/store.tsx

The root README and desktop README were also updated to document how telemetry works and what data is collected.

Testing

cargo test --lib passes with all 79 tests.

Tests cover:

  • Linux payload serialization
  • Omission of Linux-specific fields on macOS and Windows
  • Default endpoint resolution
  • Settings defaults and migration
  • Settings save/load persistence

Frontend checks also pass:

npm run typecheck
npm test

I also manually tested:

  • Enabling and disabling telemetry
  • Settings persistence after restart
  • Resetting the anonymous UUID
  • Viewing the current payload
  • Copying the JSON payload
  • Exit behavior with telemetry enabled
  • Exit behavior with telemetry disabled
  • Exit behavior with the payload preview enabled
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Opt-in usage reports

1 participant