# How FluidVoice Handles and Stores User Data: A Local-First Architecture Guide

> Discover how FluidVoice securely handles and stores user data locally on macOS. Learn about its robust local-first architecture and data privacy.

- Repository: [ALTIC/FluidVoice](https://github.com/altic-dev/FluidVoice)
- Tags: architecture
- Published: 2026-06-30

---

**FluidVoice stores all user data locally on macOS using UserDefaults for settings and transcription history, Keychain for API keys, and the Application Support directory for audio files, ensuring voice data never leaves the device unless explicitly sent to an optional cloud AI provider.**

FluidVoice is a local-first dictation application that prioritizes user privacy by keeping sensitive voice data and transcriptions on-device. Understanding how FluidVoice handles and stores user data reveals a privacy-centric architecture built on standard macOS security frameworks. This analysis examines the specific storage mechanisms, file paths, and data flows implemented in the altic-dev/FluidVoice repository.

## Local-First Privacy Architecture

FluidVoice operates on a strict **local-first** principle: user-generated content remains on the Mac unless the user explicitly opts into a cloud AI provider. The application leverages macOS-native storage solutions—including UserDefaults, Keychain, and sandboxed file directories—to ensure data persistence without compromising security boundaries.

## Application Settings and Preferences Storage

All UI-tweakable values, hot-key bindings, and overlay configurations are managed through a centralized persistence layer.

### UserDefaults Implementation in SettingsStore

The [`SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/SettingsStore.swift) file implements a singleton pattern that wraps `UserDefaults.standard` to persist configuration data. As implemented in [`Sources/Fluid/Persistence/SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Persistence/SettingsStore.swift) (lines 14-19), the store initializes with a private reference to standard defaults:

```swift
private let defaults = UserDefaults.standard

```

This singleton handles all preference mutations, writing simple key-value pairs that immediately synchronize across the app's UI through `NotificationCenter` observers listening for `UserDefaults.didChangeNotification`.

### Legacy Key Migration

The store includes migration logic to normalize legacy preference keys and values during startup, ensuring seamless updates without data loss when users upgrade to newer versions of FluidVoice.

## Secure API Key Management with Keychain

When users enable optional cloud AI providers, authentication credentials receive hardware-backed protection. The `SettingsStore` references `KeychainService.shared` (line 19 in [`SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/SettingsStore.swift)) to read and write API keys exclusively through the macOS Keychain.

Unlike settings stored in UserDefaults, API keys are never written to plaintext disk storage or exposed in source code. The [`KeychainService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/KeychainService.swift) file (located at [`Sources/Fluid/Services/KeychainService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Services/KeychainService.swift)) provides the cryptographic wrapper ensuring these credentials remain inaccessible to other applications or system processes.

## Transcription History Persistence

FluidVoice maintains a complete record of dictation sessions, including raw text, processed output, timestamps, and application context.

### JSON-Encoded UserDefaults Storage

The [`TranscriptionHistoryStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/TranscriptionHistoryStore.swift) file persists transcription entries as a JSON-encoded array under the key `"TranscriptionHistoryEntries"` (lines 51-55):

```swift
// From Sources/Fluid/Persistence/TranscriptionHistoryStore.swift
private let historyKey = "TranscriptionHistoryEntries"

func saveEntries(_ entries: [TranscriptionHistoryEntry]) {
    if let encoded = try? JSONEncoder().encode(entries) {
        UserDefaults.standard.set(encoded, forKey: historyKey)
    }
}

```

Each `TranscriptionHistoryEntry` object contains the raw and processed transcription text, originating application/window information, and optional AI-processing metadata including model names and error messages.

### Optional Audio File Storage

For users who enable audio history, raw recordings are stored outside of UserDefaults to prevent memory bloat. Each entry may carry a `DictationAudioMetadata` reference (lines 27-28 in [`TranscriptionHistoryStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/TranscriptionHistoryStore.swift)) pointing to files saved in the app's sandboxed support directory:

```

~/Library/Application Support/FluidVoice/

```

This separation ensures that lightweight text metadata resides in fast-access UserDefaults while bulky audio files remain in the filesystem, both protected by macOS sandboxing restrictions.

## On-Device AI Model Storage

The optional "Fluid Intelligence" on-device AI model downloads entirely to the user's local machine. Model files reside in `~/Library/Application Support/FluidVoice`, operating completely offline without external server communication unless the user explicitly enables a cloud provider for processing.

## Analytics and Privacy Controls

FluidVoice implements opt-in analytics that respect strict user consent boundaries. According to the README documentation (lines 63-78), the system collects only high-level, non-identifying information such as app version, macOS version, feature-usage flags, and usage ranges.

The [`AnalyticsService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/AnalyticsService.swift) file ([`Sources/Fluid/Analytics/AnalyticsService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Analytics/AnalyticsService.swift)) manages these anonymous counters stored locally in UserDefaults. When users consent via *Settings → Share Anonymous Analytics*, the service transmits aggregated statistics—but never voice data, raw audio, or transcribed text—to telemetry endpoints.

## Data Flow Lifecycle

Understanding how FluidVoice handles and stores user data requires examining the runtime data flow:

1. **Startup**: `SettingsStore.shared` loads preferences from UserDefaults and executes legacy key migrations.
2. **Runtime Changes**: User modifications trigger immediate UserDefaults writes, broadcasting change notifications to update the UI.
3. **Dictation Sessions**: Speech processing generates `TranscriptionHistoryEntry` objects; if AI post-processing occurs, model metadata attaches to the entry before JSON serialization to UserDefaults.
4. **Audio Persistence**: Enabled audio history writes raw files to Application Support while storing lightweight metadata references in the transcription entry.
5. **Analytics Transmission**: Periodic aggregation of local counters occurs only when explicit user consent exists in settings.

## Summary

- **FluidVoice** employs a local-first architecture where user data remains on-device by default according to the altic-dev/FluidVoice source code.
- **UserDefaults** stores settings and JSON-encoded transcription history in [`SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/SettingsStore.swift) and [`TranscriptionHistoryStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/TranscriptionHistoryStore.swift).
- **Keychain** protects cloud provider API keys via `KeychainService`, never persisting credentials to plaintext disk storage.
- **Audio files** reside in the sandboxed `~/Library/Application Support/FluidVoice` directory when history is enabled.
- **Analytics** operate on an opt-in basis, transmitting only anonymous aggregated counters without voice or text content.
- All storage mechanisms leverage native macOS security boundaries and application sandboxing.

## Frequently Asked Questions

### Does FluidVoice send my voice recordings to the cloud?

No. FluidVoice processes audio locally using on-device models stored in your Application Support directory. Voice data only leaves your Mac if you explicitly enable a third-party cloud AI provider and initiate processing. Raw audio files remain in `~/Library/Application Support/FluidVoice` unless you delete them or disable audio history in settings.

### Where does FluidVoice store my transcription history?

Transcription history is stored as JSON-encoded data in UserDefaults under the key `"TranscriptionHistoryEntries"`, managed by [`TranscriptionHistoryStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/TranscriptionHistoryStore.swift). The actual text content, timestamps, and application context persist on your device only, with optional audio files stored separately in the sandboxed Application Support folder.

### How secure are my API keys in FluidVoice?

API keys for optional cloud providers are stored exclusively in the macOS Keychain through [`KeychainService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/KeychainService.swift). They are never written to UserDefaults, plaintext files, or exposed in source code, leveraging Apple's hardware-backed encryption for credential protection against other applications or system processes.

### Can I completely disable data collection in FluidVoice?

Yes. FluidVoice requires explicit opt-in for analytics collection via *Settings → Share Anonymous Analytics*. You can disable this at any time, and the application does not collect telemetry by default. No voice data, raw audio, or transcribed text is ever transmitted for analytics purposes regardless of your settings.