Article
Fuzzy, Vector, or Exact: Benchmarking Inbound Account Matching on Messy B2B Data
Most Lead-to-Account (L2A) matching systems break because they treat company names as generic strings rather than specific commercial entities. When an inbound lead arrives as "IBM," "Intl Business Machines," or "I.B.M. Corp (UK) Ltd," your routing logic has to decide if this belongs to an existing enterprise account or a new territory.
Standard fuzzy matching plugins often fail here. Algorithms like Levenshtein or Jaro-Winkler are mathematically ill-suited for the specific messiness of B2B data. I ran a benchmark across four matching approaches—exact, normalized, fuzzy, and vector—to see where they break and how to build a pipeline that actually holds up under volume.
The Mathematical Failure of Edit Distance
When RevOps teams talk about fuzzy matching, they are usually talking about edit distance—the number of character changes required to turn string A into string B.
Jaro-Winkler is a popular choice because it weights matches at the start of the string more heavily. This sounds logical for company names until you test it against acronyms. In my testing, a standard 0.85 similarity threshold reliably merged "SAP" with "S&P" and "SAPA." Because the strings are short, a single character difference represents a massive percentage of the total string. The algorithm lacks the context to know that "SAP" and "S&P" are distinct multi-billion dollar entities; it just sees a 66% character overlap and a shared first letter.
Levenshtein distance is conversely too rigid. It treats "Salesforce" and "Salesforce.com, Inc." as significantly different because of the number of insertions required. If you loosen the threshold to catch the suffix variations, you inevitably start merging "Apple" with "Applied Materials." It’s a game of whack-a-mole that can't be won with simple character math.
Normalization: The Boring ROI King
Before reaching for an LLM or a vector database, you need to strip the noise. Most matching failures are caused by legal suffixes, punctuation, and inconsistent capitalization.
I tested a Python-based normalization step using the cleanco library, which is specifically built to identify and strip entity suffixes like "GmbH," "LLC," "S.A.S," and "Incorporated."
from cleanco import prepare_string
def clean_company(name):
# Lowercase, strip punctuation, remove legal suffixes
clean = prepare_string(name.lower())
return " ".join(clean.split())
# "Cisco Systems, Inc." -> "cisco systems"
# "cisco systems" -> "cisco systems"
In my benchmark, about 40% of "messy" leads that failed a raw string match matched perfectly once normalized. This is a deterministic, low-latency win. If you can match on a cleaned string, you should. It is faster, cheaper, and 100% predictable.
Where Vector Embeddings Provide Lift
Vector embeddings (like OpenAI’s text-embedding-3-small) represent company names as numerical coordinates in a multi-dimensional space. Unlike string distance, this captures semantic relationships.
Vectors are excellent at realizing that "Alphabet" and "Google" are related, or that "Facebook" and "Meta" refer to the same entity. Traditional string matching will never bridge that gap.
However, research into "dirty categories" shows that embeddings offer little benefit over string models for simple typos. If a lead types "Gogle," a vector model might correctly point to "Google," but it might also decide that "Goggle Tech" is a 0.94 match.
I found that a cosine similarity threshold of 0.92 is the "danger zone."
- >0.96: High confidence, safe to auto-match.
- 0.92–0.95: Possible match, requires a human-in-the-loop or additional signals (like country).
- <0.92: Likely a different entity.
The Recommended Tiered Architecture
A robust GTM system shouldn't pick one "winner." It should use a waterfall. You want to resolve the highest-confidence cases with the cheapest methods first.
- Email Domain Match: If the lead is
user@ibm.comand your account domain isibm.com, stop. This is the gold standard. Do not let string matching override a domain match. - Normalized Exact Match: Strip legal suffixes, remove punctuation, and compare. If they match exactly after cleaning, automate the link.
- Vector Threshold Match: For the remaining 10-15% of leads, generate an embedding. If the cosine similarity to an existing account is >0.96, auto-match.
- Human Review Queue: If the vector match is between 0.90 and 0.95, flag it in a Slack channel for the RevOps team to review.
Addressing the Counterarguments
"Why not just use an LLM for everything?" Sending every lead to GPT-4 or Claude is a common suggestion, but it’s often a bad architectural choice. LLMs are non-deterministic, relatively slow (adding 1-3 seconds to routing latency), and expensive at scale. A tiered architecture using local normalization and a few vector lookups costs a fraction of a cent per lead. Reserve the LLM for the tiny percentage of cases that fail every other tier.
"Doesn't enrichment (Clearbit/ZoomInfo) solve this?" Enrichment is a powerful signal, but it isn't a silver bullet. You will always have leads from free mail providers (Gmail/Proton) or subsidiaries using undocumented domains. If you rely solely on third-party enrichment IDs, you create a dependency on their match rates rather than your own data's integrity.
Building a custom matching pipeline is more work than buying a "black box" plugin, but it eliminates the technical debt of bad data merges. When you stop accidentally merging "Ford" and "Fordham" because of a 0.8 Jaro-Winkler score, your sales team stops complaining about stolen leads and broken routing.
— C.B.