Privacy-first iPhone voice-to-text app with explicit recording, OpenRouter zero-retention routing, and a familiar custom keyboard.
  • Swift 97.9%
  • Ruby 2.1%
Find a file
pb736 2c9820a992 sanitization-publish: export sanitized main
Source-commit: d7bd74293fdb1d521b350b14999a1f93ba1b0ca9
2026-07-28 20:23:53 +01:00
docs/screenshots sanitization-publish: export sanitized main 2026-07-28 20:21:20 +01:00
Scripts sanitization-publish: export sanitized main 2026-07-28 19:55:57 +01:00
VoiceType.xcodeproj sanitization-publish: export sanitized main 2026-07-28 19:55:57 +01:00
VoiceTypeApp sanitization-publish: export sanitized main 2026-07-28 19:55:57 +01:00
VoiceTypeKeyboard sanitization-publish: export sanitized main 2026-07-28 19:55:57 +01:00
VoiceTypeKeyboardTests sanitization-publish: export sanitized main 2026-07-28 19:55:57 +01:00
VoiceTypeShared sanitization-publish: export sanitized main 2026-07-28 19:55:57 +01:00
VoiceTypeTests sanitization-publish: export sanitized main 2026-07-28 19:55:57 +01:00
VoiceTypeUITests sanitization-publish: export sanitized main 2026-07-28 19:55:57 +01:00
LICENSE sanitization-publish: export sanitized main 2026-07-28 20:21:20 +01:00
README.md sanitization-publish: export sanitized main 2026-07-28 20:23:53 +01:00

VoiceType app icon

VoiceType

Private voice-to-text for iPhone.
Record for up to five minutes, turn speech into useful text, and take it into the apps where you write.

VoiceType transcribes finished recordings through your own OpenRouter account. Polish is optional, translation is explicit, and every result can be copied, kept as a titled memo, or inserted from a familiar English keyboard.

1. Record with control 2. Use the result 3. Keep what matters
VoiceType recording screen with Pause, Restart, and Transcribe controls Completed VoiceType transcript with Copy and Save Memo actions VoiceType memo library with saved and expiring transcriptions
Pause, restart, or transcribe without leaving the recording screen. Copy clean text, save it, or make it available to the keyboard. Recent text expires automatically; named memos stay until you delete them.

A keyboard that still feels like a keyboard

VoiceType English QWERTY keyboard with a violet microphone key

VoiceType keeps the standard four-row English QWERTY layout and adds one violet microphone key. In compatible text fields, tap it to insert the latest VoiceType transcript. The keyboard has no network client, does not request Full Access, and does not inspect or retain what you type.

The useful parts, without extra machinery

  • Deliberate recording: capture begins only after an explicit tap or the recording Shortcut; Pause, Restart, and Transcribe remain visible.
  • Text that fits the task: keep the raw transcript, apply conservative punctuation and grammar polish, or opt into a selected translation language.
  • Short-term history or lasting memos: recent transcripts show their deletion timer; Save as Memo adds a title and removes the expiry.
  • Your provider account: choose an eligible speech model and a capable, lower-cost text model through OpenRouter's zero-retention routes.

Project status

main contains the complete iOS implementation candidate: a native SwiftUI app, UIKit keyboard extension, local transcript library, OpenRouter integration, App Shortcut, privacy manifests, and deterministic tests.

  • 134 of 134 tests pass on an iPhone 17 Pro Simulator running iOS 26.5.
  • Current Simulator captures above use deterministic fabricated text and no API credential or personal content.
  • Real Simulator microphone capture and the exact synthetic OpenRouter transcription and translation routes have passed.
  • Generic-iOS Release build, static analysis, unsigned archive, privacy audit, and deterministic project generation pass.
  • Physical-device signing, App Group insertion, microphone/provider timing, Shortcut, largest Dynamic Type, RTL, and constrained-keyboard acceptance remain owner-assisted gates.

