Legal

Privacy Policy

Last updated: November 5, 2026
The short version

Your portfolio file — a CSV export or a PDF statement — is parsed inside your own browser, and the file itself is never uploaded: we do not receive a copy of it, and nor does anyone else. What reaches our server is taken from it. On every analysis, signed in or not, the app sends the ticker symbols it found so they can be classified and priced, and our server adds them to a shared list of securities that has no owner (Section 4a); and for a fund it cannot identify at all, the description printed beside it, which we store (Section 4b). And if you are signed in, importing a portfolio saves the parsed result against your email address — the securities, how many of each, what they were worth, and the labels of the accounts they sat under — so that your next visit, and every feature that depends on what you hold, can start from where you left off instead of asking for the statement again (Section 4d).

If you are an adviser, broker, insurance agent or accountant using this tool for other people’s portfolios, Section 4e is the one to read: each client is a separate record under your email address, the name you give them is stored as you type it, your clients have no login here and cannot ask us for anything directly, and having their permission to put their finances in is your responsibility rather than something we can check.

So there is a database with portfolio data in it, and this page would rather say so than lean on a distinction you did not ask for. What is not in it: your postal address and the day and month you were born, which we do not ask for. A birth year is asked for in the planners and is saved with your plan (Section 2). Nor do we ask for your account numbers, and our server strips them out of account labels before saving the labels — but some PDF statements print the account number as the account’s name, and when two accounts in a CSV export share a name the browser adds the last four characters of each account number to it, so in those cases it reaches our server first, and Section 4d says what the stripping can miss. You can delete your saved portfolios and plans yourself, and Section 9 says how, and what stays. Signing in needs an email address and a password. Sign-up also asks your name, a phone number if you choose to give one, and — for advisers and other professionals — the name of your firm; Section 3 says why. Separately, the Pricing page carries one form, for firms asking about the Firm plan: what you type in it is emailed to us and not stored, and Section 4f sets out what it sends and what it does not.

1. What this tool does with your data

Tulir Portfolio Analysis runs mostly in your web browser, with a server we operate on Cloudflare. When you add a portfolio file — a CSV export from Fidelity or Schwab, or a PDF statement from your brokerage — it is read and parsed using JavaScript running locally in your web browser. PDF statements are read by a copy of Mozilla's pdf.js that we host ourselves, so opening one does not tell any other party that you are importing a statement. The calculations on your portfolio — exposure analysis, sector breakdowns, stress testing, correlation matrices, and every other feature — happen on your own device; some figures about the securities themselves, such as their past returns, are calculated on our server from public price history and sent to your browser (Section 4c).

At no point is the portfolio file itself uploaded. There is no backend server receiving it, and no copy of the CSV or the PDF is written anywhere outside your own device. What leaves your browser is taken from it rather than being it: the ticker symbols, on every analysis; the description printed beside a fund the app cannot identify at all; and, if you are signed in, the parsed portfolio — securities, quantities, values and account labels. Section 4 sets out each case, and what is stripped out before it goes.

That is a statement about your data, not about network traffic, and the two are worth separating. The page itself does talk to our server: it counts your visit (Section 5), checks whether you are signed in, and — on every analysis — sends the ticker symbols it found so they can be classified into sectors, themes and size bands and matched to price history, asks our server to resolve any fund it cannot look through, sends that fund's symbol and printed description so the fund can be added to the database, and records which features you open — against your account if you are signed in, and against a random identifier your browser keeps if you are not (Sections 4 and 5). If you disconnected from the internet after the page loaded, the analysis would still run on your own machine, but any holding the app could not classify from its built-in database would be left unclassified, and the price history our server supplies would be unavailable.

2. Information we do not collect

We do not collect, store, transmit, or have access to:

Until October 2026 this section could say something stronger: that there was no database of portfolio data at all, and that a lawful demand for one would have found nothing to answer with. That is no longer true, and a policy that kept the sentence alive on a technicality would be worse than one that retires it. If you are signed in and you import a portfolio, we hold a list of your securities and their values under your email address, and we would have to answer a lawful order for it as any other company would. What such a record does not contain is your postal address or your brokerage login, and account numbers are stripped from it before it is written — by pattern-matching, which Section 4d describes along with what it can miss. What it does contain is an email address and a portfolio — the securities, the quantities, the values, the prices, the cost basis, the account labels with account numbers stripped out, whatever you entered in the planners, and the names you gave your accounts and account groups. We ask your name at sign-up (Section 3), and an account label can carry one too, because that is how the brokerage printed it — and if the account belongs to an adviser, it also contains a client name they typed (Section 4e). That is a good deal more than a list of tickers, and it is worth saying so plainly: such a record can show whose portfolio it is, and often which brokerage holds it — the account labels from a Schwab export end in “(Schwab)”, and a cash balance read from a PDF statement is usually stored under a placeholder symbol that names the brokerage, such as $CASH:SCHWAB. If you have no account, no email address and no portfolio of yours is held; what exists is a random visitor identifier with the pages and features recorded against it and a short-lived counter keyed to your network address (both Section 5), our hosting provider’s own logs (Section 6), and the unlinked ticker and fund-description rows in Sections 4a and 4b. Signing out only ends your session: an account’s record, and anything stored under it, stays until you delete it (Section 9).

