A complete, verifiable audit of what RetIQ does — and does not do — with your data, on every platform
Every financial calculation — tax brackets, Social Security estimates, Roth conversion optimization, Monte Carlo simulation — runs locally on your device. On the web it runs in your browser; on iOS it runs inside the app's sandboxed environment. Nothing is sent to a server for processing. Your numbers never leave your device unless you explicitly ask the optional AI Guide a question — and even then, only a plan summary goes to the provider you chose.
All plan data is saved to local storage on your device — localStorage in your browser on the web, or the app's private sandboxed storage on iOS. RetIQ cannot read, retrieve, or access this data remotely. Neither can anyone else.
RetIQ has no user accounts, no login, no analytics, no tracking pixels, no cookies, no fingerprinting. On the web, the only personal information collected is the email address you provide at Stripe checkout, used solely for license key delivery. On iOS, purchases are handled entirely by Apple — we receive no personal information at all. There is no mechanism to correlate your usage across sessions.
On the web, RetIQ installs as a Progressive Web App and works without any internet connection after the first load. On iOS, the app is fully self-contained from installation. This is structural proof that your financial data doesn't need to go anywhere — because it doesn't.
A strict Content-Security-Policy embedded in the app itself tells your browser exactly which domains RetIQ is allowed to contact. Even if the code were somehow modified, your browser would block any unauthorized connections. This is a browser-enforced guarantee, not a promise.
RetIQ is built as a single HTML file with all calculations running in your browser. You can inspect the running code at any time using your browser's View Page Source (Ctrl+U or Cmd+Opt+U) and DevTools. Every calculation is validated against authoritative sources — open the Validation tab to see 3,700+ automated tests with IRS/SSA/CMS citations. Transparency isn't a feature — it's the foundation.
The table below is an exhaustive list of every external domain RetIQ contacts, when it contacts them, and exactly what data is transmitted. There are no hidden endpoints, no background beacons, no telemetry.
| Domain | When | Purpose | Data Sent | Financial Data? |
|---|---|---|---|---|
| retiq-worker.bortvin.workers.dev Cloudflare Worker | App load, purchase & license, and — only if you use it — the AI Guide | Licensing & trial: /create-checkout-session, /start-trial, /verify-token, /validate-license, /verify-session, /redeem-session, /recover-licenseRegulatory data: /regs-current and /state-taxes-current — two small checks at app load that download current federal and state tax constants; nothing about you is sentAI Guide: /ai-proxy — relays your question, a plan summary, and your API key to your chosen AI provider, in memory only, when you submit a question(Plus a Stripe-to-worker webhook and admin-secret-gated maintenance endpoints that your browser never calls.) | License key or trial token for licensing; nothing personal for the regulatory checks. The AI Guide is the one flow that carries financial data: a plan summary, sent only when you ask a question, relayed to your provider and never stored or logged. | Only if you use the AI Guide |
| checkout.stripe.com | Web purchase only | Stripe's payment page processes web purchases. You are redirected to Stripe's domain — RetIQ never sees your credit card number. | Stripe collects payment information under Stripe's Privacy Policy. RetIQ receives only a license key in return. | No |
| Apple StoreKit iOS only | App purchase only | In-app purchases on iOS are verified on-device through Apple's StoreKit 2 framework. Purchase validation happens locally — no server round-trip to RetIQ. | Nothing sent to RetIQ. Apple handles all payment processing. RetIQ receives only a purchase confirmation from StoreKit on-device. | No |
/regs-current (federal tax constants) and /state-taxes-current (state tax overrides), which download current data and send nothing about you. Licensing endpoints fire only when you buy, start a trial, or activate a license. The AI Guide contacts the worker only when you submit a question. There are no analytics services, no advertising networks, no social media trackers, no error-reporting services, no telemetry of any kind. Even fonts are self-hosted — no Google Fonts CDN.
RetIQ includes a strict Content Security Policy (CSP) in its HTML. This is not just a claim — it's a set of rules your browser actively enforces. Even if RetIQ's code were somehow modified, your browser would block any connection that violates these rules:
| CSP Directive | Policy | What It Means |
|---|---|---|
| default-src | 'self' | By default, only load resources from retirementiq.app itself |
| script-src | 'self' 'unsafe-inline' | Only run scripts embedded in the page — no external JS files can be loaded from any domain |
| style-src | 'self' 'unsafe-inline' | Styles from the page itself only — no external CSS from any domain |
| font-src | 'self' | Font files from retirementiq.app only — self-hosted, no CDN |
| connect-src | 'self' | API calls restricted to RetIQ's own worker — no other server can be contacted via fetch/XHR |
| img-src | 'self' data: blob: | Images from the site itself and inline data (icons) |
| object-src | 'none' | No plugins (Flash, Java, etc.) can run — ever |
| frame-src | 'none' | No iframes — no third-party content can be embedded in the page |
| form-action | 'none' | No form submissions — data cannot be POST-ed to any server via HTML forms |
Ctrl+U or Cmd+Opt+U) and look for the <meta http-equiv="Content-Security-Policy"> tag near the top. Your browser reads this tag and blocks any request that violates it — you can see violations in the DevTools Console.
RetIQ includes an optional AI Guide. If you never use it, no plan data is ever transmitted anywhere. When you enable it and submit a question, three things travel to RetIQ's worker in a single request: your question, a summary of your plan (relevant inputs and projection results), and the API key you configured. The worker relays the request to the AI provider you selected — Anthropic, OpenAI, Google, Perplexity, Meta, Groq, DeepSeek, or Mistral — and returns the answer. Everything passes through in memory only: the worker does not log or store your question, your plan summary, your key, or the provider's response.
Your API key lives in your browser's localStorage (one entry per provider you configure) and is used solely to authenticate your own account with your chosen provider. Your provider's privacy policy applies to what you send it. Because the Content Security Policy allows connections only to RetIQ's worker, the app cannot contact any AI provider directly — every AI request is visible in the Network tab as a single call to /ai-proxy.
RetIQ saves your settings and plan data locally on your device. On the web, this uses your browser's localStorage, sandboxed so that only retirementiq.app can read it. On iOS, the app uses its own private sandboxed storage, inaccessible to other apps. Nothing here is ever transmitted automatically — the only exception is the AI Guide flow described above, which you trigger explicitly. Below is every key RetIQ writes (web key names shown — the iOS app stores equivalent data):
| Key | Contains | When Written |
|---|---|---|
| retiq_v1 | Your retirement plan inputs: ages, income, expenses, account balances, Social Security settings, Roth strategy, etc. This is the core of your financial plan. | Every time you change an input (Pro users only) |
| retiq_theme | Your color theme preference: "dawn" (default), "sepia", "dusk", "dark", or "light" | When you toggle the theme |
| retiq_pro | "true" or absent — whether Pro is activated on this device | When you activate a license |
| retiq_license | Your license key string | When you activate a license |
| retiq_trial_token | A trial session token (no personal info) | When you start a trial |
| retiq_trial_start | Timestamp of when your trial began | When you start a trial |
| retiq_pre_survivor_backup | An automatic backup of your plan, taken so you can restore the original after adopting a survivor plan | When you use Adopt Plan in the Survivor Planning Center |
| retiq_textScale | Your text size preference: default, large, or larger | When you cycle the Text Size button |
| retiq_showRealDollars | Whether the Today's-dollars display toggle is on | When you flip the dollars toggle |
| retiq_mode_seen | A one-time flag so the Simple/Full mode introduction isn't repeated | The first time the mode chooser appears |
| retiq_seen_guide | A one-time flag so the Guide introduction isn't repeated | The first time you open the Guide tab |
| retiq_ai_enabled | "true" or absent — whether you've enabled the optional AI Guide | When you enable the AI Guide |
| retiq_ai_provider | Which AI provider you selected | When you choose a provider |
| retiq_ai_key_<provider> | Your API key for that provider — one entry per provider you configure, used solely to authenticate your questions with that provider (see the AI Guide section above) | When you save an API key |
When you save your plan as JSON (Save → Save as JSON), RetIQ can encrypt the file with a password — tick “Protect this file with a password” in the export dialog and choose a passphrase. The encryption happens on your device, before anything leaves it: the file is encrypted with AES-256-GCM, and the key is derived from your password with PBKDF2-SHA256 at 600,000 iterations — the same standard password managers use to protect your vault. The bytes that leave your device are ciphertext; without your password they are meaningless.
Because the key is derived from your password on your device, no recovery is possible by design. If you forget the password, the file cannot be opened — not by you, not by us, not by anyone. There is no backdoor and no “forgot password” flow; that is the point of encrypting it. A protected file exported on iOS opens on the web app, and vice versa. Unprotected HTML and JSON exports work exactly as before — the password lock is strictly optional, for when you want it.
You don't have to trust these claims — you can confirm them in under two minutes using tools built into your browser. These same techniques are used by security professionals to audit web applications.
F12 (or Cmd+Opt+I on Mac), then click the Network tab. In Firefox, press F12 and select Network. In Safari, enable the Develop menu in Preferences, then press Cmd+Opt+I.retirementiq.app — the app itself, its fonts, and its icons — plus at most two small calls to RetIQ's worker: the /regs-current federal tax-constants check and the /state-taxes-current state-tax check, both of which send nothing about you. Nothing else./ai-proxy. All calculations happen locally in your browser.retirementiq.app. You'll see exactly the keys listed above and nothing else.Ctrl+U) and find the Content-Security-Policy meta tag in the <head>. This tells your browser exactly which domains are allowed. In DevTools → Console, any CSP violation would appear as a red error — the browser will block any attempt to send data to an unauthorized domain.Most retirement planning tools store your financial data on their servers, require accounts, and use tracking. Here's how RetIQ's architecture differs:
| Privacy Feature | RetIQ | Typical Cloud-Based Planning Tools |
|---|---|---|
| Where calculations run | Your browser | Their servers |
| Where data is stored | Your device only | Their cloud database |
| Account / login required | No | Yes |
| Email required | At purchase only (license recovery) | Yes (account required) |
| Analytics & tracking | None | Google Analytics, Mixpanel, etc. |
| Works offline | Yes (PWA) | No — requires server |
| Source code visible | Yes — View Page Source in browser | No — server-side code |
| Content Security Policy | Yes — browser-enforced | Rare |
| Data survives if company shuts down | Yes — your files, your device | No — data locked in their servers |
| Vendor can be breached | No financial data to breach | Yes — single point of failure |
| Password-protected export | Yes — AES-256-GCM, encrypted on your device | Rare |
Content-Security-Policy meta tag that tells your browser exactly which domains the app is allowed to contact. This is a browser-enforced guarantee — not just a promise from the developer. The policy restricts scripts to inline-only (no external JS), styles and fonts to 'self' only (self-hosted), API calls to the licensing worker only, and blocks all iframes, plugins, and form submissions. You can inspect it by viewing the page source — it's in the <head>.
/regs-current (federal) and /state-taxes-current (state). The only external origin ever contacted via fetch is RetIQ's own Cloudflare Worker — licensing calls, the regulatory checks, and the user-triggered /ai-proxy relay (the sole flow carrying a plan summary) — plus checkout.stripe.com via redirect during purchase. Fonts are self-hosted. No WebSocket connections, no Server-Sent Events, no background sync, no push notifications.
connect-src restricts API calls to 'self' and RetIQ's own Cloudflare Worker onlyfont-src 'self' restricts fonts to the app's own origin (self-hosted WOFF2 files)style-src 'self' 'unsafe-inline' — no external CSS can be loadedobject-src 'none' blocks all plugins (Flash, Java, etc.)frame-src 'none' blocks all iframesform-action 'none' blocks all form submissionslocalStorage keys shown in the table above are used. No cookies are set. No IndexedDB databases are created. No sessionStorage is used. The Service Worker cache stores only static application assets (HTML, icon images, manifest, and self-hosted font files).
window.open() and document.write(). JSON export is assembled in memory and downloaded via a Blob URL. When you choose a password, the plan is encrypted on-device — AES-256-GCM with a key derived via PBKDF2-SHA256 at 600,000 iterations — before the download begins; the unencrypted plan never leaves the page. Nothing is uploaded during any export, and encrypted files cannot be opened without your password.
Content-Security-Policy via a <meta> tag in the HTML head. This is a browser-enforced restriction — not just a promise — that prevents the app from contacting unauthorized domains, loading external scripts, or exfiltrating data. The policy restricts font-src and style-src to 'self', blocks all form submissions and object embeds, and limits connect-src to the app's own origin and RetIQ's own worker. You can verify this by inspecting the page source or checking the Application → Security panel in DevTools.