This adds a /yt-search command to Claude Code. You type a query and get back structured results: titles, channels, view counts, subscriber counts, durations, upload dates, and links. One number in that list flags videos outperforming their own channel, which is the signal you want for content research. Setup is two files and five minutes.
You are planning content or scouting a niche. So you open a browser, search YouTube, and start reading titles and eyeballing view counts. There is no way to sort by anything useful, and no quick read on whether a video did well relative to the channel that posted it. You lose the thread you were on in Claude Code and switch tabs to do research a script could do in one line.
This skill moves that job into the terminal. You ask, you get a ranked list back, and you never leave the tool you were already working in. Everything below is on this page. Copy it, paste it, and it runs.
If you have never added a skill to Claude Code, the pattern is worth learning once. I cover a handful more in five Claude skills that ship real work, and they all install the same way this one does.
What /yt-search Does
It searches YouTube from inside Claude Code and returns clean, structured data for each result. No browser, no tab switching.
For every video you get the title, the channel name and its subscriber count, the total views, a views-to-subscribers ratio, the duration, the upload date, and a direct link. By default it only shows videos from the last six months, so you are looking at current content instead of a decade of back catalog. You can widen that window or turn it off.
The point for an operator is speed on a real job. Research a competitor's channel, find the best tutorial before you build something, or pull view data for a content plan, all without breaking your session.
What You Need
Three things, and you likely have two of them already.
- Claude Code installed and working.
- Python 3. Run
python3 --versionto confirm it is there. yt-dlp, the command-line tool that does the actual searching.
Install yt-dlp with one command:
Copy this.
pip install yt-dlp
On some setups that command is pip3 install yt-dlp. On newer Python installs you may hit a wall that requires pip install yt-dlp --break-system-packages. Once it is in, verify:
Copy this.
yt-dlp --version
You should see a version number. If you get "command not found," the install did not take. Try the alternates above before moving on.
Step One: Create the Slash Command
This first file tells Claude Code that /yt-search exists and what to run when you call it. Create it at:
Copy this.
~/.claude/commands/yt-search.md
On Mac or Linux, open a terminal and run:
Copy this.
mkdir -p ~/.claude/commands nano ~/.claude/commands/yt-search.md
On Windows in PowerShell:
Copy this.
mkdir -Force "$env:USERPROFILE\.claude\commands" notepad "$env:USERPROFILE\.claude\commands\yt-search.md"
Paste this in and save:
Copy this.
--- description: "Search YouTube and return structured video results" argument-hint: "<query> [--count N]" allowed-tools: - Bash --- Run the YouTube search script with the user's arguments and present the results. Execute this command: ``` python ~/.claude/skills/yt-search/scripts/search.py $ARGUMENTS ``` Present the output directly to the user. If the script reports an error, explain it and suggest fixes.
Step Two: Add the Search Script
This is the Python that performs the search. Create the folder and open the file:
Copy this.
mkdir -p ~/.claude/skills/yt-search/scripts nano ~/.claude/skills/yt-search/scripts/search.py
Paste the full script below and save. It is about 180 lines. Read it if you want to know exactly what it does, or paste it as is and move on.
Copy this.
#!/usr/bin/env python3
"""YouTube search via yt-dlp with structured output."""
import io, json, shutil, subprocess, sys
from datetime import datetime, timedelta
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace")
def parse_args(argv):
args = argv[1:]
count, months, query_parts = 20, 6, []
i = 0
while i < len(args):
if args[i] == "--count" and i + 1 < len(args):
count = int(args[i + 1]); i += 2
elif args[i] == "--months" and i + 1 < len(args):
months = int(args[i + 1]); i += 2
elif args[i] == "--no-date-filter":
months = 0; i += 1
else:
query_parts.append(args[i]); i += 1
query = " ".join(query_parts)
if not query:
print("Usage: search.py <query> [--count N] [--months N]", file=sys.stderr); sys.exit(1)
return query, count, months
def format_subscribers(n):
if n is None: return "N/A"
if n >= 1_000_000: return f"{n / 1_000_000:.1f}M"
if n >= 1_000: return f"{n / 1_000:.1f}K"
return str(n)
def format_views(n): return f"{n:,}" if n else "N/A"
def format_duration(info):
if info.get("duration_string"): return info["duration_string"]
dur = info.get("duration")
if dur is None: return "N/A"
dur = int(dur); h, r = divmod(dur, 3600); m, s = divmod(r, 60)
return f"{h}:{m:02d}:{s:02d}" if h else f"{m}:{s:02d}"
def format_date(raw):
if not raw or len(raw) != 8: return "N/A"
try: return datetime.strptime(raw, "%Y%m%d").strftime("%b %d, %Y")
except: return raw
def get_cutoff_date(months):
if months <= 0: return None
return (datetime.now() - timedelta(days=months * 30)).strftime("%Y%m%d")
def main():
query, count, months = parse_args(sys.argv)
if not shutil.which("yt-dlp"):
print("Error: yt-dlp not found. Install: pip install yt-dlp", file=sys.stderr); sys.exit(1)
fetch_count = count * 2 if months > 0 else count
cmd = ["yt-dlp", f"ytsearch{fetch_count}:{query}",
"--dump-json", "--no-download", "--no-warnings", "--quiet"]
date_label = f", last {months} months" if months > 0 else ""
print(f'Searching for: "{query}" (top {count}{date_label})...\n', file=sys.stderr)
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
except subprocess.TimeoutExpired:
print("Error: Search timed out.", file=sys.stderr); sys.exit(1)
if result.returncode != 0 and not result.stdout.strip():
print(f"Error: yt-dlp failed:\n{result.stderr.strip()}", file=sys.stderr); sys.exit(1)
videos = []
for line in result.stdout.strip().splitlines():
if not line.strip(): continue
try: videos.append(json.loads(line))
except json.JSONDecodeError: continue
if not videos:
print("No results found.", file=sys.stderr); sys.exit(0)
cutoff = get_cutoff_date(months)
if cutoff:
filtered = [v for v in videos if (v.get("upload_date") or "00000000") >= cutoff]
skipped = len(videos) - len(filtered); videos = filtered
if skipped > 0: print(f"(Filtered {skipped} older than {months}mo)\n", file=sys.stderr)
if not videos:
print(f"No results in last {months} months.", file=sys.stderr); sys.exit(0)
videos = videos[:count]
divider = "─" * 60
for i, info in enumerate(videos, 1):
title = info.get("title", "Unknown")
channel = info.get("channel", info.get("uploader", "Unknown"))
views = info.get("view_count"); subs = info.get("channel_follower_count")
duration = format_duration(info)
date = format_date(info.get("upload_date", ""))
vid = info.get("id", "")
url = f"https://youtube.com/watch?v={vid}" if vid else "N/A"
ratio = f"{views/subs:.2f}x" if subs and views and subs > 0 else "N/A"
meta = f"{channel} ({format_subscribers(subs)} subs) · {format_views(views)} views"
meta += f" · {duration} · {date}"
print(divider); print(f" {i:>2}. {title}")
print(f" {meta}"); print(f" Views/Subs: {ratio}"); print(f" {url}")
print(divider)
if __name__ == "__main__":
main()
On Mac or Linux, make it executable:
Copy this.
chmod +x ~/.claude/skills/yt-search/scripts/search.py
Step Three: Test It
Open Claude Code and type:
Copy this.
/yt-search claude code tutorial
You should see a ranked list with titles, channels, view counts, durations, and links. If it complains that yt-dlp is not found, go back and run pip install yt-dlp. Done. The skill is installed.
How to Use It
You call it like any command, with a query and optional flags:
Copy this.
/yt-search claude code skills /yt-search AI agents --count 10 /yt-search react tutorials --months 3 /yt-search machine learning --no-date-filter
Three flags control the output. Two are numbers, one is a switch.
| Flag | Default | What it does |
|---|---|---|
--count N | 20 | How many results to return. Use --count 5 for a quick lookup, --count 50 for deep research. |
--months N | 6 | Only show videos from the last N months. Use --months 1 for this month only. |
--no-date-filter | off | Show everything regardless of date. Use it for evergreen topics where old videos still matter. |
The One Number That Matters
Most of the fields are what you would expect. The views-to-subscribers ratio is the one to watch.
It divides a video's views by the channel's subscriber count. A ratio above 1.0x means the video pulled more views than the channel has subscribers, so it reached past its own audience. That is what a video looks like when a topic or a hook is working, not just when a big channel posts to a big list. Sort a search by that ratio and you find the format that is outperforming, which is the input you want for your own content plan. A channel with 2 million subscribers and 200,000 views on a video is at 0.1x, and that tells you more than the raw view count does.
When It Breaks
Four things go wrong, and each has a fix you type in.
"yt-dlp not found" means the install did not land or is not on your PATH. Run pip install yt-dlp again, or try pip3 install yt-dlp or python3 -m pip install yt-dlp.
"/yt-search not recognized" means the command file is in the wrong place. It has to sit at exactly ~/.claude/commands/yt-search.md, not in a subfolder. Restart Claude Code after you create it.
"No results found" usually means your date window is too tight. Broaden the query or add --no-date-filter if the topic does not have much recent video.
A search that hangs is almost always a large --count. Fifty or more results take a while. Start at --count 10 and raise it once you know your connection can take it.
The Limits You Should Know
yt-dlp reads YouTube's public pages rather than an official API. There is no key to manage and nothing to pay for, and that is the trade. When YouTube changes its pages, yt-dlp can break until its maintainers push an update, so keep it current with pip install -U yt-dlp. High result counts are slower and lean harder on YouTube, so do not hammer it with fifty-result searches back to back. Subscriber counts and durations come back empty on some videos, and the script prints "N/A" rather than guessing. Treat this as a fast research read, not an audited data feed.
Use it when you want a quick, sortable look at what is being published in a niche. Reach for YouTube's official Data API instead when you need guaranteed uptime or you are wiring this into something a client depends on.
If You Do One Thing
Install it and run one real search on your own niche this week. Try --count 30 --months 1 and read down the views-to-subscribers column, not the view column. The videos above 1.0x are the ones telling you what to make next. If it is not for you, you spent five minutes and two files finding that out.