Privacy Policy
Last updated: August 2026
Overview
DuckTerm ("the App") is a mobile SSH client and AI-agent console for iPhone and Android, developed and operated by an independent developer. We take your privacy seriously. This policy explains what data the App accesses, how it is used, and your rights.
SSH Credentials & Private Keys
Passwords, private keys (.pem), passphrases, and other authentication material are stored on your device — in the iOS Keychain on iPhone, and in an encrypted vault backed by the Android Keystore on Android — and are never sent to DuckTerm's servers.
On iOS there are three sync channels. ① DuckTerm's optional iCloud Sync (the in-app toggle) carries connection metadata only — never credentials. ② Credentials are stored in the iCloud-synchronizable section of the Keychain, so if you have enabled system-level iCloud Keychain, Apple replicates them end-to-end encrypted across devices signed into your Apple ID. ③ The push pairing token — the bearer used to authenticate to the DuckTerm push relay — is kept in the synchronizable Keychain and also mirrored via Apple's iCloud key-value storage so your devices pair automatically; this channel is not controlled by the in-app sync toggle. We cannot read the SSH credentials or metadata in ① and ②. The pairing token in ③ is different by design: it is sent to the DuckTerm relay with every push request, and the relay verifies it for authentication and uses it for nothing else.
On Android, if you turn on Google Drive sync, your full connection profiles — including passwords, keys, and jump/proxy credentials — are stored in your Google account's private Drive appDataFolder. Google protects that file in transit and at rest. Optional DuckTerm-managed credential-field encryption is off by default. When enabled, it encrypts credential secret fields with a data-encryption key; the raw key stays in Android Keystore-backed local storage and a passphrase-wrapped recovery copy is stored in Drive. Profile metadata, snippets, selected settings, shortcuts, and themes remain plaintext inside the vault file either way. With credential encryption off, secret fields are also readable to a party holding a valid DuckTerm Drive grant; appDataFolder is hidden from the normal Drive UI.
Server List, Workspaces, Snippets
Saved server entries, workspaces, snippets, and shortcuts are stored locally. If you opt in to sync in Settings: on iOS, iCloud (CloudKit) carries server metadata (including host, port, username, jump/proxy topology, and startup command) plus workspaces; it does not carry snippets, shortcuts, passwords, or private keys. Credentials use iCloud Keychain as described above. On Android, your private Google Drive appDataFolder vault carries full connection profiles and standalone SSH keys, snippets, selected settings, custom shortcuts, and themes. iCloud and Drive do not sync with each other. We operate no separate profile-sync server for this data.
SSH, Mosh, and SFTP Traffic
SSH, Mosh, and SFTP sessions connect directly from your phone or tablet to the host you specify. We do not proxy, decrypt, or store this traffic. If you configure a HTTP/SOCKS5 proxy or ProxyJump bastion, that hop is also user-controlled — DuckTerm only routes packets through what you configure.
Device Permissions
The camera is used only to scan pairing QR codes shown by DuckTerm Hookd on your computer or another DuckTerm device. QR frames are processed on your device and are not saved or uploaded. You can enter the displayed 8-letter pairing code instead of granting camera access.
The system photo picker lets you choose images to upload to your own SSH host or attach to an agent reply. DuckTerm receives only the photos you choose. On iOS you may grant access to selected photos or the full library; if you decline persistent photo-library access, you can still choose individual photos through the system picker.
Face ID can protect the app or an individual server session. Biometric matching is performed by iOS; DuckTerm receives only whether authentication succeeded, not your face data or biometric template.
Microphone and speech-recognition access is requested only when you use voice input for terminal commands or agent replies. The system and optional ChatGPT voice processing paths are described under Voice Input below.
Device & Pairing Identifiers
To operate pairing, push delivery, entitlement checks, and compatible UI updates, DuckTerm may process an APN or FCM push token, a per-install or device identifier, a pairing identity, locale, app version, build number, and release channel. These identifiers are linked to your DuckTerm pairing or store entitlement for app functionality; they are not used for advertising or cross-app tracking.
Push Relay & Interactive Agent Traffic
Agent pairing and the Inbox are available on the Free tier. Platform push delivery starts with a three-day trial and then follows a server-enforced daily Free allowance; Pro removes that delivery limit. Notification content — event kind, session name, a title and a short body preview generated from your agent's activity — passes through APN on iOS or FCM on Android and our push relay, and is retained for delivery and de-duplication, keyed to your pairing identity. It is scheduled for deletion about 60–65 minutes after the relay receives it; cleanup runs every five minutes and at service startup. For lockscreen Live Activities (an iOS-only surface), the relay also keeps the current task state (a prompt summary and the last output line) while you follow the session; that content is blanked within about one minute of you stopping the follow, and any task state is deleted outright about 24 hours after its last event. We use this content only to deliver notifications — never for advertising, profiling, or resale.
The relay also carries interactive traffic between the app and your paired daemon: approvals and AskUser answers, text replies, Live Preview fallback, image fallback, and — only when selected — experimental ChatGPT voice audio. Live Preview and image bytes prefer LAN/P2P when available; P2P may use TURN. The relay forwards reply, image, and audio content in transit rather than storing that plaintext in the notification-event database. Payload hashes plus routing and delivery metadata are stored separately to prevent duplicate delivery and operate paired devices; they do not share the notification-content one-hour retention rule.
Inbox & Snapshots (On-Device)
After delivery, the canonical Inbox records and terminal-session snapshots (tmux, psmux, Herdr, and local shell) are stored on your device; their transport can use the relay paths described above. Free tier Inbox retention is 30 days; Pro tier is unlimited. You can clear individual items or the entire Inbox at any time from Settings.
Voice Input
The default voice input (Mic / Wispr) uses your platform's system speech recognition — the Apple Speech framework on iOS, the device's speech recognizer on Android. Depending on the platform, device, and installed language packs, audio may be processed on-device or by the platform vendor's speech service over the network; check your device settings to require on-device recognition where supported. With the system provider, DuckTerm itself does not record, store, or receive your audio.
An optional, experimental ChatGPT voice provider is also available. When you select it, DuckTerm records a temporary audio clip on your device and sends it through the DuckTerm relay to your paired dev machine, which submits it to ChatGPT (OpenAI) for transcription. The clip is used only for that transcription: the temporary file is deleted after upload and the relay handles the audio transiently without persisting it; OpenAI processes it under its own terms. Use the system provider if you don't want audio sent to the DuckTerm relay or OpenAI — whether the system service itself processes audio over the network depends on your platform, device, and language packs. OpenAI's handling is described at openai.com/policies/privacy-policy.
Crash Reporting (Sentry)
We use Sentry to collect pseudonymous crash and performance diagnostic data. This helps us identify and fix bugs. Diagnostic reports may include:
- Device model and OS version
- App version and build number
- Stack traces from crashes
- Basic performance metrics
Crash reports never include your SSH credentials, passwords, private keys, or terminal buffers. Diagnostic context may include non-credential metadata such as a server hostname and port or a notification title, to make errors reproducible. Sensitive fields (authorization tokens, passwords) are automatically scrubbed before transmission. You can opt out of crash reporting in Settings.
No Advertising, No Tracking
DuckTerm does not include advertising SDKs or cross-app trackers. Services that may process data for the features described here include Apple platform services (such as APN, CloudKit, and Speech), Google platform services (such as FCM and Drive), Sentry, RevenueCat, and — only if you choose ChatGPT voice — OpenAI. They process data only to provide the stated functionality under their applicable privacy and contractual safeguards. We do not sell your data, use it for advertising, or share it for cross-app tracking.
In-App Purchases
Pro tier subscriptions and the lifetime purchase are processed by the store you bought them from — the Apple App Store on iOS, or Google Play on Android. We do not receive or store your payment information. Entitlement validation is handled by RevenueCat, which processes purchase receipts and subscription state on our behalf.
Data Deletion
Deleting a server or stored key inside the app removes its credentials from the Keychain / Keystore vault. Uninstalling the app removes its local databases and files; on iOS, Keychain entries can persist per system behavior (and remain in iCloud Keychain if enabled), so delete servers in the app first if you want credentials fully gone. Cloud-side data must be removed at the source: on iOS use Apple Account → iCloud → Manage Account Storage → DuckTerm; on Android open the Google Drive website → Settings → "Manage apps" and delete DuckTerm's hidden app data. Turning sync off or disconnecting Drive does not delete remote data.
These steps do not yet remove the cross-device push pairing token or every relay-side device registration. Contact duckterm@limitwatch.app to disable a pairing and request deletion of relay-side identifiers. Notification and task content expires under the retention periods described above. Turning off crash reporting in Settings stops new Sentry diagnostic submissions.
Children's Privacy
DuckTerm is not directed at children under the age of 13. We do not knowingly collect personal information from children.
Changes to This Policy
We may update this privacy policy from time to time. Changes will be posted on this page with an updated revision date.
Contact
If you have questions about this privacy policy, contact us at duckterm@limitwatch.app.