The Moflow data charter

The promise Moflow is built on, in plain language. Every claim on this page describes code that has shipped, and the table below lists what leaves your device. The legal document that sits alongside it is the privacy policy.

Your data is encrypted in transit and encrypted at rest, and we read it only to run Moflow for you. It is never sold, never used for advertising, never turned into a profile, and deleted in a click.

Your ledger — what we hold, and what we do with it

Your accounts, balances, transfers, holdings, snapshot history, goals, reasons, and money profile (income and burn rate) are your ledger.

  • Before you have an account, there is no server copy of your ledger. It lives in your browser's local storage on your device — you don't even need an account to use Moflow. The bare ticker symbols you hold still reach our server, with no identity and no amounts; that is its own row in the table below.
  • Turning sync on is what creates a server copy of your ledger. Until you do, it is written into this browser's storage and stays there, so an outage of ours cannot take it away from you. An assistant you connect and allow to make changes can also write to that copy.
  • With sync on, we hold your ledger as records, and we can read them. One document per account, transfer, holding, snapshot, goal and reason, so a second device of yours opens the ledger this one wrote. It is encrypted in transit, and encrypted at rest by the database that stores it.
  • We read it to run Moflow for you, and for nothing else. Not to sell, not to advertise, not to build a profile of you, not to train anything, and not to hand to anyone who is not operating the service. Any other purpose would need your consent, and this page changes before it does.
  • We cannot reset your sync passphrase. It is what unlocks sync on a device, we never receive it, and no recovery mail exists. It does not gate our own ability to read your records — this line says so rather than implying otherwise.
  • You can delete the cloud copy at any time — Settings → Sync → “Turn off & delete cloud copy”.
  • If you stop paying, the copy is kept 30 days and then deleted. A lapse drops you back to local-only: your on-device data is untouched and re-subscribing inside the window resumes sync with nothing lost. A daily scheduled job deletes the cloud copy of accounts lapsed longer than 30 days, measured from the instant billing recorded the lapse — a failed card that Stripe is still retrying never starts the clock. You get a push notification about a week before the deadline, and only the server copy goes: the account, the local ledger and the ability to re-subscribe all survive.

Everything that leaves your device

Beyond your ledger, here is every request Moflow makes, so nothing is implied away:

WhatWhenContains
Changed ledger recordsSync onThe accounts, transfers, holdings, snapshots, goals and reasons you changed, and your ledger settings — currency, allocation targets and your money profile (income and burn rate).
A product momentSigned in — creating your account, adding your first account, and each snapshot you confirmWhich moment, as one word from a fixed list, with your account and the time our server stamps on it. Nothing from your ledger: the document has three fields and no fourth, so there is nowhere to put an amount, a balance, an account name, a ticker or a date you entered. It is how we see whether people who sign up come back for a second and a third month.
Sign-in credentialsWhen you sign in or create an accountEmail + password, or your Google identity. Identity only — never financial data.
Payment detailsWhen you open the plan page, and when you subscribe to Plus or Pro or open the billing portalYour card never reaches our server. Upgrading sends your browser to Stripe's own hosted checkout, and everything you enter there — card number, name, billing address — goes to Stripe. What comes back to us is Stripe telling our server that a subscription started, renewed, or ended; our server keeps that as your subscription record: whether the account is entitled, which plan, where the subscription stands — including a payment that failed and is being retried — and Stripe's customer and subscription identifiers. We never see or store a card number, an amount, or your billing name, and none of it reaches a log line. These are also the requests in this table that carry your identity: opening the plan page asks our server what your own subscription is — whether a trial is running and when it ends — and subscribing or opening the portal sends you to Stripe under your own account. Each sends your sign-in token to our own server, so the answer is about your account and not a stranger's, and the token is checked and discarded — never stored, never logged.
Ticker symbolsAny screen that prices your holdingsThe symbols you track go to our server. On a paid plan it prices them, and the symbol goes on to our market-data provider — whatever you hold, and wherever it is listed; your browser never talks to a market-data provider itself. That request carries your sign-in token, so we can confirm your plan includes daily prices; it is checked and discarded, and no record links the symbols you track to your account. On the free plan no price is fetched — holdings are valued at cost or at a price you enter yourself — and the symbols reach only our own server, which uses them to label what each holding is and passes them to nobody.
Symbol searchWhile you type in the add-position pickerThe text you type in the picker's search box — a ticker, a name, or an ISIN. It goes to our server, which answers from its own snapshot first; only when the snapshot has nothing, and only on a paid plan, does the query go on to our symbol-search provider, which is what lets a listing outside the US resolve at all. On a paid plan that request carries your sign-in token, so we can confirm your plan includes provider search; it is checked and discarded. We write no search log of our own and keep no history, and nothing we keep is linked to your identity — what you type is not part of the address of the request, so our hosting provider's request logs do not carry it either; those lines record that a search was asked for, not what you were looking for. A name you would rather not search has its own way in — "Not listed anywhere?" in the picker adds an unlisted holding without typing into this box.
FX-rate requestEvery app load, on any pageA fixed request for USD exchange rates, carrying no personal or financial data. It goes to our server, which serves rates from its own hourly snapshot — your browser never contacts a rate provider, so none of them sees your IP address or when you open the app.
Push tokenWhen you turn a notification type on or offA device token + per-type on/off flags. Notification content never contains amounts, balances, or account names — fixed copy and a deep link only.
Reason-coverage checkAny screen that shows your holdings, on every planThe symbols you hold go to our server, which answers only which of them we already hold public reason records for — a yes or no per symbol, and nothing else. No reason text, no statuses, no counts. It carries no sign-in token on any plan, nothing is stored, and the answer is the same for everyone. It is what lets the signal below ask for coverage of the right tickers.
Ticker-interest signalA holdings screen, on every plan, for a ticker we don't coverA bare ticker symbol — no identity, no amounts — so we know which tickers people actually hold and can decide which ones to cover next. It is stored only as an anonymous per-ticker counter that nobody, including you, can read back; it is never linked to you, and the popularity aggregate never leaves the server. The request carries no sign-in token on any plan, and nothing is stored against it.
Usage analyticsEvery page you openThe page address and a count of five product actions — creating an account, opening upgrade, starting a checkout, confirming a snapshot, adding a reason. They go to our analytics provider, which derives your device type and rough location from the request itself. Never an amount, a balance, a holding, an account name, a currency or anything you wrote. The counting needs nothing stored on your device; cookies recognise a repeat visit, and where consent is required we ask before setting them. Settings → Data & privacy shows and changes that for one browser.

The Contains column is what each request carries. The connection underneath it carries the IP address your browser comes from, which any server it connects to directly can see, ours among them. Our hosting provider records it in its request logs, for its default log retention, and no record of ours links that address to your account.

Usage analytics count page views and the five actions above — that counting goes to our analytics provider, identifies no one and stores nothing on your device; the cookies that recognise a repeat visit are separate, and Settings → Data & privacy shows and changes them. The product-moment row is the one line in this table that names your account, and it carries no figure from your ledger. Your sync passphrase and your birth year never leave your device at all — not on any plan, not in any feature. Your amounts, balances, account names, transfers and snapshots leave it only as the synced copy described above, and only to the one provider that hosts our database.

The invariant

Your ledger is read to run Moflow for you and for nothing else.

This is a commitment about purpose, not a switch we could show you: it is kept by how we build and review Moflow, and by this page — the day a new purpose is added, this page changes before the code ships. What each request actually carries is in the table above.

This charter is not the legal document. The privacy policy and the terms of service are those, written against exactly the behaviour described here. This page binds the product: if a future feature can’t be built without weakening a claim on it, the feature changes — not the charter.