We can also open it ourselves, and it is better to say so than to let the paragraph above imply that only a court could. A limited number of administrator accounts, which Tulir Systems LLC controls and which are fixed in the application’s code, can open what you have stored, to answer a support question — a report that looks wrong, a number that does not add up, an import that did not work. Adding or changing an administrator account takes a change to that code and a new release by us, and we decide who may use each account. Inside the product there are two ways in: a plain list of the records as they are stored, and a view that renders your tabs the way you would see them. Both views are built to read and not to write: the server routes behind them only read, and then write the audit record described below; neither signs anyone in as you; and the page refuses any save to your records made from inside the view. Those two views are not all an administrator can do, and not the only way the data could be read. Some administrator actions are not recorded: opening the account list, or one account’s details, is one. Administrators can also correct the details on an account — the name, phone number, firm, role, how you heard of us, and plan — and delete an account along with its saved portfolios, plans and feature log. And the database sits in our Cloudflare account: anyone with access to that account could read its tables directly, without either view and without writing the record described below.

Every use of either view writes a record of who looked, whose account it was, and when; the rendered view also records which client’s portfolio was opened, if one was, and the plain list records how many saved statements it returned. That makes those views accountable after the fact rather than merely promised in advance. The record is kept in the same database, and Delete my data does not remove it (Section 9).

If your adviser uses this service, this reaches you too. We said previously that an adviser's clients could not be opened this way, and that is no longer true: the rendered view opens one named client’s portfolio and plans at a time, and an adviser's clients are included. Before any client is picked, it also shows the administrator the adviser’s list of active clients, with the name, phone number and email address the adviser recorded for each. We have told you plainly rather than leaving it to be inferred, because those clients are not our users — they have no account here and never agreed to anything with us. What that access does is the same: it reads, and a record of each use names the client whose portfolio was opened; a use in which no client is opened names none, although the list of clients was shown. The plain list of stored records is still refused for an adviser account, because it spans every household they hold at once and nothing in it marks which one is the adviser's own.

Separately from any of that, we accumulate reference data about securities themselves — which companies a fund holds, what sector a ticker is in. That is public information and says nothing about who holds it.

3. Account sign-up

Some features need an account, and reading your own statement is one of them. We use your account to let you sign in, to decide what you can open, and to keep what you save filed against the right person: when you are signed in, every portfolio you import is stored under your email address automatically, as Section 4d describes, along with what you enter in the planners.

When you sign up we ask one more thing: what kind of user you are — an individual, or an adviser, broker, insurance agent or accountant. It decides whether the tool shows you the client controls in Section 4e, and whether the plain list of stored records in Section 2 is refused for your account. Accounts created before we started asking have no answer recorded, and are treated as individuals.

When you sign up we collect your email address, used to confirm the address, to let you sign in, and to send you the confirmation and password-reset links described in Section 6. We also store your password — never in readable form. It is put through PBKDF2-SHA-256 with a random per-account salt and 100,000 iterations, and only that derived value is kept, so nobody here can read your password, and anyone who obtained the stored record could recover it only by guessing it. We never ask for or store any brokerage, account, or portfolio information as part of sign-up.

From October 2026 the sign-up form also asks your name, and — if you tell us you are an adviser, broker, insurance agent or accountant — the name of your firm. Both are there so that the people running this service can tell who an account belongs to: before them, an operator could see that an account had opened the Risks tab eleven times and had no way of knowing whose account it was. They are not shown to other users, they are not used to advertise to you, and they are not sent anywhere outside this service.

Two further questions are optional and stay optional, and an account works exactly the same whether you answer them or not. A phone number, kept only so we can reach you if you have asked us to — nothing dials it, it is not passed to anyone, and no feature is withheld if you leave it blank. And how you heard about us, which is a fixed list of answers rather than a free text box, used to work out which introductions are worth making and nothing else.

Your email address is the key everything else sits under. It identifies you so you can sign in, and — if you import a portfolio while signed in — it is what the stored portfolio is filed against. That is not incidental to the feature, it is the feature: a portfolio not associated with your account could not be handed back to you next visit. Section 4d sets out what that record holds, and Section 9 how to delete it. Signed out, the tool reads only its sample portfolio, never a file of yours, so nothing from your own statement is sent or stored; the sample’s ticker symbols still go to our server, as Sections 4a and 4c describe, because classification and pricing run either way.

You can ask us to delete your email from our records at any time, by writing to hello@tulir.systems — see Section 9.

3b. Two-step sign-in (optional)

You can add a second step to signing in: a six-digit code from an authenticator app on your phone, asked for after your password. It is off unless you turn it on. We do not use text messages.

What we store when you turn it on, against your email address:

What we record while codes are being checked: a short-lived note that a code was tried (which is how we limit wrong guesses), and, after too many wrong codes, a note that two-step sign-in is paused for your address for 24 hours. These are filed under a scrambled form of your email address, not the address itself, and the attempt notes are cleared within a day.

