Bookkeeping6 min read

What "Categorising" a Bank Statement for Xero Actually Involves

Nobody explains this part clearly, so here it is: coding transactions to accounts is the slowest step in catching up a set of books, and it has nothing to do with importing a file into Xero. It's the step before the import.

The bit that actually takes the time

Say a sole trader hands you a stack of PDF statements covering the last eight months, because they never got around to connecting a bank feed. Or you take over the books for a business partway through the year and the previous bookkeeper's feed only goes back so far. Either way you end up with a pile of PDFs and a spreadsheet, not a live feed.

Xero can import a bank statement manually. You go to Accounting, then Bank Accounts, pick the account, and there's an option to import a statement as a CSV. That part is mechanical and takes a couple of minutes once the file is in the right shape. What isn't mechanical is what happens after the import: every single transaction sits there waiting to be coded to an account before it means anything for a BAS or a set of financial statements. Fuel, groceries, a software subscription, a client payment, all of it starts as an uncoded line, and someone has to click through each one.

Xero's bank rules help, but only after you've already done the work once

Xero has a bank rules feature that will auto-code a transaction to an account once a rule exists for that merchant or description pattern. It's genuinely useful, but the rule doesn't exist until you create it, and you create it by manually coding that transaction the first time it shows up. On a statement you're processing for the first time, from a client you've never worked with before, none of your existing rules apply to their merchants. You're back to coding line by line until enough rules build up.

That's fine for ongoing bookkeeping, where the same client's transactions repeat month after month and the rule library grows with them. It's a much bigger ask for a one-off catch-up job covering months of statements you've never seen, from merchants that don't match anything you've coded before.

If you're starting from a PDF statement rather than a live feed, our categorised CSV converter gives most transactions a starting category before any of that coding begins.

See how it works →

What a category rule can and can't get right

A statement is really two different kinds of transaction mixed together. One kind is predictable: interest payments, transfers between your own accounts, a recurring software subscription, a loan repayment. These follow the same wording every time and a simple pattern match gets them right close to 100% of the time. The other kind is a one-off merchant name that's never appeared on this statement before and may never appear again, a local cafe, a specific tradesperson, a small supplier. No rule-based system, and honestly no AI model either, can guess a category for a business name it has no prior signal on with full confidence.

This is why any categorisation tool that claims to get everything right is either overstating it or quietly guessing. The honest version leaves the unmatched rows as Uncategorised and lets you spend your attention there, instead of re-checking rows that were already obviously correct.

In testing across statements from CommBank, ANZ, Westpac, NAB, ING, UBank, Amex, and Up, coverage landed anywhere from around 78% to 100% depending on the bank and account type. Savings accounts and internal transfers sit at the high end. Everyday spending accounts and credit cards, where discretionary one-off purchases dominate, sit lower, simply because that's where the unpredictable merchant names live.

Why this doesn't use AI

It would be easy to point a language model at a list of transaction descriptions and have it guess categories. The trade-off is that your bank statement, which shows where you shop, what you earn, and often your address, would need to leave your machine and go to a third-party model provider to do it. For financial data specifically, that's a real cost even when the provider says it doesn't retain anything.

The alternative used here is a fixed list of keyword and pattern rules, checked in a specific order so a specific merchant (a known food delivery service, say) wins over a generic word that might also technically match (a general transport keyword). It runs as a plain function alongside the PDF parsing step, nothing is sent anywhere else, and nothing is kept afterwards. It won't catch every one-off merchant name a model might guess correctly. It also won't ever send your statement anywhere to find out.

Starting from a PDF, not a live feed?

Upload the statement, get back a CSV with most transactions already assigned a category. Import that into Xero and you're coding the leftover rows, not all of them.

Try the categorised converter →Free to preview · No signup needed

Where this fits and where it doesn't

None of this replaces a live bank feed. If an account is currently active and connected, the feed is still the better long-term setup, and Xero's own bank rules will do a good job over time as they accumulate. This is specifically for the gap: statements from before the feed existed, from a closed account, or handed to you as a stack of PDFs with no feed at all. It's a step that happens before Xero sees the file, not a replacement for anything Xero already does well.