Refolk
TeardownProcess, data, and compliance

Reconciling Two Account Lists Into One Company Universe

You can run a two-list company reconciliation end to end and arrive at a defensible single record count you can defend to your team.

17 min readLast reviewed August 9, 2026Read as Markdown

You have two company lists from different sources - a CRM export and a sourced list, say - and you need to fold them into one deduplicated master without losing records or over-merging distinct firms. This guide is for the RevOps, data-ops, and data-steward roles answerable for how that master was built. It carries one reconciliation all the way through, with the intermediate counts at each fork, including the false-merge that had to be undone.

Most cleanup guides stop at an abstract merge-or-keep rubric. This one shows the arithmetic: how many pairs the exact pass removes, how many the normalization step recovers, how many the review queue catches, and where the count moves when a wrong merge gets rolled back. Follow along on your own two lists.

What reconciling two account lists actually requires

Reconciliation means resolving two company lists into one set of golden records where each real-world firm appears exactly once, with a count you can defend and an audit trail you can show. It is not a single button. It is a pipeline: normalize, exact-match, fuzzy-score, band by confidence, review the ambiguous middle, apply survivorship, and log everything.

The hard part is not the matching. It is the asymmetry between the two ways you can be wrong. A missed duplicate leaves two records where there should be one - annoying, recoverable, visible. A wrong merge deletes a real record and reparents its children onto the wrong firm, and in most CRMs that cannot be undone. Every threshold decision downstream is a response to that asymmetry.

A wrong merge is much harder to undo than a missed duplicate, and every threshold you set is an answer to that fact.

I will use one worked case throughout, drawn from a documented reconciliation. Treat its numbers as illustrative of shape, not as a benchmark. In that case the pre-merge account duplicate rate was 21.4 percent, high-confidence pairs at or above 90 percent similarity made up 66 percent of candidate pairs, the merge itself succeeded 99.4 percent of the time, 22 merges needed rollback, and the final account count fell 19.6 percent. Those figures anchor what "normal" looks like at each stage below.

Why exact matching alone leaves duplicates on the table

Exact matching misses true duplicates by design, not by mistuning, and that structural blind spot is exactly what the normalization step exists to recover. Understand this before you set a threshold, because it explains why you cannot skip preprocessing.

The reference implementation of native dedupe compares configurable fields through matching rules that build match keys, then only compares records that share a key. If two records do not share a match key, they are never considered duplicates - they are not scored at all. So a single domain typo, or "Acme Inc" against "Acme, Inc.", produces different keys and the pair becomes invisible. Exact-key matching misses a lot of true duplicates, and fuzzy scoring is what catches those missed pairs.

Two more limits worth knowing before you lean on native tooling. Native merge handles accounts, contacts, and leads but only three records at a time, with no automation and no cross-object support. And you are capped at five duplicate rules per object. For a two-list reconciliation of any size, that pushes the real work into staging tables you control.

15-25%
Match-rate lift from preprocessing alone
Achieved before you change the matching algorithm at all, by lowercasing, suffix stripping, and domain extraction.

The lesson: no clever similarity algorithm rescues a pipeline that skipped normalization. The 15 to 25 percent preprocessing lift is recovered before any algorithm change, which means it is the cheapest accuracy you will ever buy.

Normalizing company names without over-merging

Normalization resolves cosmetic variants of the same name to one canonical value so the exact pass can catch them, but it has a ceiling and a trap you must respect. Do the high-impact steps, stop where meaning begins.

The steps that pay, in rough order of impact:

  • Lowercasing and stripping common legal suffixes (Inc, LLC, Corp, Ltd) give the biggest accuracy gains. A named Python package, cleanco, does the suffix work.
  • Removing punctuation is the next highest-impact step.
  • Normalizing whitespace collapses double spaces and stray tabs.
  • Root-domain extraction reduces every website to a stable key, which is often more reliable than the name.

Deterministic rules like these resolve about 85 to 90 percent of company-name cases instantly. But name normalization only fixes legal forms. It does nothing for common business words like Group, Holdings, and Solutions, and standard fuzzy matchers treat every token equally, so they fail on company names built from those words. The residual 10 to 15 percent is not a compute problem you can grind through - it is judgment.

The trap sits at the other extreme. Strip too much and you destroy real distinctions. Removing geographic qualifiers can merge "Toyota Motor Corporation Japan" and "Toyota Motor Manufacturing Kentucky" - the same brand, but different legal entities. This is the over-normalization false-merge, and it is why step one keeps the raw name in a separate field. Always run normalization on a staging copy and keep company_name_raw before you overwrite anything.

