Build a YouTube Channel Competitor Analysis With Public Data

Build a fixed-window YouTube channel comparison from public API records, transparent calculations, missing-count coverage, and a completed report.

Written by the Mexela Editorial Team. Technical guides are reviewed by the Mexela Technical Team under the Mexela Editorial Policy.

Red and white dashboard comparing public video cards, upload timelines, and channel trend charts

PROXY PLANS

Ready to buy proxies for this workflow?

Use the guide below to choose the right proxy type, then start with private proxies for dedicated IPv4 access or shared proxies when price matters more.

Build a YouTube channel competitor analysis from a fixed channel list, a fixed 90-day UTC window, and the same official Data API path for every channel: resolve stable channel IDs, read each uploads playlist from contentDetails.relatedPlaylists.uploads, page through playlistItems.list, then batch the collected video IDs through videos.list. Report simple public measures such as upload cadence and median public views, plus the count coverage behind each measure. Do not infer revenue, conversions, demographics, retention, or causal performance.

This example answers one editorial question: how did three comparable networking-education channels publish during 1 April through 29 June 2026? The names and values in the finished report are fictional so they cannot be mistaken for live claims. In a real run, replace them with approved public channels, capture their exact IDs, and freeze the set before requesting any video data.

Freeze the cohort and 90-day window

The illustrative cohort is Northstar Network Lab, Cedar Router School, and Meridian Wi-Fi Workshop. All three are fictional tutorial channels aimed at home-networking learners. The analysis window starts 2026-04-01T00:00:00Z and ends before 2026-06-30T00:00:00Z, which is exactly 90 days. A video belongs when its API snippet.publishedAt falls inside that half-open interval.

Frozen label Required production value Reason included
northstar-network-lab Verified channel ID beginning UC Beginner router walkthroughs
cedar-router-school Verified channel ID beginning UC Home Wi-Fi troubleshooting
meridian-wifi-workshop Verified channel ID beginning UC Comparable device tutorials

Do not rediscover the cohort from search on every refresh. Display names and handles can change; the channel ID is the join key. If a stakeholder adds a fourth channel after collection, start a new report version or rerun the same window for all four rather than appending an incomparable row.

Resolve channels, then read their uploads playlists

If the input arrives as a handle, call GET https://www.googleapis.com/youtube/v3/channels?part=id,snippet,contentDetails&forHandle={HANDLE}&key={KEY} once for that handle. The channels.list reference documents forHandle, the id filter, and the contentDetails part. Confirm one returned resource, store its ID, and use IDs thereafter.

For the frozen IDs, request part=id,snippet,contentDetails,statistics with a comma-separated id value. Read the uploads playlist at items[].contentDetails.relatedPlaylists.uploads. The method currently costs 1 quota unit per call. Channel-level subscriber counts are context only; they can be rounded, hidden, and accumulated over very different histories, so they are not a denominator for the report below.

This route avoids using search.list to rediscover uploads. YouTube represents a channel’s uploaded videos through its uploads playlist, and the official API’s sample request sequence demonstrates retrieving that playlist from the channel resource before listing its items.

Page every uploads playlist and record completeness

For each uploads playlist, call GET https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails,snippet&playlistId={UPLOADS_ID}&maxResults=50&pageToken={TOKEN}&key={KEY}. Omit pageToken on the first call, then pass each response’s nextPageToken into the next request until no token remains. The playlistItems.list reference documents a maximum of 50 items per page, token-based pagination, and a cost of 1 quota unit per call.

Filter by the analysis window after collecting the playlist item timestamps. Do not silently stop after one page or assume pageInfo.totalResults replaces pagination. For a very large archive, a reviewed page cap can protect the run, but the report must then say playlistComplete: false and must not present its window totals as complete.

Deduplicate video IDs across pages, retain the playlist-item published time for diagnostics, and log pages fetched per channel. Deleted or private items may be absent from the final video lookup. Keep that difference as a data-quality count instead of inventing a zero-view record.

Fetch public video details in batches

Split the in-window IDs into batches of no more than 50 and call GET https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics&id={COMMA_SEPARATED_IDS}&key={KEY}. The videos.list reference documents the ID filter, response parts, and current 1-unit cost. The separate video resource reference defines public statistics.viewCount and statistics.commentCount and explains the meaning of snippet.publishedAt.

Normalize decimal strings from statistics into non-negative integers only when the field exists and parses safely. A missing count stays null; it is not zero. Keep ISO 8601 duration as returned or parse it with a tested duration library if the report needs minutes. One normalized, fictional record looks like this:

{
  "channelKey": "northstar-network-lab",
  "channelId": "UC_REPLACE_WITH_VERIFIED_ID",
  "videoId": "demoVideo042",
  "title": "Place a mesh node without creating interference",
  "publishedAt": "2026-05-12T14:00:00Z",
  "duration": "PT8M14S",
  "viewCount": 18400,
  "commentCount": 73,
  "capturedAt": "2026-07-01T08:00:00Z"
}

Counts are snapshots at capturedAt, not values at publication. Comparing lifetime views across videos of different ages remains imperfect even inside one window. Show the publication range and capture time beside the summary so a reader can see that limitation.

Calculate cadence and median views transparently