What we email you: a plain message, with no link in it, whenever two-step sign-in is turned on or off, your authenticator is replaced, new recovery codes are made, a recovery code is used, or sign-in is paused. If you did not do it, the message tells you to write to us at once.

Turning two-step off removes all of this, and so does closing your account (Section 9); Delete my data does not. If you lose your phone and your recovery codes, we can remove two-step from your account after checking that you are who you say you are, outside email; we clear your password when we do, and you set a new one with Forgot password.

3c. Paying for a plan

Personal and Professional are paid for by card through Stripe, a payment processor. When you subscribe you are sent to a page that Stripe hosts, and you type your card details there: they go from your browser to Stripe and never reach our website or our server, so we cannot see your card number. Stripe keeps the card so that your plan can be renewed each year (Section 3 of the Terms of Service), and it handles what you give it under its own privacy policy, which we do not control.

What we send Stripe: the email address on your account, the plan you chose, and the discount code if you use one.

What we keep, against your email address: Stripe’s reference numbers for you and your subscription, which plan you have, whether it is active, the date it runs to or renews, whether you have cancelled it, and the version of the terms you accepted. We also keep a log of what Stripe tells us (a payment received, a renewal, a refund, a dispute, a cancellation), filed under Stripe’s reference number rather than your name or address. We do not keep your card number, expiry or security code, and we do not keep a billing address.

What we use it for: to open the plan you paid for, to show you its renewal date, to let you cancel or update your card from Manage billing, and to tell our administrators about a refund or a dispute. We do not use it to advertise, and we pass it to no one but Stripe. If you ask us to close your account while a paid plan is running, the plan has to be cancelled first, because we cannot close an account that Stripe is still billing. Stripe keeps its own records of what you paid, for as long as the law requires of a payment processor.

4. What leaves your browser, and where it goes

The subsections below describe each case in which something taken from your portfolio file leaves your browser, as the code stands today. Signed out, the tool reads only its sample portfolio, never a file of yours (Section 3), so nothing taken from your own file leaves your browser; the sample’s ticker symbols are still sent, as 4a and 4c describe. Signed in, it is the identifiers in 4a, 4b and 4c, and also the portfolio itself — 4d, and 4e if the portfolio is somebody else’s and you are their adviser. 4f is the one case that has nothing to do with your portfolio file at all: a form you can choose to fill in. Sections 5 and 6 cover the rest of the page's network traffic — visit counting, feature tracking, signing in, and fonts.

4a. Classification — runs on every analysis

When you load a portfolio, your browser sends the ticker symbols it found to our own server (a Cloudflare Worker) which returns whatever sector, industry and market-cap/style classifications it holds for them. It sends every ticker it found, in batches of 200, whether or not the app already recognises one — it does not check first. Holdings with no ticker at all are excluded, as the end of Section 4b explains. This happens on every analysis, whether or not you are signed in, and it is not optional. What is sent is the identifier only — "AAPL", "VOO" — never your share count, dollar value, cost basis, gain, or account name. Our server also adds each symbol that looks like a real ticker to a shared list of securities, which decides whose price history our scheduled job refreshes (Section 6). That list holds the symbol and when it was first and last seen, with no email address, account or visit identifier beside it, so it is not linked to you — and for the same reason Delete my data does not clear it. The price figures our server calculates for the symbols on that list can be requested by anyone, signed in or not. Results are cached in your browser so the classifications survive a reload, but the list is sent again each time you load a portfolio — the cache makes the answer local, it does not stop the request.

If a fund you hold is not in the built-in holdings database, your browser may also ask our server to resolve it. Our server then fetches that fund's publicly filed holdings from the SEC's EDGAR system, may use OpenFIGI to map identifiers to tickers, and may send some of that fund's constituent ticker symbols to Finnhub to classify them by sector and market cap. Those are the fund's own published holdings, not yours — none of these services is told anything about you, your position, or even which fund you personally hold beyond the symbol being resolved. This can happen whether or not you are signed in.

Classification results are cached in your browser's local storage so repeat visits are faster. That cache holds public reference data about securities — sectors, industries, fund holdings lists — keyed by the symbols in your portfolio. It stays on your device; clearing your browser's site data removes it. See Section 4b for the one case in which part of it is sent back.

4b. Contributing a resolved fund back — automatic

When your browser successfully resolves a fund that was not in the built-in database, it sends the result back to our server so the next person holding that fund inherits it instead of resolving it again. What is sent is the fund's symbol, the list of companies it holds with their published weights, and any sector or size classifications derived along the way. This is public reference data about the fund, taken from its own regulatory filing — it contains no figure of yours and nothing that identifies you. It is sent automatically, without being asked, and the server independently re-validates everything before storing it.

