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:
- Pulls candidates from one or more ATS connections
- Normalizes the candidate object
- Deduplicates across systems
- Aggregates application stages
- Computes recency and stale metrics
- 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:
idemails[]telephones[]link_urls[]first_name,last_namecompany_nametitletags[]metadata[]updated_atcreated_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_atacross 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_idstatusapplied_atrejected_athired_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:
statusoriginal_statusdescriptionjob_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:
| Stage | Count |
|---|---|
| NEW | 125 |
| REVIEWING | 82 |
| FIRST_INTERVIEW | 34 |
| OFFERED | 9 |
| HIRED | 6 |
| 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:
- 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
- Initial full sync of candidates and applications
- Store in internal database
- Deduplicate into canonical identities
- Compute analytics from your own DB
- Refresh via:
- Webhooks on supported integrations
- Or incremental reads with
updated_gtewhere 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.