← Back to blog

Extract SEO Keywords from Competitor YouTube Videos

Zied · 8/17/2026 · 7 min read

Extract SEO Keywords from Competitor YouTube Videos

Extract SEO Keywords from Competitor YouTube Videos

Your competitors' YouTube channels are a keyword research goldmine that most SEO teams ignore entirely. Every video title, transcript, and description contains the vocabulary those creators have already validated with an audience, and pulling that data at scale takes fewer than fifty lines of code.

This guide walks through a complete pipeline: resolve competitor channel handles, list their uploads using a YouTube channel videos API, fetch each transcript as JSON, run TF-IDF analysis on the resulting corpus, and cluster the output into actionable content gaps.

Laptop showing analytics dashboard with keyword data

Mine Competitor Channels for Keyword Opportunities

The starting point is knowing which channels to target. Pick three to five competitors whose organic search presence you want to understand. You need their canonical channel ID, not just their handle, because the channel videos endpoint expects a stable identifier.

YouTube Transcriber exposes a handle resolution endpoint for exactly this:

curl -s "https://getyoutubetranscriber.com/api/v2/channel/resolve?channel=@mkbhd" \
  -H "Authorization: Bearer YOUR_TOKEN"

The response returns the canonical channel ID. Store these IDs; you will pass them into the videos endpoint next.

If you are working in Python:

import httpx

BASE = "https://getyoutubetranscriber.com/api/v2"
HEADERS = {"Authorization": "Bearer YOUR_TOKEN"}

def resolve_handle(handle: str) -> str:
    r = httpx.get(f"{BASE}/channel/resolve", params={"channel": handle}, headers=HEADERS)
    r.raise_for_status()
    return r.json()["channel_id"]

List Channel Uploads and Pull Each Transcript

Once you have a channel ID, the channel videos endpoint returns a paginated list of every upload, newest first. Each page includes a continuation token you pass into the next request to walk through the full history.

def list_all_videos(channel_id: str) -> list[dict]:
    videos = []
    params = {"channel": channel_id}
    while True:
        r = httpx.get(f"{BASE}/channel/videos", params=params, headers=HEADERS, timeout=30)
        r.raise_for_status()
        data = r.json()
        videos.extend(data.get("videos", []))
        token = data.get("continuation")
        if not token:
            break
        params["continuation"] = token
    return videos

With a list of video URLs in hand, fetch each transcript. The transcript endpoint accepts a video_url parameter and returns a JSON array of segments, each with text, start, and duration fields.

def fetch_transcript(video_url: str) -> list[dict] | None:
    try:
        r = httpx.get(
            f"{BASE}/transcript",
            params={"video_url": video_url},
            headers=HEADERS,
            timeout=30,
        )
        r.raise_for_status()
        return r.json().get("transcript", [])
    except httpx.HTTPStatusError:
        return None  # no transcript available; skip this video

For a channel with hundreds of videos, wrap the transcript fetching loop with a small delay between requests and consider using the bulk transcripts endpoint (POST /api/v2/transcripts-bulk) which accepts up to 50 URLs per call and reduces round-trip overhead significantly.

The result of this stage is a dictionary mapping video ID to a list of transcript segments. That is your raw corpus.

Run Frequency and TF-IDF Analysis on the Text

Concatenate each video's transcript segments into a single string, then treat each video as a document in your corpus. TF-IDF scores how important a term is to a particular document relative to how commonly that term appears across all documents. Terms that appear frequently in one video but rarely across the corpus score high, which often corresponds to specific subtopics and named concepts that differentiate that video from the rest.

from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd

def segments_to_text(segments: list[dict]) -> str:
    return " ".join(s["text"] for s in segments)

# Build corpus: one string per video
corpus = {vid_id: segments_to_text(segs) for vid_id, segs in transcripts.items()}
video_ids = list(corpus.keys())
documents = [corpus[v] for v in video_ids]

vectorizer = TfidfVectorizer(
    max_features=5000,
    ngram_range=(1, 2),       # unigrams and bigrams
    stop_words="english",
    min_df=2,                  # term must appear in at least 2 videos
)
tfidf_matrix = vectorizer.fit_transform(documents)
feature_names = vectorizer.get_feature_names_out()

# Top terms per video
scores_df = pd.DataFrame(tfidf_matrix.toarray(), columns=feature_names, index=video_ids)
top_terms_per_video = scores_df.apply(lambda row: row.nlargest(20).index.tolist(), axis=1)

To surface channel-level keyword priorities, average TF-IDF scores across all videos and sort:

channel_scores = scores_df.mean(axis=0).sort_values(ascending=False)
print(channel_scores.head(50))

These are the terms your competitor's channel consistently emphasizes. Cross-reference them against your own content to find what you have not covered.