Separately, when the app meets a fund it cannot identify at all, it sends that fund's ticker symbol together with the security description printed beside it in your export — for example "VANGUARD INFORMATION TECHNOLOGY ETF" — so the fund can be added to the database later. That description is text copied from the file you uploaded — a CSV export or a PDF statement. Apart from the ticker symbols in Sections 4a and 4c, and the signed-in save in Section 4d, it is the only content from your file that is transmitted — and, like the symbols in Section 4a, it is stored. It is not linked to you: the stored row holds the symbol, the description and a timestamp, with no email address, account or visit identifier beside it. There is no routine that deletes these rows, and a row is kept even after its fund has been added to the database; some rows are also marked with when our server resolved the fund. We do not tie these rows to an account, and we do not delete them on request. Before it is sent we strip out a dollar, pound or euro amount, a number written with thousands separators, a number with two or more decimal places, a figure written with a percent sign, and any run of five or more digits, which is what an account or plan reference looks like — a statement sometimes prints a value or a percentage in the same place as the security name, and the example above is sent as "NH FIDELITY 500 INDEX". What that does not remove is a bare number: a share count printed as 1250, or a price printed as 44.5, would travel with the description. Security names are themselves full of numbers — "FIDELITY 500 INDEX", "2039 PORTFOLIO" — and stripping those would mangle the very names we are collecting. Holdings we had to invent an internal placeholder for, because the statement printed no ticker at all, are never sent here, and never reach the shared fund database or any third party — a placeholder is a slug of your statement's own wording, and it is not a security anybody could look up. If you are signed in it is stored with the rest of your portfolio, as Section 4d describes: under your email address, and removed from the live database when you delete your data. It is deliberately kept out of the shared register of securities we price, because that register has no owner against its rows and so cannot be deleted from.

4c. Market data — price history, and live data from Finnhub

When you load a portfolio, signed in or not, your browser also asks our own server for price-history figures for the tickers it found, together with a handful of benchmark funds: trailing returns over several periods, the change so far this year, the distance from the 52-week high, and the latest price. The ticker symbols, up to 400 of them, are listed in the web address of that request, and the Correlation tab makes a similar request for up to 20 of the larger companies in your look-through. Our server answers from figures it has already calculated on its own schedule (Section 6), and stores nothing from the request. Only ticker symbols are sent — no share count, dollar value, cost basis or account name — and if you are signed in, your browser attaches your session cookie, which neither request uses.

The Performance, Income and Ratings tabs also have controls that fetch live market data from Finnhub. They are optional and require being signed in (see Section 3); our server refuses the request without a session. In the current version of the tool those controls are switched off, and the three tabs show the figures above and tables built into the tool instead. When the controls are used, your browser sends a request to our own server (a Cloudflare Worker), which forwards it to Finnhub.io, a third-party financial data provider, using our own API key — you never need to obtain or enter one yourself. Finnhub returns public market data (stock prices, dividend yields, fundamental metrics) for the ticker symbols involved, which we relay back to your browser.

What is sent to our serverTicker symbols and the name of the data set requested, plus your session cookie to confirm you're signed in — never your share counts, dollar values, cost basis, or any other portfolio detail
What we forward to FinnhubThe same ticker symbols and the name of the data set requested, and nothing else — no share counts, dollar values, or account information ever reach Finnhub either
What we store from thisNothing about the request or response is retained beyond what's needed to serve it and enforce a shared rate limit, which expires after sixty seconds

Finnhub's use of any data sent to them is governed by their own terms of service and privacy practices, which we do not control. Finnhub is reached in two kinds of situation: when you use one of the live-data controls on the Performance, Income or Ratings tab, and when our server has to classify the constituents of a fund it is resolving for you (Section 4a). The first is optional and requires being signed in; the second is not optional and can happen signed out. In both cases what is involved is ticker symbols and the name of the data set requested.

4d. Saving a portfolio to your account — signed in

If you are signed in, a successful import sends the parsed portfolio to our own server, where it is stored against your email address. There is no checkbox and no save button: it happens every time, because the point of it is that your next visit does not begin by asking you for the same statement again, and that anything built on your holdings — a retirement projection, a tax estimate — is still there when you come back. The demo portfolio is never saved; it is not yours, and treating it as yours would be worse than not saving at all.

What is stored for each position is fixed by an allow-list in the page rather than by a list of exclusions, so a parser that learns a new field later cannot start sending it because nobody remembered to exclude it. The list is: the ticker symbol, the security description, the account label, the quantity, the value, the price your statement printed, the cost basis, and what kind of holding your brokerage called it — cash, a fund, a stock, an option or crypto. That last one is their classification rather than our guess, and keeping it is why a cash balance comes back as cash. Nothing else from the row travels — in particular the account-number column of a CSV export does not, even though the parser has it. The account label, though, is sent as your statement printed it, and some PDF statements print the account number there: a Schwab statement’s label is its account number followed by the account type, and other brokerages’ labels can carry the number or its last digits. When two accounts in a CSV export share a name, the browser also adds the last four characters of each account number to the label, to tell them apart. The description is put through the same strip as Section 4b before it is stored, because a statement's description column sometimes runs into the one beside it: currency amounts, percentages and any run of five or more digits, which is the shape of an account or plan reference, are removed first. Our server then strips what looks like an account number from the label before it is written: runs of four or more digits, masked endings such as …1234 or ****5678, and a number written after “account”, “acct”, “no.” or “#”. So an account your statement calls “Traditional IRA …4321” is stored as “Traditional IRA”; a label that is nothing but digits becomes “Account”. This is pattern-matching rather than a guarantee. A number of three digits or fewer standing on its own is kept on purpose, because 401(k), 403(b), 457 and 529 are three digits, so a short fragment of an account number can survive — a label beginning “147-930563” is stored beginning “147-” — and a name in a label is not removed.

