Documentation

Privacy & your data

Guest portfolios use a temporary hosted session plus a backup in your browser. Signed-in portfolios are stored under your hosted account. Desktop portfolios are stored on your disk; cloud AI, tax calculations, optional sharing and hosted synchronization send the data described below. The desktop MCP bridge requires that hosted synchronization.

Using the app as a guest

The Free dashboard works without an account. Guests can import holdings, use portfolio analytics, backtest a trade plan and use the in-app assistant within Free limits: 3 accounts and 50 assets. Social requires a signed-in account; Taxes, external-agent MCP access and investor-group analytics require Pro. See the Free plan boundaries.

As a guest on the hosted app, your data lives in two places:

Practically, that means:

What creating an account changes

An optional email + password account (the Account tab in ⚙ Settings, hosted app only) moves the durable copy of your data to the server:

Starting as a guest, signing up later

You lose nothing by trying the app first: your first sign-in from a browser claims what you built there as a guest.

The story in order:

  1. You open the app as a guest, upload your exports, star favourites, tune settings.
  2. Later you create an account (or sign in for the first time) from that same browser. If the account is still empty and your guest session has data, everything the guest session owns — sources with their transactions, settings, API keys, manual assets, favourites — is moved to the account in one step, all-or-nothing.
  3. Any other device you sign in on now sees the same portfolio, served from the server.

Two edges worth knowing, exactly as implemented:

API keys

On the hosted app, LLM API keys entered in Settings are encrypted at rest on the server and are never stored in the browser — not in localStorage, not in the IndexedDB backup. They belong to your session or account and are wiped with it. If you run the app yourself, keys can also come from the server's own .env or environment (OPENAI_API_KEY / OPENROUTER_API_KEY) — and only then. The hosted app deliberately ignores both, so no session can ever end up spending a key it was not given.

And if you'd rather not send portfolio context to any cloud model: use the desktop app with Ollama or LM Studio. Assistant inference then stays on your computer; the other outbound services below remain separate choices.

What reaches an LLM provider

Ordinary dashboard calculations do not need an LLM. Import parsing, portfolio values, charts, performance, risk and allocation are computed by the portfolio engine. Enabled assistant features — including reports, AI insights, smart search and proactive comments — can call the selected model without a newly typed chat question. Their relevant context follows the provider choice below.

Out of the box, the hosted app answers on our key. So that you are not sent off to obtain an API key before you can try anything, a new session starts on a small free budget against the deployment's own OpenAI key, on gpt-5.6-luna. Be clear about what that means: those calls reach OpenAI exactly like any other — the only difference is whose key pays for them. A quiet donut beside the chat shows how much of the budget is left, and when it runs out the assistant stops rather than quietly falling back to anything else. Enter your own key in ⚙ Settings → Assistant and it takes over at once and is never metered; use a local model on desktop to keep that model request on your computer. The desktop app has no free budget — it starts on a local model.

Whichever of those you are on, using an assistant feature (chat, the one-click reports, AI insights, smart search) sends your question plus the portfolio context the answer needs — holdings with weights and values, performance and risk figures, recent trades, your strategy text, and what's currently on your screen — to the provider behind the model you picked (OpenAI, Anthropic or OpenRouter for cloud models), under your key or, on the free budget, under ours. Your imported raw CSV files are not automatically sent as portfolio context. Attachments you deliberately send in chat are shared with the selected provider; a connected external agent can also access authorized attachments and Assistant context, as described below. What those providers do with request data is governed by their terms, which is exactly why the choice of provider — including a fully local one — is yours.

The desktop app

The native desktop app runs the portfolio engine on your computer and stores its data locally. Market-data requests, cloud AI and opt-in Social sharing have the boundaries described below. Pro users can also choose One synchronized portfolio in Settings → Assistant → External agents. This copies portfolio inputs to the hosted account and keeps web and desktop synchronized while the app is running; it is required for the desktop external-agent bridge. Review both datasets and choose which to keep before synchronization starts. Replaced inputs are backed up and conflicting edits pause sync for review.

Where your data lives

Everything the app knows sits in its own data folder on your disk: a SQLite database with your transactions, sources, settings, manual assets and favourites; the local encryption key protecting any API keys you enter; and the market-data caches. On macOS that folder is ~/Library/Application Support/Fortunest, on Windows %APPDATA%\Fortunest. Back it up and you've backed up the app; deleting it removes the local copy. If you enabled hosted synchronization, Social sharing or made a backup, those copies are separate.

What leaves your machine, and why

What works offline

