Duplicates
Finding the same charge imported twice, deciding what to keep, and undoing a delete.
Re-uploading a statement you already loaded is harmless — every transaction has an id derived from its date, description, and amounts, so the second copy is recognized and skipped.
The problem this screen solves is the other kind: the same charge arriving twice by different routes, where the two rows aren't byte-identical and so aren't the same transaction as far as the id is concerned. A credit-card CSV and the PDF statement covering the same month. A checking export downloaded in two overlapping date ranges from a bank that words its descriptors slightly differently each time. Those become two transactions, and they inflate every total you look at.
Running a scan
Duplicate detection is a scan you run, not something happening in the background. Open Duplicates and choose Scan now. The scan reads your whole history in date order and reports progress as it goes; you can leave the screen while it runs.
Results are stored, so a report stays on the screen after a reload, and everyone in a shared workspace sees the same one. When transactions have changed since a report was generated, the screen says the report is stale and offers a re-scan rather than quietly showing you old findings.
What counts as a duplicate
A pair becomes a candidate only when all of these hold:
- Both rows fall on the same calendar day. This used to be a two-day window; it was tightened because real duplicates post on the same day, and the wider window swept in genuinely distinct same-amount charges a day or two apart.
- The debit and credit amounts match exactly. No tolerance.
- The descriptions are similar — either identical after normalization, or sharing enough words to clear a similarity threshold. That's what lets
AMAZON.COM*2H4XY9andAMAZON MKTP USpair up.
And the pair is skipped outright when any of these is true:
- Both rows came from the same uploaded file. A statement that genuinely lists a charge twice — two identical coffees on the same day — is preserved at import, and it is almost never a duplicate.
- Either row carries reference numbers that the other doesn't share. Two rows with clearly different confirmation, check, or order numbers are different transactions no matter how alike the rest reads.
- You have already said they aren't duplicates. See below.
Candidates are grouped into clusters — everything transitively linked — so three copies of one charge come to you as one group, not three pairs.
Working through the results
Each cluster lists its transactions with a decision per row: keep or delete. Nothing is applied while you're deciding.
- Keep one picks a survivor and marks the rest for deletion. It prefers a row you have already edited — one carrying an override category or tags — because that's the copy holding your work. Otherwise it keeps the first.
- Keep one in every cluster does that across the whole report, for clusters you haven't already dismissed.
- Not duplicates dismisses the cluster. That's a durable decision, not a hide: those transactions will not be paired again in future scans. Use it for the real same-day-same-amount coincidences — two identical fares, two identical coffees.
Your in-progress decisions survive a page reload. A fresh scan starts them over, because it's a fresh report.
When you're satisfied, commit. The confirmation names the counts before anything happens.
Deleting here is permanent
This is the one place in the app where a delete is a hard delete. Rows removed by a duplicate commit are gone — they are not in the Deleted transactions view and cannot be undone.
That's deliberate: the whole point is that these rows should never have existed, and leaving tombstones for them would mean carrying the noise you just removed. Deleting a transaction anywhere else in the app — a row on the Transactions screen, a row in the uncategorized queue — is a recoverable soft delete instead. See Your data.
If you're unsure about a cluster, Not duplicates is the safe answer. It costs you nothing and it teaches the scanner.
When a duplicate isn't caught
The scan is conservative by design — a false negative leaves you with a number that's too big, and a false positive offers to delete a real charge. If two copies of a charge post on different days, or their descriptions have nothing in common, they won't be paired. Delete one by hand from the Transactions screen; that delete is recoverable.