Stored beside the positions are the date printed on your statement (or, if it printed none, the date you imported it, marked as such), the date you imported it, the portfolio total, and how many warnings the import raised — the count, not their text. Imports are filed by statement date: importing a statement with the same date as one already on file replaces that earlier copy, and importing a statement with a different date keeps both. A statement that printed no date is filed under the day you imported it, and replaces the previous undated one and any statement already filed for that day, so a file with no date does not build up a history. So if you import every month, what accumulates is a record of what you held at each of those dates. Deleting (Section 9) removes all of them from the live database at once.

Whatever you enter in the retirement planner is stored the same way and under the same email address — the figures and the choices you typed, so the plan is still there next time. It is kept as you typed it.

So are the college plan, any assets you record outside the portfolio, and the way you organise your accounts: the name and type you give an account, and any account groups you create — each group’s name and the words that place an account in it. These are stored exactly as you type them, so a group or an account named after a person puts that person’s name in our database.

None of this is sold, and none of it is shared with anyone for their own purposes; Cloudflare holds it for us as our hosting provider (Section 6). A stored portfolio is never sent to Finnhub or to any other data provider; the market-data requests in 4c are driven by ticker symbols, which are sent whether or not anything is stored. It exists so the tool can show your portfolio back to you. The only other things it is used for are these: our administrators can open it to answer a support question (Section 2), and their account list counts how many statements, plans and outside assets each account has saved, without showing what is in them; and when it is saved, its ticker symbols are added to the shared list of securities in Section 4a.

4e. Using the tool for other people’s portfolios — advisers and other professionals

If you told us at sign-up that you are an adviser, broker, insurance agent or accountant, the tool lets you keep a separate portfolio for each of your clients and switch between them. Everything in Section 4d applies to each of those portfolios unchanged — the same allow-list, the same stripping of account numbers and references, the same storage, the same deletion. This section is about the part that is different.

The record is yours, not theirs. Every client you create is stored under your email address. There is no account for your client, they cannot sign in, and we have no way to recognise them: the only things they ever see are a PDF you produce and the screen you show them. That is a deliberate limit rather than a feature we have not built yet, and it has a consequence worth stating plainly: if your client wants to know what is held about them, or wants it deleted, they have to ask you. We cannot identify their data as theirs, because to us it is yours, and we will not act on a request from somebody we have no relationship with.

The name is yours too. You name each client, and what you type is stored as you typed it. It appears in the client list, in the header while you are working, and on the cover page of any PDF you produce for them. We do not ask for it, we do not check it, and we do not need it to be a real name — a reference or an initial works as well for the tool as a full name does. If you type a full legal name, then contrary to the rest of Section 2, there is a name in our database, and you put it there. If that matters to you, use a reference.

Permission is yours to have. Putting another person’s holdings, retirement plan, business valuation or property into an online tool is something you need their agreement for. We have no relationship with them, no way to ask them, and no way to verify what you have been given permission to do. The professional obligations you are under — your regulator’s, your firm’s, your engagement letter’s — are yours, and nothing on this page alters them.

What is stored for each client. The name you gave them; a phone number and an email address if you chose to add either, both optional; the parsed portfolio exactly as Section 4d describes it; whatever you entered in the retirement planner for them, including any college plan; any assets outside the portfolio you recorded — a business, a property, a debt — with the values and assumptions you gave; and the names, types and groups you gave their accounts. The phone and the email are held for your reference: we never send anything to them, and they appear on no printed report. An administrator who opens your account in the rendered view (Section 2) is shown them in your client list. Each is filed against the client, not against you in general, so switching clients shows only that client’s figures. The same separation applies on your own device: the browser keeps a separate copy per client, and signing out removes every client’s copy, not just the one on screen.

Removing a client. Archive takes a client out of your list and deletes nothing: their statements, plans and contact details stay stored under your email address. An archived client does not appear anywhere in the tool afterwards, and the app has no way to reopen one or to delete it on its own; Delete my data removes archived clients along with the rest. Delete erases that client’s stored statements, their plan, their outside assets and their contact details, from our server and from your browser, immediately and with no undo in the product; a deleted record can persist for up to 30 days in the database’s automatic history (the end of Section 9 explains); it asks you to type their name first, because it sits next to Rename. If one of our administrators ever opened that client (Section 2), the record of that opening keeps the client’s name. Delete my data (Section 9) removes every client at once, along with your own portfolio and plans; your sign-in, and the other records Section 9 lists, stay.

None of this changes what we do with the data: a stored portfolio is shown back to whoever is signed in, and otherwise used only in the ways the end of Section 4d lists. It is not sold, not shared, and not used to profile anybody — you or them.