Data spreadsheet showing frequency analysis and keyword scoring

Cluster Topics to Find Content Gaps

Raw TF-IDF scores show you individual terms. Topic clustering shows you whole subject areas. K-means clustering on the TF-IDF matrix groups videos that share vocabulary into coherent topics, revealing the content pillars your competitor has built authority around.

from sklearn.cluster import KMeans

N_CLUSTERS = 8  # adjust based on channel size

km = KMeans(n_clusters=N_CLUSTERS, random_state=42, n_init="auto")
cluster_labels = km.fit_predict(tfidf_matrix)

# Inspect top terms per cluster
order_centroids = km.cluster_centers_.argsort()[:, ::-1]
for i in range(N_CLUSTERS):
    top = [feature_names[idx] for idx in order_centroids[i, :10]]
    print(f"Cluster {i}: {', '.join(top)}")

Map each cluster to a human-readable topic label, then compare the cluster list against your own published content. Any cluster with multiple competitor videos but zero equivalent content on your end is a content gap worth closing.

For deeper analysis, run the same pipeline against your own channel and compute the set difference between your topic clusters and theirs. Those missing clusters represent the keyword territories your competitor has staked out that you have not entered yet.

This approach pairs well with the sentiment and topic analysis techniques covered in Sentiment and Topic Analysis on YouTube Transcripts, where you can layer emotional tone onto the keyword picture.

Gotcha: Filtering Filler Words and Auto-Caption Noise

Auto-generated captions introduce noise that will contaminate your analysis if you do not clean it out. YouTube's speech recognition produces a few consistent artifacts:

Filler tokens. Words like "um," "uh," "you know," and "like" appear at high frequency in conversational videos. They will score well in term frequency calculations while carrying zero semantic value. Add them to your stop word list explicitly.

Transcription errors near domain terms. Technical vocabulary gets mangled. "API" might appear as "a p i," "api," or "AP eye" depending on how clearly the speaker enunciated. Normalize to lowercase and consider a light text normalization pass before vectorizing.

Repeated segment artifacts. Some auto-caption tracks duplicate segments at chapter boundaries. Deduplicate adjacent segments with identical text before concatenating.

Music and non-speech markers. YouTube inserts [Music], [Applause], and similar bracketed tokens in auto-captions when no speech is detected. Strip these with a simple regex before building your corpus:

import re

def clean_transcript(segments: list[dict]) -> str:
    cleaned = []
    for seg in segments:
        text = re.sub(r"\[.*?\]", "", seg["text"]).strip()
        if text:
            cleaned.append(text)
    return " ".join(cleaned)

Language detection. If a competitor channel publishes in multiple languages, mixing transcripts from different languages into one corpus will produce nonsense TF-IDF scores. Detect the language of each transcript and filter to a single language before analysis, or run separate pipelines per language. YouTube Transcriber supports 125+ languages and lets you request a specific language track per video, which gives you a clean way to enforce consistency at the fetch stage.

These cleanup steps are easy to skip on a first pass and easy to regret. Build them into the pipeline before you start interpreting results.

For a broader look at what happens when you try to bypass a YouTube data extraction API and build your own scraper, the DIY YouTube Scraping vs a Transcript API: The Real Cost breakdown is worth reading before you decide on your architecture.

Putting It Together

The complete pipeline in practice looks like this:

  1. Resolve competitor channel handles to canonical IDs.
  2. Paginate through channel uploads to collect video URLs.
  3. Fetch transcripts in batches, skipping videos with no available track.
  4. Clean each transcript: strip bracketed tokens, normalize casing, remove filler words.
  5. Vectorize the cleaned corpus with TF-IDF using bigrams and a minimum document frequency filter.
  6. Average scores across the channel to rank terms by overall emphasis.
  7. Cluster videos to identify topic pillars and map them against your own content.

The output is a ranked keyword list grounded in what actually resonates on a specific channel, not just what a keyword tool predicts might rank. Because the data comes from transcripts rather than metadata, it captures the vocabulary speakers use in context, which tends to match how audiences search for the same ideas.

TF-IDF is a proven starting point for this kind of analysis. As Link-Assistant explains in their TF-IDF SEO guide, the technique rewards contextually relevant vocabulary over raw keyword density by discounting terms that are common everywhere, and it is widely used to compare your content's topical coverage against competitors' high-ranking pages.

Code editor showing Python data analysis script

Next Steps

If you want to extend this pipeline, consider tracking new uploads automatically using the channel latest endpoint so your keyword corpus stays current as competitors publish new content. You can also cross-reference your term lists against a keyword volume source to prioritize gaps by search demand rather than transcript frequency alone.

Start with the channel uploads and transcript API docs and run the pipeline against one competitor channel. Most developers have usable keyword data within an afternoon using the 100 free credits included with every new account, no credit card required.