There is a genuine disagreement in the field about ordering. Some sources normalize, then exact-match, then fuzzy-score. Others argue that token weighting should replace heavier normalization rather than follow it, because down-weighting generic tokens does the entity-distinction work that suffix stripping cannot. For a two-list reconciliation I favor normalize-then-exact-then-fuzzy, then add rarity weighting inside the fuzzy step. That keeps the cheap deterministic wins while handling the business-word residual where it actually lives.

Setting the auto-merge, review, and reject thresholds

Set three bands - auto-merge, review, reject - and put the auto-merge cutoff high enough that a machine decision is effectively certain. Practitioners disagree on the exact numbers but agree on the shape and on which direction to bias.

Here is where published cutoffs land. Note they are expressed on different scales; read each row against its own source.

SourceAuto-merge cutoffReview-band floorReject below
Plauti99-100% (97-98% with AI)80-85%below review
Supportbench0.95-1.00mid-range-
Neo4j (compliance preset)0.980.90<0.90
Neo4j (balanced preset)0.950.85<0.85
Primentra>0.920.75-0.92<0.75
Salesforce DQE FAQ80-90%below 80-90%-

The spread is real, but the logic collapses to one principle: auto-merge only pairs at a very high confidence on high-certainty fields, queue the middle range for a human, and auto-dismiss pairs below the floor. Given that merges are permanent, I default to the precision-heavy end - 0.98 or higher for auto-merge, roughly 0.85 to 0.98 for review - and I require at least one hard identifier in the auto band regardless of name score.

That last requirement matters more than the number. Field completeness, not name similarity, often decides the case. The same Acme pair scores about 0.94 with a matching VAT number but only about 0.78 without it. So a real duplicate lands in the review queue not because its names are far apart but because a hard identifier is missing. Do not chase that gap by lowering the name threshold - you will import false merges.

The merge decision by name score and hard-identifier match

Hard identifier matchesNo hard identifier
Reject
Auto-dismiss as distinct
Review
Queue it; a matching domain or VAT can still rescue a weak name
Review
Queue it; a high name score without a hard ID is not enough to auto-merge
Auto-merge
Safe band; high name score plus matching hard identifier
Name score lowName score high
Two variables, not one, decide whether a pair is safe to auto-merge.

The worked reconciliation, stage by stage

Run the pipeline in the fixed order below, recording a count at every stage so the final number is traceable back to raw rows. This is the part you follow with your hands.

Two-list company reconciliation, end to end

  1. Stage and profile both lists
    Load each source into a staging copy, count raw rows per list, and keep the raw name in company_name_raw before overwriting. Done when you have two immutable raw tables with row counts recorded.
  2. Normalize deterministically
    Lowercase, strip punctuation, strip legal suffixes, normalize whitespace, and reduce websites to a root domain. Done when both lists carry a canonical key column.
  3. Run the exact/key match pass
    Join on normalized name and root domain and record how many pairs match exactly. Done when you have a count of exact matches removed before fuzzy scoring.
  4. Fuzzy score the remainder
    Block candidates, then score with token and Levenshtein methods, weighting unique fields highest so email, phone, and domain outweigh city or generic tokens. Done when every remaining pair carries a 0-100 score.
  5. Band and route by confidence
    Set auto-merge, review, and reject cutoffs; auto-merge only very high-confidence pairs on hard identifiers, queue the middle, dismiss below the floor. Done when you have three named buckets with counts.
  6. Work the review queue
    Mark every queued pair merge or keep-separate with a logged reason, and track the steward reject rate. Done when the queue is empty and every decision is recorded.
  7. Apply survivorship and merge in staging
    Pick the survivor by the pre-declared rule, back up first, merge accounts before contacts, and confirm ownership points to the master. Done when each cluster resolves to one golden record.
  8. Write the audit log and validate
    Record kept and discarded values, moved children, IDs, user, and timestamp, then compute the final unique count and coverage. Done when you have a defensible single record count and an audit file.

Now the arithmetic on the documented case, so you can see how the count moves. The two staged lists carried a pre-merge duplicate rate of 21.4 percent. Normalization and the exact pass cleared the cosmetic variants. Fuzzy scoring split the remaining candidate pairs: 66 percent scored at or above 90 percent (the high-confidence band), 22 percent landed in the 60 to 89 percent medium band and went to review, and the tail below that was dismissed. Survivorship and merge ran at a 99.4 percent success rate. Twenty-two merges later needed rollback. The final account count fell 19.6 percent, a hair under the 21.4 percent raw duplicate rate - the gap between those two numbers is exactly the distinct firms the review queue protected from over-merging.

StageValue
Account duplicate rate (pre)21.4%
High-confidence pairs (≥90%)66%
Medium-confidence (60-89%)22%
Merge success rate99.4%
Merges needing rollback22
Final account count reduction19.6%