4f. Asking for a meeting — the Firm enquiry form

The Firm plan has no published price, so the Pricing page offers a Talk to us button instead. It opens a short form. It is the only form on this site that is not part of creating or using an account, and it is entirely optional: nothing else on the page depends on it, and if you never open it, none of what follows happens.

What it asks. Your name, a work email address and the name of your firm, which are required; and, if you want to give them, a phone number, how many advisers you have in mind, and a note. Nothing is taken from your portfolio, your statement or your account — the form does not read any of them, and you do not need to be signed in.

Where it goes. Straight out as an email to hello@tulir.systems, sent through Resend, our email provider, which delivers it for us and keeps its own record of it under its own policy, which we do not control. The reply address is set to the one you gave, so an answer goes back to you rather than to a no-reply address.

It is not stored. No record is created in our own database: your enquiry exists only as an email, which passes through Resend on the way, as above, and is kept in the mailbox that receives it. It is not filed against an account, it is not added to the portfolio database described in Section 4d, and filling it in does not create an account or add you to a mailing list. A phone number you give here is a different thing from the optional one at sign-up in Section 3 — that one is never passed to anyone, while this one travels in the email, because reaching you is the point of sending it.

Two things happen that you cannot see. The form carries one hidden field that a person never encounters and never fills in; if it arrives filled in, the message is discarded as automated and nothing is sent. And to stop the form being used to flood that mailbox, the server counts recent requests per address: it stores a SHA-256 hash of your IP address, never the address itself, with a counter that deletes itself after an hour, and refuses more than five requests from the same source in that time — counting this form, sign-ups and password-reset requests together. That hash is not linked to you, to an account or to anything else, and after the hour there is nothing left of it.

5. Usage analytics

We measure two things: how many people visit, and which features get used. Visit counting carries no name, no email address and no cookie — only a random identifier your browser invented, which the fourth paragraph below explains. Feature usage is not, for signed-in users — if you are signed in, opening a feature records that feature and the time against your account. This page used to add that neither could be linked to the contents of your portfolio, because those contents never reached us. Now that a stored portfolio sits under the same email address as the feature log, that is a claim about our conduct rather than an impossibility, and it is made as such in the commitments at the end of this section.

We count visits ourselves, on our own server — and, separately, our hosting provider runs a page-view counter of its own, which Section 6 describes. The rest of this section is about ours. When you open the site, your browser generates a random identifier — a short string with no meaning anywhere outside this site — keeps it in your browser's local storage, and sends it to us together with which page you opened. That is the whole contents of that request. The same identifier is also sent, at most once per browsing session for each, when you reach one or two milestones — such as loading a portfolio for the first time, or loading the demo. Those pings record that the milestone happened, never anything about the portfolio itself. We do not store your IP address alongside that identifier, we do not derive a device fingerprint, and nothing about your portfolio is involved — these pings carry a milestone and nothing else. Section 4 describes the cases in which something from your portfolio leaves your browser; none of them is involved in these pings. Your IP address is used for one thing only: a short-lived counter, discarded an hour after the last request it counted, that stops a single network flooding these counts or our lookup endpoints. It is never joined to the visit record, to your account, or to anything else.

Feature usage is recorded differently, and in one of two ways depending on whether you are signed in. If you are signed in, opening a tab or feature sends its name to our server, where it is stored against your email address with a timestamp. If you are not signed in — including when you are looking at the sample portfolio — the feature's name is sent against the same random identifier the visit counter uses, and no email address is involved, because there is none to involve. The two are counted and reported separately. This is how we see which parts of the tool are actually used and which are not worth maintaining. In both cases what is recorded is the feature's name and when, never anything it displayed.

If you reached this site from a link in an email we sent, that link may carry a short campaign tag — something like oct-intro — identifying the send, never you. It is recorded once, against the same random identifier, so we can tell which message brought people here. The tag is limited to 32 letters, digits and hyphens, and the ones we use are plain labels for a send, never a code for one recipient: a per-recipient code would let the identifier be traced to your email address before you had given it to us. (Once you create an account the identifier is recorded beside your email address, as the next paragraph says.)

The visit counter exists to answer one question: how many people try the tool without ever creating an account. If you do later sign up, that identifier is recorded alongside your email address so we can tell "looked and left" apart from "looked and signed up". That association stays internal to us and is never sold or shared. Clearing your browser's site data deletes the identifier; your next visit simply counts as a new one.

We may add or change analytics tools over time — for example, to better understand which specific buttons or screens people use, or how visitors move from browsing for free to signing up — as the product grows. Regardless of which specific tool is in use at any given time, we commit to the following, and we will not change these commitments without updating this page and, for account holders, telling you, the next time you use the product signed in, that the terms have changed, with a link to them (Section 8):

