Privacy Policy
Last updated: July 14, 2026
OpenFi ("we," "our," or "the app") is a personal finance application for macOS. This Privacy Policy explains what data we collect, how it's used, and your rights.
Our Core Principle: Local-First
OpenFi is designed so your financial data stays on your device. Your transactions, balances, categories, goals, and reports are stored in a local database on your Mac — not on our servers.
What Data Stays on Your Device
The following data is persisted only on your Mac; we do not keep a server-side ledger or backup of it. Specific excerpts may be transmitted temporarily to the processors described below when you use a connected or AI feature:
- Bank account balances and transaction history
- Spending categories and your personalized taxonomy
- Financial goals, budgets, and monitors
- AI-generated reports and Oracle chat history
- Investment positions you enter manually or import via CSV (positions from a linked brokerage are fetched through Plaid or SnapTrade — see below)
- Net worth calculations and cash flow analysis
What Data Is Shared with Third Parties
To provide core functionality, OpenFi communicates with the following services:
Plaid (Bank Connectivity)
- What's shared: Your bank login credentials (entered directly in Plaid's secure interface — we never see them). Once connected, Plaid sends OpenFi your transaction history (up to 730 days), account balances, and account metadata (account name, type, last four digits of the account number).
- What's NOT shared with OpenFi: Your bank username and password are never sent to OpenFi — they are entered into Plaid's interface and used by Plaid to authenticate with your bank on your behalf.
- Why: To connect your bank accounts and download transactions. Brokerage holdings can be added three ways: CSV upload, Plaid's investments product, or a SnapTrade connection (see the SnapTrade section below).
- Server-side retention: Plaid access tokens are stored in your Mac's Keychain. A copy is also stored in our access-restricted Firestore database (Admin SDK only) while an institution is linked, so Plaid webhooks can be routed and processed. Other Plaid data (transactions and balances) is stored only in your local database on your Mac, not on our servers. Disconnecting the institution or deleting your account requests revocation and removes the normal server mapping. If Plaid is temporarily unavailable, we retain an AES-256-GCM-encrypted cleanup record only until Plaid later confirms that the item is revoked or already gone; see Limited Records Retained After Account Deletion below.
- Right to revoke: You can disconnect a bank in OpenFi's Accounts view at any time. You can also revoke access directly at https://my.plaid.com, Plaid's consumer portal, which shows every app connected to your accounts.
- Plaid's End User Privacy Policy: https://plaid.com/legal/#end-user-privacy-policy (this is the agreement that governs Plaid's handling of your data).
- Note: Plaid settled a $58M class action in 2022 regarding data practices. We use Plaid because it's the industry standard for bank connectivity in the US, but we want you to be aware.
SnapTrade (Brokerage Connectivity)
- What's shared: If you connect a brokerage through SnapTrade (used for brokerages Plaid can't reach, such as Fidelity), SnapTrade sends OpenFi your investment account metadata (account name, type, masked number, institution), your positions/holdings, balances, and cost basis.
- What's NOT shared with OpenFi: Your brokerage username and password are never sent to OpenFi — you enter them directly in SnapTrade's secure Connection Portal, and SnapTrade uses them to authenticate with your brokerage on your behalf.
- Why: To connect investment accounts that Plaid does not support, so your holdings and net worth stay current automatically.
- Server-side handling: SnapTrade requests pass through our authenticated Firebase Cloud Function proxy, which holds the SnapTrade API credentials and a per-user
userSecret. ThatuserSecretis stored in our Firestore database (admin-only access) and is never sent to the app — your Mac only ever sends its own Firebase login token. The holdings data itself is stored in your local database on your Mac. - Right to revoke: You can disconnect SnapTrade from OpenFi's Connect Brokerage screen at any time. Full disconnection or account deletion removes the normal server-side
userSecretrecord. If SnapTrade is temporarily unavailable, a cleanup record containing the pseudonymous Firebase user ID—but nouserSecret—is retained until SnapTrade confirms deletion or reports that the user is already gone. - SnapTrade's Privacy Policy: https://snaptrade.com/privacy
Google Gemini API (AI Features)
- What's shared: Different AI features send different data. Across all features, the following may be sent to Google's Gemini API:
- Transaction merchant names (raw and cleaned), amounts, and dates
- For some features, your current account balances (Oracle answering "what's my balance?")
- Your category taxonomy and prior category corrections, used as context for categorization
- Your onboarding interview answers, used to generate a personalized category taxonomy and to tailor later category review and suggestion features
- The full text of any Oracle question you type (e.g., "how much did I spend on tacos last quarter?")
- For AI asset valuation (manual property/vehicle accounts), the home street address (property) or vehicle year/make/model and VIN you entered. These valuation requests additionally enable Google Search grounding, meaning Gemini may issue web searches derived from that input to estimate current market value.
- Documents you choose to upload (e.g., a PDF account statement when adding or updating a manual account) are sent to Gemini in full for analysis. A statement may itself contain account numbers and other details; OpenFi's prompts only ask the model to return the last 4 digits, and only the extracted fields are stored — on your Mac.
- What's NOT shared: Bank login credentials, routing numbers, and Plaid access tokens are never sent to Gemini. OpenFi never asks Gemini to extract or return a full account number, and never stores one — though a document you upload may itself contain them (see above).
- Why: To power AI-driven categorization, natural language financial queries, and report generation.
- What OpenFi sees server-side (subscription tier only): If you use the subscription tier, your Gemini requests pass through our authenticated Firebase Cloud Function proxy. The proxy is necessary to attach our billed API key and to enforce per-user rate limits. We log request metadata (user ID, model, response status, token counts) but do not retain prompt or response bodies beyond what's required to deliver the response. BYOK users' Gemini requests go directly from their device to Google and never touch our servers.
- Data usage by Google: OpenFi uses the Gemini Developer API (
generativelanguage.googleapis.com). Google's data-use rules depend on whether the API key calling Gemini has billing enabled, not on which endpoint is used.- BYOK (bring your own key) on Google AI Studio's free tier: Google may use your inputs to improve their models and human reviewers may see them. We recommend BYOK users enable billing on their Google AI Studio API key to receive paid-tier protections.
- BYOK with billing enabled, or our subscription tier (server proxy with our billed key): Per Google's Gemini API additional terms for paid services, inputs and outputs are not used to train Google's models and are not subject to human review for service improvement.
- The specific data-use commitments above reflect Google's published policy at the time this document was last updated; please consult the linked terms below for the current authoritative language.
- Their terms: Gemini API Additional Terms (this is the governing agreement for the Gemini Developer API; Vertex AI / Google Cloud Terms of Service do not apply because OpenFi does not use Vertex AI).
Firebase (Authentication, Sync Notifications & Crash Reporting)
- What's shared: Your email address (for authentication and public-beta provisioning), payment/beta status, sync notification triggers, access-restricted Plaid/SnapTrade connection credentials needed for webhook routing and brokerage access, and the minimal signup, deletion-suppression, and cleanup records described below.
- Short-lived identity-mutation lease: To prevent two trusted server flows from creating or changing the same Firebase Auth identity at once, OpenFi writes an access-restricted Firestore lease whose document key is SHA-256 of the normalized email. The lease stores a random owner value, the trusted-flow purpose, and acquisition, expiry, and cleanup timestamps—but not the raw email. It controls concurrency for six minutes and a normally completed flow deletes its own lease immediately. If a process crashes, the lease stops blocking at that unchanged expiry and is scheduled for deletion 24 hours later; Firestore TTL deletion is asynchronous and typically occurs within another 24 hours. A later replacement lease resets its cleanup timestamp.
- Crash reporting: We use Firebase Crashlytics to collect crash reports if the app unexpectedly quits. Crash reporting is enabled by default but can be disabled at any time in Settings → Privacy. The app prevents Crashlytics from auto-starting before it applies that preference, and associates your Firebase user ID only while reporting is enabled after sign-in. Crash reports contain stack traces and device/app state — they do not include your financial data.
- What's NOT shared: Your transaction history, balances, categories, goals, or AI responses. Integration credentials and notification metadata are not used as a server-side copy of your financial ledger.
- Why: To manage your account, verify your purchase, trigger transaction syncs when your bank has new data, and fix crashes.
Public Beta Signup, Cloudflare Turnstile & Resend
- What's collected by OpenFi: If you request public-beta access on our website, we collect your normalized email address, confirmation that you are at least 18, the policy version you accepted, request/verification/provisioning timestamps and status, and later the Firebase UID and App Store Connect tester identifier associated with a provisioned account. We use this information only to verify your mailbox, enforce the cohort limit, provision TestFlight and OpenFi access, send essential beta notices, prevent abuse, and support/deprovision the account. The address is not added to a marketing list.
- Verification and anti-abuse: The one-time email link expires after 30 minutes. Its raw token exists in the email and your browser URL fragment; OpenFi stores only a SHA-256 digest, and the verification page removes the fragment before sending the token to our server. The signup service sends your network IP address to Cloudflare Turnstile for server-side bot verification. OpenFi's signup records do not store the raw IP: we store a keyed HMAC for a two-hour rate-limit window. We also store a SHA-256 digest of the Turnstile response for ten minutes to reject replay. Aggregate daily email-capacity counters contain no email or IP address.
- Cloudflare processing: The Turnstile script loads only after you deliberately submit the signup form. Cloudflare says Turnstile processes signals including IP address, TLS fingerprint, User-Agent, site key, and origin to distinguish humans from bots and to improve its bot detection. See Cloudflare's Turnstile Privacy Addendum.
- Firebase/Google operational request logs: Firebase Hosting and the Google Cloud infrastructure behind our signup functions may generate access-restricted request logs containing ordinary network and request metadata, such as IP address, User-Agent, requested URL or path, HTTP method and status, response size, latency, and trace identifiers. We use these logs for security, abuse prevention, reliability, and incident response. Their retention is controlled by our configurable Google Cloud Logging buckets and settings and may change; we do not promise a fixed log-retention period. OpenFi's application logging is designed not to include the signup email, raw Turnstile response, or verification token. See the Firebase Hosting request-log documentation and Cloud Run logging documentation.
- OpenFi retention: An unverified, expired, or waitlisted signup—including its raw email—is scheduled for deletion 30 days after its latest accepted request. A suppressed signup—which the verification response may describe as requiring manual review—clears its direct identifiers immediately and is scheduled for deletion 30 days after that terminal transition. If automated provisioning instead fails eight times, the stored
manual_reviewsignup retains its protected details and reserved capacity without an automatic TTL until reviewed reconciliation or the program cutoff. At cutoff it becomesprogram_ended, releases the seat, and is scheduled for deletion 30 days later. A legacy/direct invitation that collides with an existing untrusted Firebase credential creates a durable recovery block keyed by SHA-256 of the normalized email; the block stores only a schema version, reason, and timestamp—not the raw email, Firebase UID, or Apple tester ID—and is removed by successful verified public provisioning, account deletion, or audited operator resolution. Hashed verification lookups are scheduled for deletion after 24 hours, hashed Turnstile replay markers after ten minutes, keyed-IP rate records after two hours, and aggregate email budgets after two days. Firestore TTL deletion is not instantaneous and typically occurs within 24 hours after those expiration times. A verified request and its one-way email authorization remain during active provisioning; after provisioning, the signup, authorization, and beta marker remain for the active account lifetime. They are removed through OpenFi account deletion after provisioning or a verified manual privacy request before provisioning. A provisioning-manual-review or cutoff-terminal signup retains a one-way authorization guard until an operator verifies the address is absent from OpenFi's app-scoped Apple tester list; this includes cases where no tester ID was recorded, because Apple enrollment may have succeeded just before persistence failed. The guard prevents the legacy poller from recreating access. The aggregate capacity counter contains no email; a reserved seat remains counted during provisioning manual review and is decremented only through reviewed reconciliation, account deletion, or cutoff terminalization. - Operational email through Resend: We use Resend as our SMTP email processor. Resend receives the recipient and sender address, subject/body (including a one-time verification or password-setup link), and delivery metadata needed to send the message. Resend states that it retains email data for 30 days across its plans, with different arrangements possible for Enterprise, and that account metadata, logs, and API records are stored in the United States; see Resend's retention documentation, region documentation, and Privacy Policy.
Apple TestFlight & App Store Connect (Beta Provisioning)
- What's shared and received: For the website signup flow, we send your verified email address to Apple through the App Store Connect API so Apple can invite you to a private external TestFlight group; Apple returns the tester identifier and enrollment status. For legacy/direct email invitations, our server may also poll App Store Connect for the tester email and identifier. We use them to create or flag the matching OpenFi beta account and send its password-setup message. We keep the Apple public link disabled because public-link testers can be anonymous and cannot be reconciled with this verified-email flow.
- OpenFi retention: While the beta account is active, we store the normalized email, tester identifier, Firebase UID, beta expiry, and provisioning timestamp in access-restricted signup/account records. The active beta marker's document key is SHA-256 of the normalized email, not the email itself. Account deletion removes the public signup/authorization, marker, and active account record and releases its reserved OpenFi capacity; the separate one-way deleted-email suppression described below remains so continued Apple polling cannot silently recreate the account.
- Apple control and retention: Apple separately controls your TestFlight/App Store Connect enrollment and related data under Apple's policies. Deleting OpenFi does not delete Apple's tester record. You can leave the beta in Apple's TestFlight app, contact us to request removal from our App Store Connect tester list, or use Apple's account/privacy controls. Apple may retain its records under its own policy and legal obligations.
- Apple's Privacy Policy: https://www.apple.com/legal/privacy/
Discord (Internal Notifications)
- What's shared: When you make a purchase, we send a notification to a private team Discord channel via a webhook with your email address, the amount paid, and the plan. The legacy/direct Apple beta-polling path also sends the invited email address and setup-email status; the website public-signup worker does not post this notification.
- What's NOT shared: Your financial data, transactions, or any data from your local database.
- Why: So our team is alerted when a customer joins or a legacy/direct beta tester is provisioned.
- Their privacy policy: https://discord.com/privacy
Stripe (Payments)
- What's shared: Your payment information, email address, selected plan, and purchase amount. Card details are processed entirely by Stripe — we never see your card number.
- Why: To process your purchase or subscription payment.
- Server-side retention: We store your Stripe customer identifier, email, entitlement/tier, and payment timestamp with your active OpenFi account. The in-app account-deletion flow deletes the Stripe customer and these active OpenFi records, which immediately ends active billing, subject to the limited suppression and processor records described below. If a Stripe checkout-completion webhook has the same whole-second event timestamp as an account-deletion cutoff, we cannot safely tell which happened first and do not provision automatically. The server-only
stripe_checkout_reviewsrecord stores no raw email; it contains the Stripe event, Checkout Session, and customer identifiers, the event and deletion-cutoff times, and review status needed to refund or reconcile the payment. When orphan-authentication cleanup is required, it may also temporarily contain a pseudonymous Firebase UID, which is removed after the credential is deleted or found to have been adopted by another trusted flow. App clients cannot access the record. It remains until an operator completes an audited refund or reconciliation. The review record is then removed, although the processed Stripe event identifier may remain to prevent duplicate webhook handling. - Their privacy policy: https://stripe.com/privacy
Yahoo Finance (Stock Prices)
- What's shared: Stock ticker symbols from your investment portfolio.
- What's NOT shared: Your holdings, quantities, account information, or stored browser/app cookies. Price requests use a cookieless, ephemeral network session.
- Why: To fetch current stock prices for portfolio valuation.
NHTSA Vehicle API (VIN Decoding)
- What's shared: When you ask OpenFi to decode a vehicle, the full VIN is sent to the U.S. National Highway Traffic Safety Administration's vPIC API. The request also exposes ordinary network information such as your IP address.
- What's NOT shared: Your financial accounts, balances, transactions, or OpenFi login are not sent with the request.
- Why: To look up the vehicle year, make, and model. OpenFi does not retain a server-side copy of the VIN; any vehicle details you save remain in your local database.
- Their privacy policy: https://www.transportation.gov/privacy
Hugging Face (Voice Model Download)
- What's shared: If the speech-recognition model is not already installed, OpenFi downloads it from Hugging Face only after you first use voice input or choose the model-download action in Settings. The download request reveals ordinary network information such as your IP address and the model file requested.
- What's NOT shared: OpenFi does not send your microphone recordings, transcripts, financial data, or account identifier to Hugging Face. Speech recognition runs on your Mac after the model is downloaded.
- Why: To install the model used for voice input after you request that feature.
- Their privacy policy: https://huggingface.co/privacy
Analytics
OpenFi collects minimal, privacy-respecting analytics stored locally on your device:
- Which features you use (e.g., Oracle, Reports, Goals)
- Whether you completed onboarding
- Error counts (no error details or financial data)
This data is stored in your local database and is not transmitted to our servers. Settings can copy a privacy-safe report containing only aggregate counts and app/OS versions, which you may choose to share with us.
Data Security
- Encryption at rest: Your local database is isolated by macOS App Sandbox, and your most sensitive data — bank connection tokens and API keys — is never stored in the database itself (see Credentials below). Your local database is encrypted at rest with SQLCipher (AES-256); the encryption key is a per-environment random key stored in your Mac's Keychain (device-only, not synced to iCloud). We additionally recommend enabling macOS FileVault for full-disk encryption.
- Credentials: API keys and bank connection tokens are stored in the macOS Keychain using a device-only accessibility class so they are not synced to iCloud.
- Network security: All connections to third-party services use HTTPS/TLS encryption.
Limited Records Retained After Account Deletion
Account deletion removes your Firebase authentication account, Stripe customer, active OpenFi account and beta-provisioning records, stored integration credentials, per-user rate-limit records, local financial database, and per-account Keychain credentials. The following narrowly scoped exceptions are retained to prevent deleted accounts from being recreated by delayed automation and to finish revocation requests that a third party has not yet confirmed:
- Account-deletion tombstone:
account_deletions/{Firebase UID}retains the pseudonymous Firebase UID, terminal deletion status, and timestamps indefinitely. It is a server-side write barrier that prevents delayed webhooks or in-flight requests from recreating the deleted account. - Deleted-email suppression:
deleted_account_emails/{SHA-256(normalized email)}retains a one-way SHA-256 lookup key and deletion metadata, but not the raw email address. It has no automatic expiry because App Store Connect polling or delayed payment events could otherwise provision a new account. It is consumed only when a deliberate Stripe checkout produces a completion event whose Stripe event timestamp is unambiguously later than the deletion cutoff; a same-second event goes to the manual-review path described below. It may also be removed after an audited re-enrollment request from the address owner. - Stripe checkout manual review: When a checkout-completion event and deletion cutoff have the same whole-second timestamp,
stripe_checkout_reviewsretains no raw email. It stores the Stripe event, Checkout Session, and customer identifiers, the event and deletion-cutoff times, and review status needed to refund or reconcile the payment; while orphan-authentication cleanup is required, it may temporarily store a pseudonymous Firebase UID that is removed after deletion or trusted-flow adoption is confirmed. App clients cannot access this server-only record. It remains until an operator completes an audited refund or reconciliation and is then removed; the processed Stripe event identifier may remain to prevent duplicate webhook handling. - Plaid cleanup: If Plaid has not confirmed revocation, a cleanup record retains the access token encrypted with AES-256-GCM, keyed hashes of its optional user/item context, and retry metadata. It has no fixed expiry and is deleted only when Plaid confirms removal or reports the token/item is already gone. This prevents a temporary Plaid outage from leaving a live connection unrevoked.
- SnapTrade cleanup: If SnapTrade has not confirmed deletion, a cleanup record retains the pseudonymous Firebase UID and retry metadata, but no SnapTrade
userSecretor brokerage data. It has no fixed expiry and is deleted when SnapTrade confirms deletion or reports that the user is not found. - Local database encryption key: The encrypted database file and its sidecars are destroyed during deletion, along with per-account Plaid tokens and API credentials. The random, environment-scoped SQLCipher encryption key may remain in the macOS Keychain. With the encrypted database ciphertext deleted, that key cannot be used to recover the deleted financial data and may secure a later fresh local database.
- Non-user operational records: Aggregate daily service-capacity counters and processor event identifiers used to prevent duplicate webhook handling may remain. They do not contain OpenFi's copy of your financial ledger. Third-party processors may also retain records under their own policies or legal obligations.
Your Rights
- Export your data: Use File > Export Data to download your transactions, accounts, and net worth history as CSV files at any time.
- Delete your data: Use Settings → Account → Delete Account & All Data to revoke linked institutions and delete your OpenFi authentication account, active public-beta signup/authorization, reserved seat, active server-side product records, per-account integration/API credentials, and local financial database, subject to the narrow retention exceptions above. If you have only requested beta access or the in-app flow is unavailable, contact privacy@tryopenfi.com from the signup/account address to request deletion. Moving the app to Trash by itself does not reliably erase its sandbox container or macOS Keychain items.
- Revoke bank access: You can disconnect bank accounts at any time in the Accounts view. You can also revoke access directly through Plaid's consumer portal at https://my.plaid.com, which shows all apps connected to your accounts and lets you disconnect any of them.
Children's Privacy
OpenFi is not intended for anyone under 18, and the public-beta form requires confirmation that the requester is at least 18. We do not knowingly collect data from children.
Changes to This Policy
We may update this Privacy Policy from time to time. We will notify you of material changes through the app or by email.
Contact
For privacy questions or data deletion requests:
- Email: privacy@tryopenfi.com