Publishing cadence is the number of in-window uploads divided by window weeks. For 90 days, the denominator is 90 / 7. Median public views sorts only videos with a numeric public view count and takes the middle value, or the average of the two middle values. Always report videosWithViewCount beside the median so missing statistics cannot disappear from the denominator.

function median(values) {
  if (values.length === 0) return null;
  const sorted = [...values].sort((left, right) => left - right);
  const middle = Math.floor(sorted.length / 2);
  return sorted.length % 2 === 1
    ? sorted[middle]
    : (sorted[middle - 1] + sorted[middle]) / 2;
}
function calculateMetrics(videos, windowDays) {
  if (!Array.isArray(videos)) throw new TypeError('videos must be an array');
  if (!Number.isFinite(windowDays) || windowDays <= 0) {
    throw new RangeError('windowDays must be positive');
  }
  const publicViews = videos
    .map((video) => video.viewCount)
    .filter((value) => Number.isFinite(value) && value >= 0);
  return {
    uploads: videos.length,
    uploadsPerWeek: Number((videos.length / (windowDays / 7)).toFixed(2)),
    medianPublicViews: median(publicViews),
    videosWithViewCount: publicViews.length,
  };
}
const channels = [
  {
    channelKey: 'northstar-network-lab',
    videos: [18400, 12100, 9400, 22100, 18700, 16500]
      .map((viewCount) => ({ viewCount })),
  },
  {
    channelKey: 'cedar-router-school',
    videos: [6200, 8300, null, 9700, 10400, 11900, 7300, 15100, 9100]
      .map((viewCount) => ({ viewCount })),
  },
  {
    channelKey: 'meridian-wifi-workshop',
    videos: [26300, 21400, 33800, 29700]
      .map((viewCount) => ({ viewCount })),
  },
];
const report = channels.map(({ channelKey, videos }) => ({
  channelKey,
  ...calculateMetrics(videos, 90),
}));
console.log(JSON.stringify(report, null, 2));

The code counts every published video for cadence but excludes the one missing view count from Cedar’s median. It does not replace missing data with zero. Run it with Node.js 18 or newer; it has no package dependencies and all fixture values are defined in the example.

Finish a one-page comparison without a score

The completed fictional output below includes collection coverage before interpretation. Values are illustrative, not observations about real channels.

Channel Uploads Uploads/week Median public views View-count coverage Observed format note
Northstar Network Lab 6 0.47 17,600 6/6 Six focused setup walkthroughs
Cedar Router School 9 0.70 8,700 8/9 Frequent short troubleshooting lessons
Meridian Wi-Fi Workshop 4 0.31 28,000 4/4 Fewer, longer comparison tutorials

Coverage: all three channel IDs resolved, all uploads-playlist pages completed, 19 in-window video IDs found, 19 video resources returned, and 18 videos exposed a numeric view count. Observation: Cedar published most often; Meridian’s four-video median was highest; Northstar sat between them. Editorial action: test one original troubleshooting lesson weekly for four weeks, then evaluate it against the team’s own goal rather than copying another channel’s titles or cadence.

Do not combine the columns into a “competitor score.” The official developer policies guide permits simple mathematical presentation of API metrics but warns against inaccurate replacement metrics, custom channel scores, rivalry-oriented ranking, audience-demographic estimates, and financial projections. Keep raw public counts, transparent arithmetic, and editorial interpretation visibly separate.

State what public data cannot answer

Public view and comment counts cannot reveal conversion rate, watch time, retention, revenue, margin, sponsorship terms, audience demographics, customer quality, or why a video received its views. Subscriber count does not fix those gaps. A title pattern and a high view count may coexist without one causing the other.

Shorts view counting differs from long-form video measurement: the current video resource reference notes that from 31 March 2025 a Shorts viewCount counts starts and replays without a minimum watch-time requirement. If the cohort mixes formats, report the mix and avoid treating every view as directly comparable.

A regional search screenshot can add a separate discoverability observation, but it is not an input to the metrics above. If that question matters, use the YouTube search Data API and regional QA guide and keep its query, market, language, and capture time in another table.

Refresh the report without changing its history

Store each run as a dated snapshot. On the next refresh, reuse the same channel IDs, window definition, request path, field mapping, and metric functions. Do not overwrite July’s captured counts with August’s values. If a video disappears, preserve the prior record and note that the current lookup did not return it.

API calls do not need a browser proxy for this workflow. If a separate, permitted regional visibility check needs a stable country route, first follow the exit verification procedure. Mexela’s proxy plans can then be compared for the required country and session duration; the proxy never exposes private channel analytics.

Frequently asked questions

Why use uploads playlists instead of channel search?

The channel resource provides its uploads playlist, and playlistItems.list supplies documented pagination over that playlist. It avoids using search ranking as an upload inventory.

Why use median public views?

A median is less dominated by one unusually large value than an average. It remains a snapshot measure, so include sample size, count coverage, publication window, and capture time.

Should a missing view count become zero?

No. Zero is a reported value; missing is unavailable. Exclude missing counts from the median, show how many numeric counts were present, and investigate retrieval coverage separately.

Can this report estimate a competitor’s revenue or audience demographics?

No. Those are not available from the public fields used here, and inferring them would overstate the evidence.