Your browser's local storage holds twenty things. Seven of them are about you or your account: the visit identifier described above; a flag recording that this browser has signed in before, so the page knows whether to wait for a stored portfolio before drawing; a flag recording that your account has a stored portfolio, which is what the home page reads to decide where a returning visit lands; a flag recording that we have already told you a portfolio was saved; a one-way digest recording that this browser has already shown you the choice between subscribing and continuing free, so it is shown once and not at every visit (it is a digest, not your address); a short one-way digest of the email address this browser last signed in with, which is how signing in as somebody else clears the previous person's answers from the device instead of showing them to you — it is a digest rather than the address itself, it is never sent to us, and it is removed when you sign out; and, if you reached us from one of our emails, the campaign tag described above. Seven are things you typed or chose: any account-grouping rules you create; everything you have entered in the retirement planner — ages, incomes, pensions, spending plans; any assets you recorded outside the portfolio, such as a business or a property; which sections you last chose to include in a PDF; the page size you last chose for it; the college plan you entered — who each 529 is for, the year they were born and the year they start; and any correction you made to what an account is called or what kind of account it is, which the tax and planning screens use instead of guessing from the name your brokerage printed. All seven are kept here so the page still has them after a reload. The fund holdings you enter by hand when the app could not resolve a fund are listed with the working data below instead, because they describe a fund rather than you. The last six are working data: the cached classification described in Section 4a, a note of which classifications this browser has already contributed back, the fund holdings you entered by hand, a timestamp for when the dividend-yield database was refreshed, a flag recording whether this browser has already filed its older entries under a client, and a flag recording that something you entered has not yet reached your account — so a later visit does not treat what we hold as more current than what is on this device, and quietly replace it.

If you hold portfolios for clients (Section 4e), those seven, and the flag that something has not yet reached your account, are kept once per client rather than once per browser, so switching clients does not show you the previous one’s answers. Signing out removes every client’s copy of all of them, together with the flags that this browser has signed in before, that your account has a stored portfolio and that older entries have been filed under a client, and the digest of your email address. It does not remove the visit identifier, the campaign tag, the flag that we have told you a portfolio was saved, the cached classification, the note of what this browser contributed, the hand-entered fund holdings or the dividend-yield timestamp; clearing your browser’s site data does. The hand-entered fund holdings are deliberately not kept per client: what a fund holds is the same fact whoever is looking at it.

Of all of that, only the visit identifier and the campaign tag are sent to us as a matter of course; the cached classification only in the narrow case in Section 4b; and, only if you are signed in, under Section 4d, the planner’s answers, the college plan, any assets you recorded outside the portfolio, your account groups, and the names and types you gave your accounts. Clearing your browser's site data removes every one of them, and removing the planner's answers from this browser does not remove the copy saved to your account — Section 9 is how you do that.

6. Hosting infrastructure

This website is hosted on Cloudflare Pages, a static-site hosting service. Cloudflare may log standard web server metadata (such as IP address, browser type, and timestamp) for security and performance purposes, consistent with their role as our hosting provider. Cloudflare also provides the server that receives a saved portfolio and the database it is stored in. In that role Cloudflare is our infrastructure provider rather than a separate recipient of your data: it is not given the data for its own purposes. See Cloudflare's privacy policy for details on their hosting-level practices.

Every page on this site also carries Cloudflare Web Analytics, a page-view counter Cloudflare inserts into the page at its edge rather than something we add to the source. It sets no cookie and stores nothing in your browser. Once per page view it reports the address of the page and the referring page if your browser sends one, both with any query string or anchor removed; your browser and operating system and their versions; and how quickly the page loaded and responded to you, including a technical label for the part of the page that was slowest to draw or respond. None of those labels contains anything from your portfolio. It is a separate count from the one described in Section 5, it carries none of the identifiers described there, and nothing from your portfolio is involved. Our other product, PulseAlert, has its own counter with its own key, and no identifier is shared between the two. Blocking static.cloudflareinsights.com removes it and changes nothing else about the page.

Every page on this site, including this one, loads its typefaces from Google Fonts. Requesting those files tells Google your IP address and browser user-agent, as any request to any server would. We send Google nothing else, and nothing about your portfolio is involved. If you would rather not make that request, a content blocker set to block both fonts.googleapis.com and fonts.gstatic.com will stop it; the site remains fully usable in a fallback typeface.

Email we send you — the confirmation link when you create an account, any password-reset link, and the notices about two-step sign-in (Section 3b) — is delivered through Resend, a third-party email provider. Resend receives your email address and the contents of that message so that it can deliver it, and nothing else; it is never given anything from your portfolio. Its handling of that address is governed by its own privacy practices, which we do not control. When you confirm a new account, we also use Resend to send ourselves a short notice of it, delivered to our administrators’ own mailboxes: it contains your email address and the running number of accounts, and nothing else from your sign-up or your portfolio.

Payment for Personal and Professional is taken by Stripe, a payment processor, on a page Stripe hosts (Section 3c). Stripe receives the email address on your account, the plan you chose and the card details you type into its page, and keeps its own records of the payments it takes, under its own privacy policy, which we do not control. Our server and Stripe also exchange notices by a connection between the two (a payment received, a refund, a cancellation); your card number is in none of them.

