DEV Community

Elowen
Elowen

Posted on

How to Verify Public Profiles Without Hiding Uncertain Matches

You have a spreadsheet of public figures and need to find a credible profile for each person. A simple script may accept the first matching name, which can attach the wrong role or social account to someone who shares that name.

This walkthrough classifies each person as matched, review_needed, or not_found and keeps the supporting results. The labels show which rows are ready, need review, or returned no usable candidate.

For a public example, I searched Tim Berners-Lee public profile in US English desktop results on August 25, 2026. Wikipedia ranked first, Internet Hall of Fame second, MIT seventh, and X eighth.

The institutional and independent pages supported the name and public role. The X result matched the name and handle, while a dated institutional page remained the stronger source for a current role.

Turn search results into three decisions

Each status has a narrow meaning:

  • matched: the name matches and credible sources support the expected role.
  • review_needed: a candidate exists, while role or account evidence remains incomplete.
  • not_found: the search returned no usable candidate. This state says nothing about whether the person exists.

The code below applies those rules to three anonymous inputs. These inputs demonstrate the batch logic; the Tim Berners-Lee results above came from the public query.

function normalize(text = '') {
  return text.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();
}

function hostname(link) {
  try {
    return new URL(link).hostname.replace(/^www\./, '');
  } catch {
    return '';
  }
}

function verifyTarget(target) {
  const expectedName = normalize(target.name);
  const checked = target.results.map((result) => {
    const text = normalize(`${result.title} ${result.description || ''}`);
    const nameMatch = text.includes(expectedName);
    const roleMatch = target.expected_role_terms.some((term) =>
      text.includes(normalize(term))
    );
    const domain = hostname(result.link);
    const trustedSource = target.trusted_domains.some((trusted) =>
      domain === trusted || domain.endsWith(`.${trusted}`)
    );

    return { ...result, nameMatch, roleMatch, trustedSource };
  });

  const candidates = checked.filter((result) => result.nameMatch);

  if (candidates.length === 0) {
    return { target: target.id, status: 'not_found', evidence: [] };
  }

  const strong = candidates.filter(
    (result) => result.roleMatch && result.trustedSource
  );

  return {
    target: target.id,
    status: strong.length > 0 ? 'matched' : 'review_needed',
    evidence: candidates.map(({
      position, title, source, link, nameMatch, roleMatch, trustedSource
    }) => ({
      position, title, source, link, nameMatch, roleMatch, trustedSource
    }))
  };
}

const targets = [
  {
    id: 'Person A',
    name: 'Person A',
    expected_role_terms: ['research director'],
    trusted_domains: ['institution-a.example'],
    results: [{
      position: 1,
      title: 'Person A - Research Director',
      description: 'Biography and current research role.',
      source: 'Institution A',
      link: 'https://institution-a.example/people/person-a'
    }]
  },
  {
    id: 'Person B',
    name: 'Person B',
    expected_role_terms: ['engineering lead'],
    trusted_domains: ['company-b.example'],
    results: []
  },
  {
    id: 'Person C',
    name: 'Person C',
    expected_role_terms: ['chief scientist'],
    trusted_domains: ['institution-c.example'],
    results: [{
      position: 2,
      title: 'Person C - Conference Speaker',
      description: 'Session biography for an industry event.',
      source: 'Conference A',
      link: 'https://conference-a.example/speakers/person-c'
    }]
  }
];

console.log(targets.map(verifyTarget));
Enter fullscreen mode Exit fullscreen mode

Running the code produces all three statuses. Person A has a name, role term, and trusted institutional domain. Person B has no candidate. Person C has a matching name, while its event page lacks the expected role and trusted domain.

This is a first screening step. Open every review_needed source and check the person, role, and publication date. Name and keyword checks can still confuse namesakes, so the evidence stays attached to every decision.

For larger lists, save the query context, result position, title, source, link, access time, and decision status. A later reviewer can then see how the conclusion was reached.

TalorData can supply the Google results for this workflow. New accounts receive 500 responses immediately after registration

Top comments (0)