When you choose a file, your browser reads it locally using standard web APIs, the same ones for a CSV, an Excel file, or a PDF. The contents are handed directly to a program running inside that same browser tab. They are never attached to a network request, never uploaded to a server, and this site has no backend to receive them even if it wanted to.
The tool uses a project called Pyodide, which compiles a real Python interpreter to WebAssembly so it can run inside your browser. Excel files are read with a library called SheetJS, and PDFs are read with Mozilla's pdf.js, both also running entirely client-side. None of this code performs network I/O with your data.
Open your browser's developer tools (F12 or Cmd+Opt+I) and watch the Network tab while you upload a file. No request containing your file's data will appear. You can even disconnect from the internet entirely after the page has loaded, then upload your file: it will still work, which is only possible if nothing is being sent out.
There's no database, no account requirement, and no cookies tracking your session. If you refresh or close the tab, the results and your file are gone. There is nothing left over on any server, because no server ever saw them.
Clicking "Generate My Report" sends the aggregated findings already shown on-screen (vendor names, categories, dollar totals, never your raw transaction rows) through a small server we control, to write up the explanations in plainer language. If that step doesn't succeed for any reason, the report falls back to the version already computed locally, so you always get a report either way. Separately, if a file's columns genuinely can't be identified by name or by their values, an optional step sends a small real sample (the header row plus three example rows) to figure out which column is which, since that specific task needs to see a few real values to work at all. Neither exception ever receives your full file.
fetch, XMLHttpRequest, or Python socket/requests calls anywhere
in it. Pyodide, pdf.js, and SheetJS each only make network requests once, on initial page
load, to fetch their own runtime/library files, never your data. PDFs have no real rows or
columns, just text positioned on a page, so pdf.js extracts each fragment's position and
the page reconstructs a table by grouping fragments into rows and columns based on their
coordinates, then hands that to the same Python pipeline as a normal CSV upload. This works
well for typical text-based bank/card statement PDFs; it can't read a scanned image with no
underlying text layer, since there's nothing to extract.