Two further services are contacted by our server on a schedule of its own, never by your browser. A background job refreshes price history from Yahoo Finance, and a set of public macroeconomic series from FRED, the St. Louis Federal Reserve's data service. The Yahoo requests carry ticker symbols taken from a shared list of every symbol this tool has ever seen, the symbols in your portfolio among them once you have analysed it (Section 4a); the list records no owner and so says nothing about who holds what; the FRED requests carry nothing but the identifier of the public series being fetched. Neither service receives your IP address, your portfolio, or anything else of yours, because neither is ever contacted from your browser.

7. Children's privacy

This tool is intended for use by adults — managing their own investment portfolios, or, for the professionals in Section 4e, their clients’. It is not directed at children under 13, and we do not knowingly collect information from children. If we learn an account was created by a child under 13, we will delete the associated email address.

8. Changes to this policy

If this policy changes, we will update the "Last updated" date at the top of this page. If you have an account with us and the change is material, you are told the next time you use the product signed in, with a link to the changed terms, and you are asked to accept them before you carry on. If you don't have an account, we encourage checking this page periodically if you have concerns.

9. Contact

Tulir Systems LLC is a New Jersey limited liability company. It is the controller of the data described in this policy, and it can be reached at:

Tulir Systems LLC
1099 White Horse Road
Voorhees, NJ 08043
United States
hello@tulir.systems

To delete what is stored about your portfolio, you do not have to ask us. Sign in, and Delete my data is on the upload screen, in the small print beside “What we send and keep”. It removes every saved portfolio, everything you entered in the retirement planner, the college plan, the assets you recorded outside the portfolio, the names and groups you gave your accounts, and the record that groups them — from our server and from this browser, immediately and with no review step; the product has no undo. The database our server uses keeps an automatic point-in-time history for up to 30 days, so a deleted record can persist in that history for that long; we cannot shorten it. It tells you how many stored portfolios it found to remove. If you hold portfolios for clients, it removes every client’s, not just the one on screen; to remove one client and keep the rest, use Delete in the client list (Section 4e).

What it does not touch is named here rather than left to be discovered. Your email address and sign-in are a separate record and survive it, so you can still sign in — to an account with no portfolio in it. That record also keeps what you gave us at sign-up (your name, your role, and any firm, phone number and answer about how you heard of us), when you accepted the Terms of Service and this policy, and the visit identifier from Section 5 if your browser had one. Also left in place: the log of which features you opened while signed in (Section 5); the visit records from Section 5, which are filed under that identifier rather than your email address, though the identifier kept on your sign-in record links the two; and our administrators’ log of what they did with your account (Section 2), which records each use of the two views described there, naming your email address and any client of yours they opened, and the changes they made to your account’s name, firm, role or plan, with the old and new values. Also left in place: if you redeem a discount code, a record of that, which holds your email address; and, if an administrator has set, changed or removed a plan on your account, a record of that — the plan, its dates and which administrator made the change — which Delete my data does not remove (closing the account removes it). Also left in place by Delete my data, and removed when the account is closed: your two-step sign-in record and recovery codes, if you turned it on (Section 3b), and our record of your plan and its Stripe reference numbers, if you have a paid plan (Section 3c). Stripe, which takes payment, keeps its own records of what you paid, under its own policy, which we do not control. Resend, which delivers our email, keeps its own records of what it delivers, under its own policy, which we do not control. And two things stay because we do not tie them to an account, so we cannot find them from yours and we do not delete them on request: the shared list of ticker symbols in Section 4a, and the fund descriptions in Section 4b. Having your email address removed (below) also removes the feature log and what is still stored under the account from the live database, and the sign-in record from the separate store that holds it. Rows deleted from the database can persist for up to 30 days in its automatic history; the sign-in record has no such history, but the 30-day note of the removed address described below remains. The visit records, the record of any discount code you redeemed and the administrators’ record stay even then, and so, either way, does any notice of your sign-up sent to our administrators’ mailboxes (Section 6). For 30 days after that removal we also keep a note of the removed address. While the note lasts, no sign-in session for that address works, including one from signing up again (so signing up again inside the 30 days gives an account you cannot use until the note ends), and a sign-up link requested before the removal is refused; any such session, sign-up or password-reset record is kept, unusable, until it expires, which is within those 30 days. That is a different 30 days from the one in the paragraph above: the database host keeps an automatic history of the database, so rows removed by Delete my data, by removing a client or by closing an account can persist in it for up to 30 days, and we cannot shorten it.

Portfolio Analysis is operated by Tulir Systems LLC. There is no staffed support desk, but privacy requests are read and answered. For a privacy question, or to have your email address itself removed, write to hello@tulir.systems. If you ask in writing to have it removed, we will remove your sign-in record and what is stored under your account within 30 days of your request. That does not reach the records the paragraph above says stay even then, or the database host’s automatic history, which can hold deleted rows for up to 30 days.

This privacy policy describes the practices of the Portfolio Analysis website and tool only. It does not apply to Fidelity Investments, Charles Schwab, Finnhub, Cloudflare, Resend, or any other third-party service you may interact with separately. We are not affiliated with Fidelity Investments or Charles Schwab.