How accurate is StatementCheap? Our test method and results
In our latest test, on October 29, 2026, StatementCheap extracted all 628 transactions from 8 test statements with the right date and amount, and all 8 statements reconciled to the cent. It took about 4 seconds per page. The test statements are synthetic: realistic layouts filled with made-up data. The limits are listed below.
The short answer
On our test set, StatementCheap made no errors in dates or amounts, and every statement balanced to the cent. Descriptions matched word for word on 6 of the 8 statements.
| Measure | Result |
|---|---|
| Transactions found with the correct date and amount | 628 of 628 (100%) |
| Extra transactions that weren't on the statement | 0 |
| Statements that reconciled to the cent | 8 of 8 |
| Signs (money in vs money out) wrong | 0 |
| Dates with the wrong year | 0, including a statement that runs from December into January |
| Printed running balances read correctly | All of them, on the 5 statements that print one |
| Average speed | About 4 seconds per page (104 seconds for 26 pages) |
| Password-protected PDF and a non-statement PDF | Both refused with a clear message |
How does the balance check work?
Every statement prints an opening balance and a closing balance. If every transaction was read correctly, the opening balance plus money in minus money out equals the closing balance, to the cent. StatementCheap runs that check on every conversion and shows you the result before you download.
It runs three checks:
- The whole-statement check. Opening balance + money in − money out = closing balance. A missed row, a duplicated row or a misread amount almost always breaks this.
- Running balances, row by row. Many bank statements print a balance after each transaction (or after the last one each day). Each printed balance must equal the previous balance plus the transactions since then. When one doesn't, we mark that row, so you know exactly where to look.
- Sign repair. The most common extraction mistake is a sign: a deposit read as a withdrawal. When a running balance is printed, we flip a row's sign only if flipping it makes the balance arithmetic exact. When there's no running balance, we use the statement's printed totals (total deposits and total withdrawals) or the opening and closing balances to find a statement-wide swap, or one or two rows whose flip makes everything add up exactly. If no single fix works, we leave the data alone and show a mismatch.
Credit cards work the same way, but the balance is what you owe: new balance = previous balance + purchases, fees and interest − payments and credits.
Worked example
A statement opens at 1,000.00 and closes at 3,329.63. Here are its rows, with the balance the statement prints after each one:
| Date | Description | Amount | Printed balance | Previous balance + amount | Check |
|---|---|---|---|---|---|
| 09/02 | Payroll deposit | +2,500.00 | 3,500.00 | 1,000.00 + 2,500.00 = 3,500.00 | ✓ |
| 09/05 | Check 1042 | −640.00 | 2,860.00 | 3,500.00 − 640.00 = 2,860.00 | ✓ |
| 09/12 | Refund, office supplies | +84.37 | 2,944.37 | 2,860.00 + 84.37 = 2,944.37 | ✓ |
| 09/18 | ACH electric utility | −142.10 | 2,802.27 | 2,944.37 − 142.10 = 2,802.27 | ✓ |
| 09/30 | Transfer from savings | +527.36 | 3,329.63 | 2,802.27 + 527.36 = 3,329.63 | ✓ |
Whole statement: 1,000.00 + 3,111.73 (money in) − 782.10 (money out) = 3,329.63, which equals the printed closing balance. The statement reconciles.
Now say the refund on 09/12 had been read as −84.37. The row check fails right there: 2,860.00 − 84.37 = 2,775.63, not the printed 2,944.37. Flipping the sign to +84.37 makes that row and every row after it add up exactly, so the sign is repaired. If the amount itself had been misread, say 48.37 instead of 84.37, no sign flip would fix it. That row would be flagged and the result marked as a mismatch.
What you see after a conversion
- Reconciled: the transactions add up from the opening balance to the closing balance, and every printed running balance matches.
- Doesn't fully reconcile: we show the difference and highlight the rows where the running balance stops adding up. Check those rows against the PDF before you import anything.
- Balances not found: the statement doesn't print the balances we need, so there's nothing to check against. Review the rows yourself.
What did we test?
We tested 8 synthetic statements with 628 transactions over 26 pages, in US, UK and European formats. A script generates them with fake banks, people and merchants, and writes down the correct answer for every row at the same time. Each one copies a layout problem that real statements cause.
| Test statement | What makes it hard | Pages | Transactions |
|---|---|---|---|
| US checking | Dates printed without a year, beginning and ending balance and totals rows inside the table, a daily balance grid, a promo box with dollar amounts | 1 | 21 |
| US checking, signed amounts | One amount column with minus signs for debits, a running balance on every row, a fee summary table | 2 | 44 |
| US checking, year boundary | Runs from December 2025 into January 2026 with "Mon DD" dates, two-line descriptions, a check number column, a balance only on each day's last row, and a "summary of checks" that repeats rows (which must not be counted twice) | 3 | 50 |
| US credit card | Purchases, a payment, merchant credits marked "CR", a foreign purchase with an exchange rate line, transaction and posting dates, interest and minimum payment tables to ignore | 2 | 30 |
| US business, long | 14 pages, separate debit and credit columns, no running balance, many two-line ACH and card descriptions | 14 | 410 |
| UK current account | DD/MM/YYYY dates printed only on each day's first row, payment type codes (DD, SO, FPI), paid out and paid in columns in pounds, "balance brought/carried forward" lines at page breaks | 2 | 38 |
| German (EU) statement | DD.MM.YYYY dates, amounts written 1.234,56, euros, booking and value dates, descriptions over two or three lines, no running balance | 1 | 14 |
| Scanned statement | An image-only copy of the first statement, with no text layer: 150 dpi grayscale, rotated slightly, blurred, with added noise | 1 | 21 |
We also checked that a password-protected PDF and a one-page letter that isn't a statement are both refused with a clear error, and not charged.
Results
| Test statement | Correct transactions | Reconciled | Descriptions | Time |
|---|---|---|---|---|
| US checking | 21 / 21 | Yes, difference $0.00 | Identical | 7.2 s |
| US checking, signed amounts | 44 / 44 | Yes, $0.00 | Identical | 14.6 s |
| US checking, year boundary | 50 / 50 | Yes, $0.00 | Identical | 14.5 s |
| US credit card | 30 / 30 | Yes, $0.00 | Identical | 8.1 s |
| US business, 14 pages | 410 / 410 | Yes, $0.00 | Identical | 32.1 s |
| UK current account | 38 / 38 | Yes, £0.00 | 89% word overlap (see below) | 14.6 s |
| German (EU) statement | 14 / 14 | Yes, €0.00 | Identical | 5.5 s |
| Scanned statement | 21 / 21 | Yes, $0.00 | 99% word overlap (see below) | 7.1 s |
| Total | 628 / 628 | 8 / 8 | 103.7 s for 26 pages |
The description differences were small:
- UK statement: the payment type code printed in its own column (such as DD, SO or DEB) was left out of the description, so "DD SKYLINK BROADBAND" came out as "SKYLINK BROADBAND". Our reference answer included the code.
- Scanned statement: two words were misread from the blurred image. "QUIKFUEL" came out as "QUICKFUEL", and a repeated word ("INS INS") was read once.
Speed: the long 14-page statement took 32 seconds, because pages after the first are read in parallel. The times include uploading the file and were measured one file at a time.
How we scored it
- A transaction counts as correct when its date and amount match the reference answer to within half a cent. Each reference row can match only one extracted row, so duplicates count as errors. For the credit card and German statements, either of the two printed dates (transaction or posting, booking or value) counts.
- Descriptions don't affect the count. We compare them separately, by the share of words they have in common.
- "Reconciled" is the status StatementCheap itself reported for each statement, which we also confirmed against the reference opening and closing balances.
- The test ran against the live site, through the same upload API the website uses, with the AI model the site uses (DeepSeek V4.1 Flash on Cloudflare Workers AI).
- The test script is
scripts/eval.mjsand the statements are generated byscripts/make-fixtures.mjs. Both are deterministic, so the same statements can be rebuilt and re-run.
What are the limits of this test?
This is a small, synthetic test, so treat it as evidence that the method works, not as a guarantee for your statements.
- Synthetic, not real banks. The statements copy real layout problems, but they aren't real statements from real banks. We don't keep the statements people upload, so we can't test on them. Real statements will produce errors this test didn't catch.
- Small sample. 8 statements and 26 pages. A larger and more varied set would give a more reliable number.
- One simulated scan. The scanned test is a clean statement turned into a degraded image. Real scans vary more. Phone photos of paper statements were not tested.
- No balances, no check. When a statement doesn't print an opening and closing balance (some card statements and transaction histories), the balance check can't run, and the result is marked as not checked.
- The check covers amounts, not everything. A reconciled statement can still have a wrong date or description, because those don't change the totals. In rare cases, two errors can cancel each other out.
- One run, one model. AI output can vary between runs, and we may change models. We re-run this test after changes that affect extraction and update this page.
How to check a conversion yourself
You can verify any conversion in a few minutes with Excel or Google Sheets. Put dates in column A, descriptions in B and signed amounts in C (money in positive, money out negative).
- Count the rows. Compare the number of transactions with the statement. Many statements print a count of deposits and withdrawals in the summary box.
- Compare the totals.
=SUMIFS(C:C,C:C,">0")should equal the statement's total deposits, and=-SUMIFS(C:C,C:C,"<0")its total withdrawals. - Roll the balance forward. With the opening balance in F1 and the closing balance in F2,
=ROUND(F1+SUM(C:C)-F2,2)should return 0. For a credit card, use=ROUND(F1-SUM(C:C)-F2,2), with the balances as amounts owed. - Find the first broken row. If the statement prints running balances, add them in column D and follow the steps in how to reconcile a bank statement in Excel. A formula there finds the first row where the balance stops matching.
- Spot-check dates and descriptions. The balance check can't see these. Look at the first and last rows of each page, and at any month or year change.
The size of a difference is a clue. If it equals one transaction, a row is missing or duplicated. If it's twice a transaction, a sign is flipped. If it divides evenly by 9, two digits were probably swapped.
Last tested
October 29, 2026, on the live site, with the 8 statements above. The test is re-run after changes that affect extraction, and this page is updated with the new results, good or bad.