The dangerous errors in a converted bank statement are not the obvious ones. A row split in half, a description spilling into the amount column, a date reading 45/13/2026: those announce themselves the moment the file opens. The error that survives review is a single digit. A 1 read as a 7. An 8 read as a 3. The number that comes out is a perfectly well-formed amount, correctly formatted, in the right column, on a row with a sensible date and a sensible description.
Nothing about it looks wrong, because nothing about it is wrong except its value. Catching OCR digit errors in statements is therefore not a proofreading problem. It is an arithmetic problem, and it has an exact solution.
What a single misread digit actually costs
The damage from a misread digit depends entirely on which column of the number it sits in. A wrong digit in the pence position shifts a value by at most nine pence. The same misread in the hundreds column shifts it by up to nine hundred.
Take a statement that opens at 4,215.60 and carries four transactions. A card payment of 1,890.00 takes it to 2,325.60. A credit of 3,000.00 brings it to 5,325.60. A direct debit of 212.45 leaves 5,113.15. A final payment of 1,000.00 closes the period at 4,113.15, which is the figure printed at the foot of the statement.
Now suppose the 8 in 1,890.00 was recognised as a 3. The extracted debit is 1,390.00, which is 500.00 less than it should be, so every balance after it runs 500.00 high. Rebuilt from the extracted amounts, the chain reads 2,825.60, then 5,825.60, then 5,613.15, then 4,613.15. The file closes 500.00 above the statement, and the amount that caused it looks entirely ordinary.
Why eyeballing does not work
Reviewers routinely believe they will notice a wrong number. They will not, and there are three structural reasons why.
- There is no signal to notice. A misread amount is not malformed. It has the right number of decimal places, the right separators, and a plausible magnitude for the account. Visual review scans for things that look wrong, and this does not.
- You are reading the wrong document. Review happens in the spreadsheet, not on the statement page. Without the source in front of you, character by character, you have no reference for what the value should have been.
- The task defeats attention. Comparing 150 amounts against 150 amounts, digit by digit, is exactly the kind of repetitive matching where human accuracy collapses fastest, and it takes longer than the conversion did.
A misread digit in the description or reference field is often obvious, because language has redundancy and a wrong letter breaks a word. Numbers have no redundancy. Every digit is independent, so a wrong one is indistinguishable from a right one.
Why the balance chain finds it
The balance chain gives digits the redundancy they lack. Every amount on a statement participates in an equation with its neighbours: the balance after a transaction equals the balance before it plus or minus that transaction. Change one amount and the equation breaks, and it stays broken for every row that follows, because the error propagates forward and there is nothing downstream to cancel it.
This is the specific reason a misread digit cannot hide. It is not a matter of probability or of the checker being attentive: an amount that is wrong by any quantity at all shifts the chain by exactly that quantity, and the shift is arithmetic rather than visual. Of all the automatic checks that can be run on a converted statement, this is the strongest, and the error class it catches outright is the one this article is about.
Two things it does not do, stated here so the technique is not oversold. It says nothing about dates or descriptions, which take no part in the equation. And a second error that exactly offsets the first, most obviously a dropped row paired with a duplicated row of the same value, restores the chain and passes. That combination is uncommon rather than impossible, and the row count is what catches it, which is why the chain is run alongside a count rather than instead of one.
The propagation property is the one to exploit. Build a column that rebuilds the running balance from the extracted amounts, then compare it against the balance the statement itself prints on each line. Where the two differ, an amount is wrong.
In plain text: the rebuilt balances run 2,825.60, 5,825.60, 5,613.15 and 4,613.15, against printed balances of 2,325.60, 5,325.60, 5,113.15 and 4,113.15. The offset is 500.00 at row 1 and 500.00 at every row after it. A constant offset appearing at one row and holding steady from there is the signature of a single error at that row, which is far and away the commonest explanation, and the row where it first appears is the row to read against the page.
Two other things produce the same picture, so confirm rather than assume. A wrong opening balance offsets every row from the first, including row 1, which is why an offset that is already present at the top of the statement points at the opening figure rather than at any transaction. And two errors whose net effect equals the offset can mimic one error if they sit at the same row. Reading the suspect amount against the printed page settles both cases in seconds, and correcting it and rebuilding the chain settles them definitively: if the offset does not fall to zero everywhere, there is more to find.
The offset column is also a counter. One error gives you one offset that begins somewhere and never changes. Two errors at different rows give you two different offsets with a step between them, and the size of each step is the size of that individual error. You can therefore read the likely number and magnitude of the misreads straight off the column before opening the statement, and use the statement only to confirm the handful of rows the column nominates.
Running the check
- 1
Add a rebuilt balance column
Put the opening balance in the first cell, then set each cell below it to the cell above plus that row's signed amount, wrapped in ROUND to two decimals. - 2
Add an offset column
Subtract the extracted statement balance from your rebuilt balance on every row, again rounded to two decimals. - 3
Filter for non-zero offsets
Every zero is a verified row. The first non-zero value is your suspect. - 4
Read the suspect against the page
Open the statement at that transaction and compare the amount digit by digit. You are now checking one number instead of a hundred and fifty.
If your statement layout carries no per-line balance to compare against, the same logic works at page granularity using the carried-forward balance printed at each page break, and from there a halving search narrows the range quickly. That procedure is set out in what to do when a converted balance does not reconcile.
Which statements are most exposed
Recognition error tracks the condition of the page far more than it tracks which bank issued the statement. Print quality is the dominant factor, with layout, typeface, image resolution and the language of the document all contributing. The statements most likely to produce a misread digit are photographed pages, phone scans taken at an angle, re-scanned photocopies, faxed pages, and anything printed on a thermal or dot matrix printer where the strokes are broken to begin with. Heavy image compression makes it worse by smearing the very stroke junctions that distinguish a 3 from an 8.
If you are not sure which kind of document you are holding, the difference between a scanned and a text-based statement is worth two minutes, because it determines whether recognition is involved at all. For statements that only exist as a photograph, shooting the page flat, square to the camera and in even light reduces the error rate before conversion rather than after.
A statement with a genuine text layer is not immune, but it fails differently. The digits are read rather than recognised from a shape, so nothing is guessing at a stroke, and stroke-level misreads largely disappear. Values can still come through wrong: a document built with an unusual or defective font encoding can map characters to values other than the ones on screen, and a malformed text layer can extract digits that do not match the printed page. More often what goes wrong is structural, with amounts landing in the wrong column or a transaction split across two rows. The balance chain catches all of those, which is the reason to run it regardless of the source format.
The verdict should come with the file
Everything above is a procedure a competent person can run. That is the point of writing it down. It is also, honestly, a procedure nobody runs on the twelfth statement of a twelve month engagement, because building a rebuilt balance column and an offset column per file, across a roster of clients, is hours of work that produces nothing billable when it passes.
This is why the check belongs in the conversion, not after it. Convert·Into recalculates the running balance line by line on every statement and compares it against the balance printed on the document, so the offset column above is computed for you and the rows that break the chain arrive flagged. Extraction accuracy is 99.6%, which means the flagged rows are a short list rather than a second pass over the whole file.
Let the arithmetic find the digit
Hold every method to the same test
Use this as the question you ask of any approach to getting statements into a spreadsheet. Manual keying introduces transposed digits of its own and produces no control totals to catch them. A generic table extractor lifts rectangles off a page, and unless it has been given statement-specific validation rules it has no notion of an opening balance, so it cannot know that it misread a digit or dropped a row. Both leave you holding the offset column.
The limits of the technique are worth restating plainly, because they define it rather than undermine it. A balance check tests the fields that participate in the arithmetic, which is to say the amounts, and it tests them hard: no single misread amount can pass. It says nothing about a misread character in a description, a reference, a cheque number or a date, and it can be defeated by two errors that offset each other exactly, which is why it is run alongside a row count against the statement's own transaction total.
That division of labour is the useful part. Descriptions and references are the fields where a wrong character is visible to a reader, because words break in ways numbers do not, so a scan catches them. Amounts are the fields that cannot be reviewed by eye and are the fields that must be right. Those are precisely the ones arithmetic can settle, which is why a conversion that does not settle them is not finished work.
Frequently asked questions
How would I catch it if the converter read 1,890 as 1,390?
Rebuild the running balance from the amounts and compare it to the balance printed on the statement. The misread understates that debit by 500.00, so every rebuilt balance from that row onward sits exactly 500.00 too high. The row where the offset first appears is the row that was misread.
Why can I not just proofread the converted file?
Because a misread digit produces a valid, plausible number. There is no visual signal in the cell: 1,390.00 is formatted exactly like 1,890.00, sits in the right column and carries a sensible date and description. Finding it by eye means comparing every character of every amount against the source page.
Which digits does OCR confuse most often on statements?
Pairs that share a stroke pattern once print quality degrades: 1 and 7, 3 and 8, 5 and 6, 6 and 8, and 0 and 8. Thousands separators and decimal points are also confused with each other, which can shift a value by a factor of a hundred or more.
Does a balance check catch every OCR error?
No, and the distinction matters. It catches a misread digit in an amount, because a wrong amount breaks the chain arithmetically and the break persists to the end of the statement. It does not check dates or descriptions, since those take no part in the arithmetic, and errors that offset one another exactly, such as a dropped row and a duplicated row of the same value, can survive it. Pair the balance chain with a row count against the statement's own transaction count and a scan of the description column.
How do I tell one OCR error from several?
Look at the offset column. A single error produces one constant offset that begins at one row and continues unchanged to the end of the statement. Two errors at different points produce two different offsets, and the size of each step is the size of that individual error. Read the column as a map of where the errors are, then confirm each suspect row against the printed page, because a wrong opening balance produces the same flat offset from row one.
Are text-based statement documents immune to this?
No, though the failure mode differs. A statement with a genuine text layer has its digits read rather than recognised from a shape, so stroke-level misreads are far less likely. They are not impossible: a defective or unusual font encoding can map characters to the wrong values, and a malformed text layer can extract digits that are not what the page displays. The commoner text-layer failure is structural, with amounts landing in the wrong column or a transaction split across rows. The balance check catches all of those the same way.