How candidate pairs narrow across the pipeline

  1. All candidate pairs
    100%

    after blocking

  2. High-confidence (≥90%)
    66%

    auto-merge band

  3. Medium (60-89%)
    22%

    goes to review

The review queue sits at the 22 percent medium band, where judgment replaces compute.

The 22 rollbacks are the point of this teardown. In that case, a batch of pairs auto-merged on high name similarity where the clusters actually spanned two legal entities - the over-normalization trap. The fix was not a better algorithm. It was re-inspecting every cluster that spanned two countries against the retained raw name, unmerging the false pairs, and adding a rule that a country or tax-ID conflict blocks auto-merge no matter the name score. Keep the raw name and you can undo this in an afternoon. Discard it and you are guessing.

When your source lists are themselves sparse or inconsistent, describing what you want in plain language beats hand-stitching filters. I built Refolk so you can ask for exactly the segment you need and get back people who match, without reconciling three exports first.

Choosing which record survives the merge

Survivorship is the rule that decides which record wins when a cluster collapses to one, and you declare it before you look at the data, not after. Guessing per-cluster is how bias and stale values sneak onto the golden record.

Three techniques are documented, and best practice stacks them rather than picking one:

  • Most Recent orders date-stamped records newest first and keeps the newest.
  • Most Frequent treats a value that repeats across records as reliable.
  • Most Complete favors the record with the fewest incomplete or empty attributes.

On top of those, add source precedence: prioritize authoritative systems so the CRM of record beats a sourced list on ties. Stacking system priority with completeness leads to fewer null values and more accurate survivorship. Document the stack in writing before you merge.

Survivorship rule stack (fill in before merging)
1. Source precedence: system_of_record > enrichment_vendor > sourced_list
2. Most Complete: field-level, non-null and non-placeholder value wins
3. Most Recent: on a real business event date, NOT system-modified date
4. Most Frequent: value appearing in the majority of cluster records
5. Tie-break: manual steward decision, reason logged

Apply in order; the first rule that produces a clear winner decides that field. Record the version alongside the audit log.

Two traps here. First, recency poisoning: survivorship on most-recent updates gets thrown off by metadata updates from a nightly batch run, which stamps every record "modified today" and hands the golden record whichever happened to run last. Use a real business timestamp, not the system-modified date. Second, treating missing as evidence. Absence of a value is missingness, not proof of anything - a caution the source data itself illustrates. In Refolk's index, only 42 of 1,075 US RevOps managers explicitly list "Salesforce" as a skill, 3.9 percent, despite the tool being near-universal in the role. If you scored "most complete" naively, you would penalize records for an absence that means nothing.

3.9%
US RevOps managers who explicitly list Salesforce as a skill
42 of 1,075 in Refolk's index - a reminder that a blank field is missingness, not evidence, when you set "most complete."

Where reconciliation goes wrong

The failure modes below are the most valuable part of this standard, because each one produces a plausible-looking master that is quietly wrong. Learn the tell and the check for each.

Failure modeWhat it looks likeCheck
Over-normalization false-mergeTwo legal entities of one brand collapse into one recordKeep raw name; re-inspect any cluster spanning two countries or tax IDs
Common-word false positive"Acme Group" and "Beta Group" score as a pairDown-weight generic tokens (Group, Holdings, Solutions) or use rarity weighting
Short-name false merge"CBS" and "NBC" score high below an 80% thresholdEnforce minimum character length; raise the cutoff for names under ~4 tokens
Recency poisoningNightly batch stamps every record "modified today"Use a real business timestamp, not system-modified date
Thin-scenario over-matchingA two-field rule calls unrelated records duplicatesRequire at least one hard identifier (domain, tax/VAT, phone) in the auto band
Recycle-bin illusionA restored merge looks whole but children are goneVerify child-object counts on the survivor, not just record existence

Two of these deserve extra weight because they cost the most to recover from.

The first is the irreversible merge with no log. Native merges delete the losing records, reparent their contacts, opportunities, and activities onto the survivor, and cannot be undone. There is no native merge-history tracking, so once it runs you cannot even trace which accounts were merged or when. The recycle bin is a false comfort: deleted duplicates sit there up to 30 days, but restoring one does not reinstate its relations to child objects that were reparented onto the master. The check is procedural, not technical - sandbox test, export first, and write your own merged-ID audit table.

The second is the review queue as false comfort. The queue is a sensor, not a chore. Its size and the steward's reject rate read out whether your thresholds are set right. A queue of 30 to 50 pairs a week is healthy; a queue of 5,000 a week means the thresholds are wrong. If the steward is rubber-stamping everything, the threshold is too cautious. If they are rejecting half, it is too aggressive. When the queue explodes, recalibrate the bands - do not hire.

Proving the result and keeping it clean

Close the job with two load-bearing metrics and an audit file, then set a guardrail so the duplicates do not grow back. A single record count means nothing without the coverage figure and the log behind it.

