How FluidVoice Handles Analytics Privacy: Anonymous Usage Tracking Explained

FluidVoice collects only anonymous, low-cardinality usage metrics while deliberately excluding all user-generated content and personally identifying information from its analytics pipeline.

The open-source macOS dictation app FluidVoice (available at altic-dev/FluidVoice) implements a privacy-first analytics architecture that balances diagnostic utility with strict data minimization. Rather than capturing transcription text or personal identifiers, the system records only aggregate hardware statistics and feature usage patterns to help developers improve performance without compromising user confidentiality.

The Analytics Pipeline Architecture

At the core of FluidVoice's privacy strategy is a lightweight, non-blocking event pipeline implemented in Sources/Fluid/Analytics/AnalyticsService.swift.

In-Memory Queue and Fire-and-Forget Design

The service maintains an in-memory ring buffer that automatically drops the oldest events when capacity is reached, ensuring no persistent local cache of analytics data exists. Batched events flush in the background using fire-and-forget network requests, preventing any UI thread blocking during capture operations.

According to the source code in AnalyticsService.swift (lines 4-8), the pipeline uses asynchronous dispatch queues to serialize JSON payloads and transmit them to a configurable PostHog endpoint without interfering with transcription workflows.

What Data FluidVoice Actually Collects

FluidVoice explicitly excludes high-risk data categories, capturing only static hardware attributes and feature flags that contain no semantic content.

Anonymous Hardware Snapshots

Each installation transmits a one-time hardware fingerprint gathered at startup, including CPU family, chip model, and hardware model identifier. These values remain constant for the session and attach to every subsequent event (lines 103-114 in AnalyticsService.swift).

Common Event Properties

Every captured event automatically includes generic metadata defined in lines 55-94 of AnalyticsService.swift:

  • Application version and build number
  • macOS version and CPU architecture
  • User-controlled settings (AI processing enabled, streaming preview active, hot-key mode status)

The Anonymous Install ID

Rather than linking activity to Apple IDs or system serial numbers, FluidVoice generates a random anonymous install ID via AnalyticsIdentityStore.shared.anonymousInstallID. This identifier persists across app launches but cannot be correlated with personal accounts or other applications, as implemented in Sources/Fluid/Analytics/AnalyticsIdentityStore.swift.

FluidVoice provides granular, immediate control over analytics participation with transparent UI explanations.

The Opt-Out Toggle

The "Share Anonymous Analytics" preference resides in Sources/Fluid/Persistence/SettingsStore.swift (lines 1274-1275) and defaults to ON for existing installations. This default-true semantics ensures users upgrading to analytics-enabled versions do not silently opt-out, while new users can immediately disable the feature.

When users toggle analytics off in SettingsView.swift (line 1873), the app fires an analytics_consent_changed event and instantly purges the in-memory queue, guaranteeing no stale events transmit after opt-out. If analytics is disabled, AnalyticsService clears the queue immediately and halts all network traffic (lines 18-30 and 95-102).

Transparent Privacy Explanations

The dedicated AnalyticsPrivacyView.swift (lines 13-50) presents a clear breakdown of collected data categories, explicitly stating that transcription content remains local and private. This view binds directly to the analytics enabled state, providing real-time visual confirmation of the user's privacy settings.

Implementation Code Examples

The following Swift patterns demonstrate how FluidVoice implements its privacy-preserving capture mechanism:

// Enable or disable analytics from user preferences
AnalyticsService.shared.setEnabled(true)   // Opt-in
AnalyticsService.shared.setEnabled(false)  // Immediate opt-out with queue purge

// Capture a generic feature usage event (no transcription content)
AnalyticsService.shared.capture(.transcriptionCompleted,
                                properties: ["duration_ms": 1234])

// Automatically injected properties include:
// "app_version", "os_version", "hardware_arch_family", "cpu_model"

When analytics is disabled, the service returns early from capture methods, ensuring zero network overhead and no serialization of event data.

Summary

  • Data minimization: FluidVoice captures only hardware models, app versions, and feature flags—never transcription text or user identity.
  • Anonymous identifiers: The anonymousInstallID in AnalyticsIdentityStore provides session correlation without personal linkage.
  • Non-blocking architecture: The in-memory queue and background flushing in AnalyticsService prevent performance impact.
  • Immediate opt-out: Toggling analytics off purges pending events instantly and stops all network requests.
  • Transparency: AnalyticsPrivacyView explicitly documents the limited data collection scope.

Frequently Asked Questions

Does FluidVoice collect my transcription data?

No. The analytics pipeline explicitly excludes all user-generated content. According to AnalyticsService.swift, captured events contain only metadata like duration_ms or feature flags, while transcription text remains strictly local to the device and never serializes into analytics payloads.

What is the anonymous install ID and can it identify me?

The anonymous install ID is a random UUID generated by AnalyticsIdentityStore that persists across app launches but contains no reference to your Apple ID, email, or hardware serial numbers. As implemented in the source code, this identifier exists solely to distinguish unique installations for aggregate usage statistics without enabling personal tracking.

How do I disable analytics in FluidVoice?

Navigate to Settings and toggle off "Share Anonymous Analytics." When disabled via SettingsView.swift (line 1873), the app immediately fires an analytics_consent_changed event, purges the in-memory event queue, and ceases all network transmission to the PostHog endpoint. No restart is required.

Why is analytics enabled by default?

The default-ON setting in SettingsStore.swift (lines 1274-1275) ensures that existing users who upgrade to versions containing analytics do not silently opt-out, maintaining statistical continuity for development decisions. New users retain full control to disable the feature immediately upon installation, and the AnalyticsPrivacyView clearly discloses the data collection scope before any transmission occurs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →