Kayabyte

How to turn a bank statement into Beancount

By Kayabyte · Last updated 28 October 2026

Beancount and the Ledger family (Ledger, hledger) keep your finances in plain text files. That is their appeal and their chore: every transaction has to get into the file somehow, and banks give you PDFs and CSVs. This guide covers the common ways to get statement data into Beancount, then the checks that make the result trustworthy.

1. What a Beancount entry needs

A transaction has a date, an optional payee and narration, and at least two postings that sum to zero:

2026-09-14 * "Grocery Store" "Weekly shop"
  Assets:Bank:Checking   -54.20 USD
  Expenses:Food:Groceries

For a statement import, the first posting is the bank account with the amount from the statement. The second posting is a placeholder (often Expenses:Uncategorized) that you reassign later. Beancount also has balance assertions, which are the best feature for this job:

2026-10-01 balance Assets:Bank:Checking  1234.56 USD

If the transactions before that date don’t add up to that balance, bean-check fails and tells you.

2. The manual way

  1. Download CSV from your bank if available; otherwise copy the table from the PDF into a spreadsheet.
  2. Clean it: one date format (Beancount wants YYYY-MM-DD), one signed amount column, descriptions on one line.
  3. Write the entries. For a few transactions, type them; for many, use a spreadsheet formula to build each text line, then paste into your file.
  4. Add a balance assertion for the statement’s closing balance on the day after the statement ends (Beancount balance assertions apply at the start of the day).
  5. Run bean-check yourfile.beancount.

3. Importers

For ongoing use, people write importers with Beancount’s import tooling (the bean-extract flow and the community beangulp package; check the current docs, since the tooling has changed between versions). An importer reads a CSV or OFX file from one specific bank and emits entries. It is powerful, but you write and maintain Python for each bank, and PDFs need an extra extraction step first. Hledger users have a similar route with CSV rules files, which describe how columns map to postings.

4. Limits of the manual way

5. Where Balanced helps

Balanced is a Mac app we make that reads PDF statements (text PDFs, scans and photos using Apple’s on-device text recognition) and CSV or TSV, from any bank, with headers and months in 10 languages. The preview shows the table found; you can fix column roles, date order and sign handling, and it remembers each bank’s layout.

Its totals check does for the statement what a balance assertion does in your ledger: opening balance plus transactions must equal the closing balance, and the running balance row by row when present. If something doesn’t add up, it names the rows and the difference, and exporting needs an explicit “Export anyway”.

Choose Beancount from the Export button (Ledger/hledger is next to it) and you get entries you can paste into your file, ready to be assigned to categories. No AI guessing: every number is copied from your statement and checked, and it all stays on your Mac.

Limits: results depend on layout, so check the preview; low-quality or skewed scans can fail; unlock password-protected PDFs first with the password from your bank. We can’t promise every bank.

Download Balanced and convert for free: the free version converts and checks everything and exports the first 10 transactions per file. Pro is USD 59 per year or USD 7.99 per month, up to 3 Macs, cancel anytime. See pricing and help. macOS 14 or later.

6. After the import