The two metrics to report:

  • Match coverage (recall): the percentage of records that can be accurately linked to their true counterpart. This tells you how many duplicates you caught.
  • Duplicate creation rate: the volume of new duplicates appearing after cutover. Track it against a documented target of under 1 percent of new records. In the worked case the ongoing rate settled at 0.8 percent, inside target.

The audit log is what makes the count defensible. A post-merge report should show which records were merged, which field values were kept or discarded, which related records were moved, plus the user and timestamp - a full trail essential for compliance and troubleshooting. Build it as an external table, because the CRM will not build it for you.

From two raw lists to a defensible count with a trail

  1. Stage
    Two immutable raw tables, row counts recorded
  2. Match
    Exact count removed, then fuzzy scores assigned
  3. Band and review
    Three buckets, steward decisions logged with reasons
  4. Merge in staging
    One golden record per cluster, survivor rule applied
  5. Audit and validate
    Kept/discarded values, moved children, IDs, user, timestamp
Every stage writes a number and a log entry, so the final count is traceable to raw rows.

Before you call the reconciliation done

  • Raw row counts for both lists are recorded and the raw name is preserved in a separate field
  • Exact-match count is logged before any fuzzy scoring ran
  • Auto-merge, review, and reject bands are named with counts, and the auto band required a hard identifier
  • Every review-queue pair is marked merge or keep-separate with a logged reason
  • Survivorship rule stack was declared in writing before the merge, using a business timestamp not system-modified date
  • A full export/backup exists and the merge ran in staging, not production
  • Every cluster spanning two countries or tax IDs was re-inspected against the raw name
  • Child-object counts on each survivor were verified post-merge
  • An external audit table holds merged IDs, kept/discarded values, moved children, user, and timestamp
  • Final unique count, match coverage, and duplicate creation rate against the under-1% target are reported

To keep the universe clean after cutover, re-run the creation-rate check on a schedule and treat any drift above 1 percent as a signal that an upstream feed is writing un-normalized names. The mechanism to watch is the same one that created the duplicates in the first place: a source that skips normalization will regenerate variants faster than you can merge them. Fix it at the intake, not the master. When you need to rebuild or extend the list of firms behind this universe, describe the segment you want in plain English rather than reconciling yet another export by hand - that is the friction the whole pipeline exists to remove.

Questions practitioners ask

What confidence threshold should I use to auto-merge accounts?

Bias toward precision because a wrong merge is much harder to undo than a missed one. Published sources cluster tightly: 99 to 100 percent for automated merging, dropping to 97 to 98 percent only with AI recommendation, 0.95 to 1.00 as a safe zone, and above 0.92 as a candidate. Anything below roughly 80 percent for review, and require at least one hard identifier like domain or VAT in the auto band.

How many company duplicates does exact matching miss?

A precise published percentage is not established, so treat any single figure with caution. What is quantified is the recovery: preprocessing alone lifts match rates 15 to 25 percent before you change the algorithm. Exact matching's blind spot is structural, not a tuning error, because records that do not share a match key are never scored at all, so a domain typo or suffix variant makes a true duplicate invisible.

Which record should win when I merge two companies?

Pick the survivor by a rule you declared before you looked at the data. The three documented techniques are Most Recent, Most Frequent, and Most Complete, usually stacked with source precedence so an authoritative system wins ties. Prefer a real business timestamp over system-modified date, since nightly batch jobs can poison a most-recent rule and write stale values onto the golden record.

How do I make a CRM merge reversible?

You largely cannot, so build the safety net outside the merge. Native merges delete the losing records, reparent their children onto the survivor, and cannot be undone, with no native merge history. Test in a sandbox, export a full backup first, and write your own audit table capturing merged IDs, kept and discarded field values, moved children, user, and timestamp. Restoring from the recycle bin does not reinstate reparented child relations.

How big should my review queue be?

A queue of 30 to 50 pairs a week is healthy. A queue of 5,000 a week means the thresholds are wrong, not that you need more headcount. Read the steward reject rate as a sensor: rubber-stamping everything means the threshold is too cautious, and rejecting half means it is too aggressive. Recalibrate the bands rather than working through noise by hand.

Try it on your own search

Stop building boolean strings. Just describe the person.

Type one sentence and I plan the search, read GitHub, public LinkedIn and Crunchbase records, and the open web live, then hand back a ranked shortlist with the reasoning behind every name. No filters to learn, no export to clean up, no sales call to sit through.

  • One sentence in, a ranked shortlist out. No boolean, no filters, no seat to buy.
  • Read live at search time, not from a database that went stale last quarter.
  • Watch every step as it runs, and see why each name made the list.

500 free credits on sign-up. No card, no demo call. See real searches.

Read next