Ledger

Drop in a bank statement and see where the money actually went — without the statement ever leaving your computer.

My bank's app shows me every transaction and not much else. It cannot tell me what I spend on restaurants in a month, it will not let me fix a category it got wrong, and it has no idea when the same charge comes through twice. Ledger is the dashboard I wanted instead.

Try it with your own statement Your file stays in your browser

The problem

I can already see my spending in banking apps, but what I cannot do is ask them anything like:

  • How much went to outside eating this month, and is that more than usual?
  • Which refunds am I still waiting on?
  • Did I pay that bill twice?
  • Where did the money go to a name I half remember?

None of that is hard to work out. The data is right there, it is just not arranged to answer anything. I also wanted to put a merchant in the right category myself and have it stay there.

There are apps that do all of this, and they want my bank login. That is a lot to hand over to find out how much I spend on groceries, which is why I ended up building it myself.

What I built

Everything runs in the browser. You drop your bank statements in CSV. It reads the file, cleans up the merchant names, sorts transactions into categories and draws the charts. There is no backend and no account, so a backup is a file you export and keep.

What comes back is a dashboard, not a list. Where the money went by category, your biggest merchants, and a short written summary of the month. The trend is a line chart you can read by day, week or month over whatever window you choose.

Rent is not news. Fixed costs — housing, tuition — are pulled into their own figure, so the day-to-day number underneath is the part of the month you can actually do something about.

Every category is editable. You can change a single transaction’s category whenever you want, or apply the change to the merchant as a whole — across your entire history and every import after it. A transaction can also be split across categories, which is how one withdrawal becomes rent and a deposit.

Refunds and pending charges are tracked too. You can tag a refund so it nets off properly, and log a pending charge before it clears; when the real transaction arrives, the two are matched. The whole history is searchable.

Your accounts pay each other, and that is not spending. Load a card, a current account and a savings account and the same dollar appears two or three times — a card payment drawn from savings is both a debit and a credit. Those movements are recognized, paired up and kept out of every spend figure. Money you sent an actual person stays in.

Cash counts too. ATM withdrawals are spending, and deposits net against them. The statement cannot say where the cash went, but it says how much.

Subscriptions get their own tab. Anything billed on a steady cadence is collected there, with what you pay, when it is next due and what it has cost you so far.

Double charges or any anomalies get flagged. When the same merchant charges the same amount twice within a day, a warning appears and stays there until you acknowledge it. The headline numbers turn red when the month runs more than 15% above your usual.

It makes no network requests at all. No fonts, no analytics, no CDN. You can open the network tab while you use it and watch it stay empty.

What I learned

Good categorization requires getting the merchant name right. Banks turn merchants into strings like AMZN Mktp US*2X4RT1, so the parser strips the noise back to something recognizable — Amazon. Throw too much away and FRONTIER AI lands under software, when it is four flights on Frontier Airlines.

One category per merchant is not always enough. The rules file Amazon under shopping, which is right for most of it and wrong for the monitor I bought there. So a transaction can carry its own category — change one transaction and only that one changes. Changing the merchant’s category is also possible: it overrides the rule, applies across the whole history, and holds for every import after.

A month that is not over cannot be compared with months that are. On the 10th of October it told me I was spending 73% less than usual, which was true and useless. Any figure for the current month now says how far through it is.

Every bug worth finding came from someone using it — and there were plenty. Some I caught myself, some came from friends, and the rest from a tester agent I wrote with Claude Code that works through the whole flow as a first-time visitor, then as a returning one, and pushes back on the fixes.

Stack

Plain HTML, CSS and JavaScript. No framework, no build step, no dependencies, no server. Written with Claude Code.

See it

One CSV in, a month you can read out.

Your CSVread in the browser
Clean & categorisenames, then rules
Charts & summaryand what changed

Stays on your machine

There is no server to send anything to. Your transactions are held in your own browser and nothing is transmitted — which you can verify yourself in the network tab.

  • no upload
  • no account
  • no network requests
  • works offline

Open Ledger — it starts empty, and whatever you load is yours alone.

Three months of statements, read in the browser and never sent anywhere. Every name and number here is made up — this is demo data, not mine. Scroll inside it to look around.

← Back to the homepage