Privacy boundary

  • Recording starts only after the user taps Record or explicitly runs the VoiceType recording Shortcut. Normal launch never records.
  • Audio and transcript processing contact only https://openrouter.ai.
  • OpenRouter's dedicated multipart transcription API does not apply per-request provider-routing fields. Immediately before every audio upload, VoiceType refreshes the selected model's complete endpoint list and OpenRouter's current ZDR endpoint list, requires every exact model endpoint to appear in the ZDR set, and sends nothing when that proof is incomplete.
  • Optional polish and opt-in translation use OpenRouter chat completion with provider.zdr = true, provider.data_collection = "deny", and provider.require_parameters = true. A conservative local validator rejects every token insertion, deletion, substitution, or reordering—including names, numbers, dates, negation, tone, or unexpected language changes—and falls back to the raw transcript. Translation is a distinct, off-by-default mode: the selected ISO target language is included in a complete-text, meaning-preserving translation instruction, and local checks reject empty, extreme-length, or number-changing output.
  • The OpenRouter key is stored only in the main app's non-synchronizing, device-only Keychain. It is never shared with the keyboard.
  • Retry audio is file-protected. By default, failed-request audio may survive for less than one hour and is excluded from backup. “Never persist” instead uses a protected temporary file for the active process and clears remnants when the retry store is next created.
  • The App Group stores at most one versioned final transcript with creation, expiry, and raw/polished/fallback state. Its default lifetime is 24 hours.
  • A separate schema-versioned app-only library stores successful transcripts with complete file protection and backup exclusion. Unsaved records use the selected expiry (24 hours by default); Save as Memo removes that expiry, adds an editable local title, and retains the exact read-only text until explicit deletion or Clear Local Data. This library never enters the App Group or keyboard target.
  • The keyboard reads only that VoiceType-owned record. It has no network, microphone, Keychain, clipboard-read, analytics, or host-document inspection code, keeps no typed-text buffer or history, and revalidates the record immediately before an explicit ready-state microphone tap inserts it.
  • No VoiceType accounts, analytics, advertising, tracking, cloud sync, hidden recording, or remote service beyond OpenRouter are included.

Build

Requirements:

  • macOS with Xcode 26.6 or a compatible newer release;
  • iOS 18-or-later Simulator or iPhone;
  • Ruby with the xcodeproj gem only when regenerating the checked-in project.

Open VoiceType.xcodeproj and use the shared VoiceType scheme, or build the checked-in project from Terminal:

xcodebuild build \
  -project VoiceType.xcodeproj \
  -scheme VoiceType \
  -configuration Debug \
  -destination 'generic/platform=iOS Simulator'

The project generator is deterministic:

ruby Scripts/generate_project.rb

Regeneration rewrites VoiceType.xcodeproj; review the resulting diff before keeping it. No API credential or signing secret belongs in the project, arguments, environment, fixtures, or repository.

Install On An iPhone Without A Paid Membership

A paid Apple Developer Program membership is not needed for an initial private device build. A free Personal Team profile lasts seven days, after which the app must be rebuilt and reinstalled from Xcode. It does not provide TestFlight or App Store distribution. Apple's current iOS capability matrix lists App Groups for free Apple Developer accounts, so the app-to-keyboard design is compatible with this path; Xcode must still provision the matching entitlement for both targets on the owner's account and phone.

  1. In Xcode, open Xcode > Settings > Accounts, add your Apple Account, and complete any Apple sign-in or agreement prompts.
  2. Open VoiceType.xcodeproj. Select the project, then the VoiceType target. Under Signing & Capabilities, enable automatic signing and select your Personal Team.
  3. Repeat the same team selection for VoiceTypeKeyboard. Both targets must retain the same App Group, group.com.pb736.voicetype.
  4. If Xcode reports that an identifier is unavailable, choose one unique reverse-DNS base and update all of these together before regenerating the project: Scripts/generate_project.rb, VoiceTypeShared/AppGroup/AppGroup.swift, VoiceTypeApp/Resources/VoiceType.entitlements, and VoiceTypeKeyboard/Resources/VoiceTypeKeyboard.entitlements. Keep the keyboard bundle ID as a child of the app ID and the App Group identical in both entitlements.
  5. Connect, unlock, and trust the iPhone. Select it as the run destination. Enable Developer Mode if iOS/Xcode requests it, then build and run.
  6. In VoiceType, approve microphone access and open Settings. The OpenRouter API Key section appears first; enter the user's own key and use Save and Validate. VoiceType keeps an existing valid key if a replacement fails validation.
  7. On the iPhone, open Settings > General > Keyboard > Keyboards > Add New Keyboard, then select VoiceType.
  8. VoiceType does not request Allow Full Access. The keyboard reads the VoiceType-owned latest result and inserts it without network access or shared-container writes; clearing remains in the main app.
  9. In a compatible text field, switch to VoiceType to use its system-adaptive English QWERTY layout. Open VoiceType manually, record and transcribe, then return to the field. When the latest transcript is ready, an explicit tap on the violet microphone revalidates and inserts it; with no ready transcript, the same key provides the record-in-app accessibility guidance.

Third-party keyboards may not appear in secure fields, phone-pad fields, or apps that disable custom keyboards. iOS custom-keyboard APIs do not provide a supported way to launch the containing app, so the microphone control cannot open VoiceType directly in an App-Store-safe build. VoiceType also cannot identify or automatically return to the previous app.

When the seven-day profile expires, reconnect the phone, select the same Personal Team, and build/run again. Xcode will refresh the temporary provisioning. Apple currently documents Personal Team limits of 10 App IDs, 3 registered devices, and 3 installed apps per device.

Official references:

Copyright © 2026 Pouya Baniasadi. All rights reserved.

VoiceType is publicly viewable source, not open-source software. No permission to use, copy, modify, distribute, deploy, or create derivative works is granted without prior written permission. See LICENSE for the full proprietary notice.