Unified.to
All articles

How to Deduplicate and Visualize Talent Pools Across ATS Platforms with

·

To give recruiters one talent pool across several ATS connections with Unified.to's ATS API, read candidates and applications from each connection, merge candidates on email, LinkedIn URL and phone in your own database, and chart stages from each application's status. This guide is for recruiting products adding cross-ATS talent-pool views.

Recruiting teams rarely operate in a single system.

They may use:

  • Different ATS platforms across regions
  • Multiple ATS instances for separate business units
  • An ATS plus an internal talent CRM
  • A sourcing database layered on top

From the recruiter's perspective, this creates blind spots:

  • Are we sourcing candidates who already exist in another system?
  • How many unique candidates do we actually have?
  • How many are active vs stale?
  • Where are candidates getting stuck in the funnel?

If you're building a recruiting product, this is a customer-facing feature:

A unified talent pool view across ATS platforms.

This guide walks through how to implement talent pool deduplication and visibility using Unified.to's ATS API.

This is a read and analytics feature; nothing is written back.

What does a talent-pool feature do?

Your product becomes a candidate identity layer.

It:

  1. Pulls candidates from one or more ATS connections
  2. Normalizes the candidate object
  3. Deduplicates across systems
  4. Aggregates application stages
  5. Computes recency and stale metrics
  6. Visualizes funnel distribution

Unified.to provides normalized candidate and application models across supported ATS integrations.

You provide:

  • Identity resolution logic
  • Cross-system merging
  • Analytics and visualization

Step 1: How do you read candidates from each ATS connection?

Start by listing candidates for each connected ATS.

Endpoint

GET /ats/{connection_id}/candidate

Node SDK Example

const candidates = await sdk.ats.listAtsCandidates({
  connectionId,
  limit: 100,
  offset: 0,
  sort: 'updated_at',
  order: 'asc',
});

Important fields from AtsCandidate:

  • id
  • emails[]
  • telephones[]
  • link_urls[]
  • first_name, last_name
  • company_name
  • title
  • tags[]
  • metadata[]
  • updated_at
  • created_at

Store candidates in your own database. Do not run analytics directly off live API calls.

Step 2: How do you normalize candidate identity?

You need a canonical identity key across systems.

Use the following priority order:

Email (primary key)

emails[] contains structured email objects:

{
  "name": "Jane Doe",
  "email": "jane@example.com",
  "type": "WORK"
}

Deduplicate primarily on normalized email address:

  • Lowercase
  • Trim whitespace
  • Remove aliasing patterns if appropriate (e.g., Gmail dots)

Email is the most reliable cross-system identifier.

LinkedIn URL

link_urls[] includes:

URLs for web pages containing additional material about the candidate (LinkedIn, other social media, articles, etc.)

Extract LinkedIn URLs and normalize:

  • Remove tracking parameters
  • Standardize domain variants

This becomes your secondary dedupe key when email is missing.

Phone number (fallback)

From telephones[], normalize:

  • Strip formatting
  • Standardize country codes

Phone numbers are useful but less consistent.

Step 3: How do you build a canonical candidate record?

After dedupe, merge candidate records into a single canonical entity:

CanonicalCandidate
  - primary_email
  - linkedin_url
  - phones[]
  - first_seen_at
  - last_updated_at
  - ats_sources[]
  - candidate_ids_by_connection

Store:

  • All ATS candidate IDs
  • Which connection they belong to
  • The most recent updated_at across systems

This lets you:

  • Avoid re-sourcing known candidates
  • Show a unified profile
  • Link back to each ATS record

Step 4: How do you merge applications for funnel visibility?

Now pull applications.

Endpoint

GET /ats/{connection_id}/application

Example

const applications = await sdk.ats.listAtsApplications({
  connectionId,
  limit: 100,
  offset: 0,
});

From AtsApplication, use:

  • candidate_id
  • status
  • applied_at
  • rejected_at
  • hired_at

Map each application to your canonical candidate record.

Step 5: How do you visualize stage distribution?

Use status for stage aggregation.

To retrieve available stage vocabulary:

GET /ats/{connection_id}/applicationstatus

From each application status record:

  • status
  • original_status
  • description
  • job_id (when the ATS scopes stages per job)

Now compute:

  • Count of candidates per status
  • Count per ATS connection
  • Cross-ATS aggregated funnel

Example output:

StageCount
NEW125
REVIEWING82
FIRST_INTERVIEW34
OFFERED9
HIRED6
This becomes a funnel visualization in your product.

Step 6: How do you highlight stale candidates?

Use updated_at on the candidate object.

Define stale logic, for example:

  • No updates in 90 days
  • No active applications
  • No interview scheduled

Example:

const isStale = daysSince(candidate.updated_at) > 90;

You can also compute:

  • Days since last application
  • Days since last interview
  • Days since stage change (if you track it yourself)

Unified.to doesn't return stage history, so you must track changes over time if you need them.

Step 7: How do you merge internal and ATS data?

If your product also has:

  • Internal CRM candidates
  • Sourced prospects
  • Event leads

You can unify them using the same identity logic:

  • Email
  • LinkedIn
  • Phone

Then show:

  • 'Already in ATS (Greenhouse)'
  • 'Previously applied in EMEA instance'
  • 'Rejected 6 months ago'

This prevents duplicate outreach and improves recruiter efficiency.

Architecture Recommendation

  1. Initial full sync of candidates and applications
  2. Store in internal database
  3. Deduplicate into canonical identities
  4. Compute analytics from your own DB
  5. Refresh via:
    • Webhooks on supported integrations
    • Or incremental reads with updated_gte where the integration supports it

Do not recompute dedupe in real time on every page load.

Why This Matters to Your Customers

Talent pool visibility helps customers:

  • Avoid sourcing duplicates
  • Reduce recruiter fatigue
  • Understand true funnel size
  • Identify pipeline bottlenecks
  • Re-engage dormant candidates

By using Unified.to's normalized ATS API as a read layer, you can provide cross-platform visibility without building custom integrations for every ATS.

Is talent-pool deduplication an integration problem?

Deduplicating and visualizing talent pools across ATS platforms is not an integration problem.

It's an identity and analytics problem.

Unified.to provides:

  • Structured candidate models
  • Standardized application objects
  • Stage vocabulary
  • Pagination on every integration and incremental reads on many

Your product layers on:

  • Identity resolution
  • Canonical merging
  • Funnel analytics
  • Staleness detection
  • Recruiter-facing insights

That combination turns fragmented ATS data into actionable talent intelligence.

→ Start your 30-day free trial

→ Book a demo

All articles