Essentially all of it: the dashboard, performance, allocation, risk, dividends, correlations, simulations, trade recommendations, Explore, and the assistant on a local model. Price history is cached for a day; when the network is away the app simply keeps serving the last cached prices (and quietly retries in the background), so charts show the world as of your last online session. An offline session cannot fetch fresh market data or price a symbol it has never fetched before — so a fresh install wants one online session to warm its cache, and after that cached analysis remains available. Cloud AI, Social, hosted synchronization/MCP and Pro tax calculations need connectivity. For a mode-by-mode comparison and a local-model check, see the private portfolio tracker guide.

External agents & your permissions — Pro

Connecting Codex, Claude Code or another MCP client gives that named client the permissions you approve at Fortunest sign-in. Authorized reads can include portfolio figures and Assistant context: conversations, attachments, notes, memories, skills and reports. Your chosen agent provider receives this information under its own terms. Fortunest provider API keys and login credentials are never exposed to the agent.

Connection consent sets the client’s permissions; ordinary authorized reads do not require a new approval for each call. Sensitive changes need action approval unless an active permission already covers them. Approve once, reject, allow matching bounded actions, or allow all actions within this connection’s existing permissions for 1 hour or 8 hours. Review activity and revoke connections or permissions in Settings → Assistant → External agents. Desktop-agent approvals and Undo are reviewed in the hosted app. Completed action details and Undo are retained for seven days, with minimal status history for 90 days. Interrupted actions require review instead of being retried automatically. See the connection guide and approval details.

Social & friends

Group portfolios keep the current relative snapshot and three previous publications. Current sharing toggles and friendship/block grants apply to all four at read time. Delete shared data and account deletion remove the history. Own comparison weights stay on your device.

The Social tab is the one place data of yours can become visible to other people — and only ever the people you approved, only ever the sections you ticked, and only ever relative figures. The rules, exactly as built:

Usage analytics & feedback

Recovering a failed app download. If a tab cannot download part of the app, it can reload once in five minutes to fetch the current version. A later failure can recover again after that pause. This uses one timestamp in the tab’s session storage. If that storage is blocked, the original error remains visible; you can reload the page through your browser. Chart range strips also defer resize measurements to the next frame and discard pending work when closed; browser error reporting remains enabled.

The hosted app records anonymous, cookieless usage events (which features are used, how large portfolios are as counts). Only generic values travel — never file names, tickers, amounts, queries, chat or strategy text, or emails. The same anonymous counts are mirrored into cookieless Umami page analytics; this website uses the same cookieless Umami counter and no analytics of any other kind. The only cookie this website ever reads is the pd_signedin marker described above — set by the app when you sign in, deleted when you sign out, carrying the character 1 and nothing else — and it is used for one thing: deciding whether the header should show your avatar. It is never sent anywhere, and if you have no account you have no cookie from us at all.

One visit counter of our own. Both this website and the hosted app send the server a single visit beacon once per browser tab session: a request to /api/visit whose entire content is two words — which surface you are on (site or app) and a device class (desktop, mobile or tablet, worked out in your browser from the screen width and whether it has a touch pointer). That is the whole payload. It carries no cookie (the request is sent without credentials and the server sets none in reply), no identifier of any kind, no page address and no user-agent string; the server does not store your IP address — it keeps only a salted, in-memory hash of it for about a minute to throttle abuse, then forgets it. What is stored is one row per day per surface per device class with a count, so the operator can see "how many visits came from phones this week" and nothing finer. It respects the same opt-out as the analytics: a browser that has opted out with ?notrack sends no beacon either. The desktop app sends none at all.

When an assistant answer fails, is refused, is cut short or comes back empty, the server notes how it ended — which AI provider and model, the reason it stopped, the provider’s own error text and its id for the request, token counts — in its event log, tied to the same anonymous session id, and in its error tracker, which sees only a salted hash of that id. Never your question and never the answer: error reports carry no request contents at all.

Server diagnostics. The hosted service also keeps a size-limited local error journal, separate from usage analytics, so faults can be investigated without the external error tracker. It records timestamps, severity, route patterns, software version identifiers, diagnostic messages and bounded stack locations. It does not collect request bodies, headers, cookies or stack-frame variable values. Common credentials, email addresses and URL queries are scrubbed from diagnostic text. Access is restricted to server operators; older records are overwritten within a 10 MiB storage budget, and excess reports are dropped during an error flood.

One exception exists, and you type it yourself: a message sent through the in-app Feedback button is stored as written (with the email field only if you fill it in), tied to nothing more than the same anonymous session id.

Asking about your data

Write to privacy@fortunest.ai for anything covered on this page — a copy of what is stored about you, a correction, or deletion. The app already does both without a letter — Download my data in the account panel is the copy, and deleting your account removes it; the address is there for the cases that need a person, and for the rights the GDPR gives you beyond the button.

For everything else: support@fortunest.ai for help with the app, security@fortunest.ai for a vulnerability report.