Fuzzy matching isn't magic
Ask an analyst why a screening alert fired and the honest answer is often "the algorithm decided." That isn't a good enough answer, and treated as a final word rather than a starting point, it isn't even true. Fuzzy matching, the mechanism behind almost every sanctions and PEP screening hit, is not a black box handed down from somewhere unaccountable. It is documented, public, and tunable. The gap between an analyst who can explain why a match fired and one who can only accept or dismiss it is understanding, roughly, how that mechanism actually works.
Fuzzy matching means comparing a submitted name against a reference list not by exact string equality but by a calculated similarity score. Real names arrive misspelled, transliterated, reordered, or shortened, sometimes several of those at once, and a system that only catches an exact character-for-character match catches almost nothing that actually matters in practice.
This guide grounds every claim in one real, currently running production system rather than a textbook abstraction: OpenSanctions, the sanctions and PEP data provider behind a meaningful share of the industry's screening tools, including FinCrimeRadar's own. OpenSanctions documents its matching approaches openly, and the actual options are worth naming precisely rather than treating as interchangeable. Two older approaches, name-based and name-qualified, compare names using Jaro-Winkler string similarity combined with Soundex phonetic matching. Both are now deprecated, and OpenSanctions' own documentation is explicit that neither one reaches parity with OFAC's public Sanctions List Search tool [1]. A separate algorithm exists specifically for that purpose, reverse-engineered from OFAC's own scoring FAQ and calibrated to emulate the live public tool's behaviour [2]. The current recommended default is logic-v2, a deterministic, rule-based system that annotates parts of a name using curated, multilingual reference data before comparing anything, purpose-built to improve cross-language and cross-script matching over its predecessor [3]. Alongside it sits a regression-based approach, a logistic regression model scored across 18 separate features spanning name similarity, dates, and identifiers, not the name string alone [4].
Underneath every one of these sits a tension that no amount of tuning removes. Tighten the match threshold to cut false positives and a genuine match can slip through unflagged. Loosen it to catch more genuine matches and analysts drown in noise that was never a real hit. There is no setting that solves both problems at once. There is only an informed trade-off, made deliberately, rather than one made by accident and never revisited.
Not a computer-science specification of exact scoring formulas, and not a claim that any single number here is precise to three decimal places on every possible input. Every technical figure is sourced to a real, current primary document, listed in this site's verification ledger, and flagged honestly where OpenSanctions itself gives a range rather than a fixed value.
The 0.98 same-name problem
In a benchmark released in February 2026, researchers working with OpenSanctions' own large-scale labelled pair dataset surfaced a case that illustrates the ceiling of name-only matching better than any constructed example could. Two individuals appear on Pakistan's proscribed persons list under the identical name Khalid Mehmood. Same name, same country, same sanctions programme. They are not the same person: one record carries a national identity number ending 9885 and lists a father's name of Muhammad Khan, the other carries an ID ending 0181 and lists a father's name of Haji Muhammad. A standard rule-based matching baseline, the same category of algorithm many production screening systems still run today, scored this pair 0.98 out of a top score of roughly 1.0, functionally treating two different people as the same entity [5].
This is not a story about a badly built algorithm. Jaro-Winkler, Soundex, Levenshtein distance, whatever string-comparison method sits underneath a name-only matcher, none of them can resolve identity between two people who genuinely share a name, because the information needed to tell them apart was never encoded in the name string to begin with. That is exactly why OpenSanctions' newer algorithms don't stop at the name: name-qualified, logic-v2, and the regression-based approach all add a second identifying feature on top of the name score, a date of birth, a national ID, an address, precisely because the name alone runs out of resolving power once a name is common enough.
No amount of refining how two name strings get compared changes the outcome of the Khalid Mehmood case, because both names are identical strings. The only thing that can distinguish these two people is a second, independent piece of identity: a date of birth, a national ID number, an address. That is the entire argument for qualified and regression-based scoring over name-only matching.
The two-stage pipeline
Real production screening does not run a single calculation. It runs two distinct stages, and conflating them is the source of a lot of "why did this even fire" confusion among analysts.
Stage one is retrieval: a broad, deliberately high-recall search across the reference database that pulls in every plausible candidate, tuned to avoid missing anything, even at the cost of pulling in candidates that have no real chance of turning out to be a genuine match. Stage two is scoring: each retrieved candidate is compared against the query using whichever matching algorithm is configured, and assigned a numeric score [6]. Only candidates whose score crosses the configured threshold, 0.7 by default for OpenSanctions-backed screening, get surfaced to an analyst as a match [7].
The reason this two-stage shape matters in practice: a candidate that should never have been retrieved in stage one can still produce a specific-looking, confident score in stage two. An analyst who only ever looks at the final score has no way to tell the difference between "this is a strong match" and "this is a strong score on a candidate that shouldn't have made the candidate list in the first place." Understanding that a score is downstream of a retrieval decision, not a single self-contained judgement, is the first step toward being able to explain an alert rather than just react to it.
Transliteration and cross-script matching
Comparing a Latin-alphabet name against its Arabic, Cyrillic, or CJK rendering is a live, actively maintained engineering problem, not solved theory sitting quietly beneath whichever algorithm a screening tool advertises.
A concrete, dated example: OpenSanctions' underlying matching engine shipped a fix in May 2026 for a specific class of bug in cross-script candidate handling. Before the fix, a Latin-script candidate that already carried strong supporting evidence of a genuine match could still be silently outranked at the retrieval stage by an unrelated candidate whose name happened to render in Arabic, Cyrillic, or another script, purely because of how script-based weighting was calculated when candidates were first pulled in, not because the final score itself was wrong. The fix aligned that retrieval-stage weighting with how the scoring stage actually values evidence, so a same-script candidate with genuine supporting evidence is no longer pushed out by a same-name candidate in a different script that carries none [8].
The lesson for a practitioner is not the specific bug, which is already fixed. It is that transliteration and cross-script handling are not a fixed, solved layer sitting underneath whichever algorithm a vendor advertises. They are actively maintained logic that can and does change between versions, which is exactly why pinning a specific algorithm version matters for regulatory consistency: a compliance team that cannot say which version of the matching logic produced a given day's alerts cannot fully explain why alert volume shifted.
Corporate suffix and patronymic noise
A more everyday version of the Khalid Mehmood problem shows up in two places: corporate suffixes and patronymics.
Corporate suffixes, LLC, OJSC, SA, Trading, Limited, and the like, are exactly the kind of variation a naive matcher can treat as a meaningful difference when it usually isn't one. "Global Trading Ltd" and "Global Trading OJSC" are, in the large majority of real cases, worth comparing as the same underlying entity name with an incorporation-type suffix attached, not two unrelated companies. Patronymics, name elements built from a parent's given name and common across Slavic, Arabic, and other naming conventions, create a related kind of noise: they look like meaningful, distinguishing name content to a naive matcher but often carry less weight in practice than the rest of the name.
Stripping this noise reduces false positives caused by suffix and patronymic variation, and current matching approaches do some version of it deliberately [9]. OpenSanctions' logic-v2 approach explicitly annotates and de-prioritises generic terms like these using curated reference data, rather than removing them outright [3]. Done carelessly, though, the same stripping logic can cut too deep and remove a part of a name that was genuinely doing distinguishing work, the same failure mode as the case study above, approached from the opposite direction: instead of a name-only score missing a real difference because two people share a common core name, an over-aggressive stripping rule can manufacture a false similarity by deleting the exact part of a name that would have told two entities apart.
Building a test set before changing anything in production
Everything covered so far points to the same practical conclusion: never change a threshold or an algorithm version based on a handful of recent alerts. Measure it first.
A golden test set is a fixed, held-out collection of known true-positive and true-negative name pairs, used specifically to check whether a proposed tuning change actually improves matching before it reaches production, not after. At minimum, a usable one should contain:
- Known sanctioned names across multiple scripts, so a cross-script regression gets caught before it reaches production.
- Common-name collision pairs, like the Khalid Mehmood case above, so name-only overconfidence gets caught rather than assumed away.
- Real historical false positives from the reader's own alert history, because every screening population has its own recurring noise patterns a generic test set will not cover.
- Deliberately difficult transliteration variants, chosen specifically to stress-test the matcher rather than flatter it.
The discipline this replaces is dangerous precisely because it feels reasonable in the moment: a threshold nudged up because analysts complained about noise last week, or nudged down because someone worried about a near miss, with no measurement of what that change actually does to the true-positive and false-positive rate against a fixed reference. A golden test set turns "I think this change helped" into something a compliance team can actually show a regulator.
The Algorithm Pipeline Visualizer
Four name pairs, walked through both pipeline stages exactly as described above. Every score and feature value below is a fixed, pre-written illustration of how each pair is scored, not a live recalculation, so the numbers stay identical no matter how many times you replay them.
All four feature values above are fixed illustrative figures written to demonstrate how each stage reasons about a pair, based on the real mechanics described in the sections above. They are not live recalculations and will not change between visits.
Now you try
Three fresh name pairs. Predict match or no match before revealing the answer.
FinCrimeRadar's own screening tool calls OpenSanctions' live /match/default endpoint, the same retrieval-and-scoring pipeline described above, not a simulation of it. Try a real name against it →
Four ways tuning goes wrong
The risk each pattern creates, the signal that tells you it's happening, and the response that actually fits.
FAQ
Sources
Each numbered claim above is checked against the specific source below it. Figures without a bracketed number are illustrative examples rather than verified facts; the surrounding text says which.
- OpenSanctions, Matcher: Deprecated Matching Algorithms (name-based, name-qualified; Jaro-Winkler and Soundex, do not reach OFAC parity). opensanctions.org/matcher
- OpenSanctions, Matcher: ofac Algorithm (reverse-engineered from OFAC FAQ #249 and parity fixtures against the live public tool). opensanctions.org/matcher
- OpenSanctions, Matcher (logic-v2) and API: Tuning the Matching System (rule-based, cultural reference data, recommended for new integrations). opensanctions.org/matcher / opensanctions.org/docs/api/tuning
- OpenSanctions, Matcher: regression-v1, 18-feature table (name, phone, email, identifier, DOB, gender, country, address features), confirmed by manual count. opensanctions.org/matcher
- Konstantin, N. et al., OpenSanctions Pairs: Large-Scale Entity Matching with LLMs, arXiv:2603.11051, February 2026, Figure 1. arxiv.org/abs/2603.11051
- OpenSanctions, API: Tuning the Matching System (two-stage retrieval-then-scoring pipeline). opensanctions.org/docs/api/tuning
- OpenSanctions, API: Tuning the Matching System (0.7 default match-score threshold). opensanctions.org/docs/api/tuning
- opensanctions/yente, GitHub Releases, v5.4.0, 13 May 2026 (cross-script candidate ranking fix). github.com/opensanctions/yente/releases/tag/v5.4.0
- OpenSanctions, Changelog #32, API Service Backend Upgrades, effective 8 September 2025 (company suffix/prefix matching, cross-script retrieval). opensanctions.org/changelog