---
title: "How to Deduplicate and Visualize Talent Pools Across ATS Platforms with"
img: https://s3.us-east-2.amazonaws.com/unified-article-images/how_to_deduplicate_and_visualize_talent_pools_across_ats_platforms_with-icon.png
date: 2026-02-25T19:16:00.000Z
updated: 2026-10-21T11:23:50.817Z
readingTime: 4
tag: Product
description: "To give recruiters one talent pool across several ATS connections with Unified.to's ATS API, read candidates and applications from each connection, merge..."
url: "https://unified.to/blog/how_to_deduplicate_and_visualize_talent_pools_across_ats_platforms_with"
---

# How to Deduplicate and Visualize Talent Pools Across ATS Platforms with

To give recruiters one talent pool across several ATS connections with [Unified.to](http://unified.to/)'s [ATS API](/ats), 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](http://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](http://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


```plain text
GET /ats/{connection_id}/candidate
```


### Node SDK Example


```typescript
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:


```json
{
  "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:


```plain text
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


```plain text
GET /ats/{connection_id}/application
```


### Example


```typescript
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:


```plain text
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:


| 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:


```typescript
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](http://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](/blog/replacing_polling_with_event_driven_integrations_using_virtual_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](http://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](http://unified.to/) provides:

- Structured candidate models
- Standardized application objects
- Stage vocabulary
- [Pagination](https://docs.unified.to/reference/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](https://app.unified.to/login)


[→ Book a demo](https://calendly.com/d/cph9-g8n-jzg/connect-with-unified)