How to deduplicate a YouTube channel list
Resolve aliases to confirmed channel IDs, group matching identities, and preserve source rows for review and correction.
A channel list can contain several rows for the same creator. One file may use a handle URL, another an ID-based URL, and a third a different display name. Removing duplicate names can also combine two unrelated channels.
For an importer, the useful distinction is between a channel's identity and the labels observed when a row was collected. Keep both.
Separate the identifier from the label
YouTube documents several URL forms that can lead to a channel: ID-based URLs, handle URLs, custom URLs and legacy username URLs. A /channel/... URL contains the channel's unique ID. Different URL strings are therefore insufficient evidence that two rows describe different channels. YouTube's URL guide explains these forms.
A handle starts with @ and is distinct from a channel name. Handles can also change or be reclaimed. Preserve the handle you observed, together with a date; do not treat an old handle-to-channel mapping as permanent. YouTube's handle documentation covers these rules.
For a research import, a small record can keep these concerns separate:
| Field | Purpose |
|---|---|
channelId |
Confirmed YouTube channel ID used for grouping. |
observedHandle |
Handle captured with this source row. |
displayName |
Human-readable label, retained for review. |
sourceUrl |
Original link, before normalization. |
observedAt |
When the observation was recorded. |
This is a proposed import record, not a requirement that every CSV already have these columns. A row without a confirmed ID remains useful evidence.
Resolve before merging
When your application already uses the YouTube Data API, channels.list provides a forHandle filter for a handle and forUsername for a legacy username. Its id filter retrieves channels by channel ID. The method requires exactly one filter parameter per request. Use the returned channel resource's ID as the identity key; YouTube documents the channel ID as uniquely identifying the channel. The official reference describes the filters, and the channel implementation guide describes the ID-based lookup.
Do not send the last segment of every channel URL as a legacy username. /@handle, /user/name and /c/name have different meanings. Resolving an alias needs evidence from the relevant official response or channel page, not a string replacement.
Keep unresolved rows in a review queue. A failed lookup is a resolution failure; it does not establish that a channel no longer exists.
Group confirmed IDs and retain the original rows
The following JavaScript groups rows whose IDs your importer has already confirmed. It does not fetch YouTube data or validate whether an arbitrary string is a real channel ID.
function groupKnownChannels(rows) {
const byId = new Map();
const unresolved = [];
for (const row of rows) {
const id = typeof row.channelId === "string"
? row.channelId.trim()
: "";
if (!id) {
unresolved.push(row);
continue;
}
const observations = byId.get(id) ?? [];
observations.push(row);
byId.set(id, observations);
}
return { groups: [...byId.values()], unresolved };
}
Consider four synthetic rows. CHANNEL_A and CHANNEL_B are placeholders, not real channel IDs:
const rows = [
{ channelId: "CHANNEL_A", displayName: "Field Notes", source: "a.csv" },
{ channelId: "CHANNEL_B", displayName: "Field Notes", source: "b.csv" },
{ channelId: "CHANNEL_A", displayName: "Field Notes Studio", source: "c.csv" },
{ channelId: null, observedHandle: "@fieldnotes", source: "d.csv" }
];
const { groups, unresolved } = groupKnownChannels(rows);
// groups.length === 2; unresolved.length === 1
// The CHANNEL_A group retains both source rows.
With these synthetic rows, the example produces two groups, one unresolved row, and two retained source rows for CHANNEL_A. Local Node assertions confirmed this result; no network requests or real channel data were used.
The shared display name does not merge A with B. The changed label does not split A into two identities. The handle-only row stays unresolved until there is evidence tying it to an ID.
Choose a representative after grouping
For a clean shortlist, choose one row to display per confirmed ID, but retain the observations behind it. If labels disagree, show the most recently verified label and keep the older source. If identity evidence conflicts, pause that merge for review.
This also makes corrections practical: you can see which file introduced a row and revise a mistaken match without reconstructing the import. Deduplication becomes an explicit identity decision instead of a destructive operation on names.
I make Channel Finder, a desktop Chrome extension for finding channels with similar YouTube content and exporting CSV shortlists. The import pattern here is general; it does not describe the extension's export schema.
Comments
Join the discussionNo comments yet. Be the first to comment.