YouTube channel videos API: list and search any channel
YouTube channels are goldmines of organized content. A single channel can have thousands of videos, all categorized by topic, sorted by date, and waiting to be analyzed.
But getting that data programmatically? That's where things get messy.
The YouTube Data API v3 makes you jump through hoops. You need to find the channel's "uploads" playlist ID, then paginate through that playlist, then make separate calls for video details. It's three API calls minimum just to list videos from one channel.
TranscriptAPI gives you dedicated channel endpoints that handle all of this in a single call. List videos, search within channels, resolve channel identifiers, and monitor new uploads.
There are four channel-related endpoints in total. Two are free. Two cost 1 credit per request. This guide shows you how to use each one with working code examples.

Resolving channel identifiers
Here's a problem you've probably hit before. YouTube channels have multiple URL formats. The same channel can be reached at least four different ways.
The channel resolve endpoint (free)
Before you can list a channel's videos, you need a consistent channel ID. YouTube uses the UC... format internally, but users share channels in all sorts of formats.
TranscriptAPI's resolve endpoint converts any format to a canonical channel ID. And it's free. Zero credits.
curl "https://transcriptapi.com/api/v2/youtube/channel/resolve?input=@mkbhd" \
-H "Authorization: Bearer YOUR_API_KEY"
Response:
{
"channel_id": "UCBcRF18a7Qf58cCRy5xuWwQ",
"resolved_from": "@mkbhd"
}
Supported URL formats
The resolve endpoint handles all of these:
Handle URLs:
youtube.com/@mkbhdChannel ID URLs:
youtube.com/channel/UCBcRF18a7Qf58cCRy5xuWwQCustom URLs:
youtube.com/c/mkbhdLegacy user URLs:
youtube.com/user/marquesbrownlee
If you pass a UC... ID directly, the resolution is instant since no lookup is needed.
I recommend always running inputs through the resolve endpoint first. Your users might paste any of these formats, and you don't want to write parsing logic for all of them.
Have you ever had a user paste a channel URL that broke your code?
Resolve in Python
Here's the resolve call in Python:
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://transcriptapi.com/api/v2"
headers = {"Authorization": f"Bearer {API_KEY}"}
# Resolve any channel format to a UC... ID
response = requests.get(
f"{BASE_URL}/youtube/channel/resolve",
params={"input": "@mkbhd"},
headers=headers
)
channel_data = response.json()
channel_id = channel_data["channel_id"]
print(f"Resolved to: {channel_id}")
# Output: Resolved to: UCBcRF18a7Qf58cCRy5xuWwQ
Use this resolved ID in all subsequent calls for consistency. Store it in your database alongside the original input so you only resolve once per channel.

Listing all videos from a channel
This is the endpoint you'll use most. Pass a channel handle (or resolved ID) and get back a paginated list of every public video.
The channel videos endpoint
curl "https://transcriptapi.com/api/v2/youtube/channel/videos?channel=@mkbhd" \
-H "Authorization: Bearer YOUR_API_KEY"
Each response includes video metadata: title, URL, publish date, thumbnail, duration, and view count. You get roughly 100 videos per page, and each page costs 1 credit.
The response also includes a continuation_token and a has_more boolean so you know when to stop paginating.
Pagination for large channels
Some channels have thousands of videos. TED has over 5,200. Here's how to paginate through them all:
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://transcriptapi.com/api/v2"
headers = {"Authorization": f"Bearer {API_KEY}"}
all_videos = []
params = {"channel": "@TED"}
while True:
response = requests.get(
f"{BASE_URL}/youtube/channel/videos",
params=params,
headers=headers
)
data = response.json()
all_videos.extend(data["videos"])
if not data.get("has_more"):
break
# Next page uses continuation token only
params = {"continuation": data["continuation_token"]}
print(f"Total videos: {len(all_videos)}")
A channel with 1,000 videos takes about 10 page requests. That's 10 credits, or about 5 cents on the monthly plan.
Here's what I like about this approach: you don't need to know the channel's "uploads playlist" ID. You don't need a separate API call for video details. Everything comes back in one clean response per page.
Cost breakdown for large channels
Channel sizePages neededCredits usedCost (monthly plan)100 videos11$0.005500 videos55$0.0251,000 videos1010$0.055,000 videos5050$0.25
The channel resolve step is free, so it doesn't add to your costs.
Compare that with the YouTube Data API v3, where listing 1,000 videos costs hundreds of quota units across multiple API calls. And you have a daily cap of 10,000 units total across all operations.

Searching within a channel
What if you don't need every video? Maybe you just want videos about a specific topic from a channel with 2,000 uploads.
The channel search endpoint
The /youtube/channel/search endpoint lets you search within a single channel's video catalog. It costs 1 credit per search.
response = requests.get(
f"{BASE_URL}/youtube/channel/search",
params={
"channel": "@3blue1brown",
"q": "linear algebra",
"limit": 10
},
headers=headers
)
results = response.json()
for video in results:
print(f"{video['title']}")
This is much cheaper and faster than listing all videos and filtering client-side.
When to use channel search vs channel videos
Use channel search when you: - Know what topic you're looking for - Want results from a specific channel about a specific subject - Need to find videos fast without paginating through everything
Use channel videos when you: - Need the complete video catalog - Want to analyze publishing frequency or content strategy over time - Are building a full index of a channel's content
Do you usually need all videos from a channel, or just specific ones?
Channel search parameters
The channel search endpoint accepts these parameters:
ParameterTypeRequiredDescriptionchannelstringYes@handle, channel URL, or UC... IDqstringYesYour search querylimitintegerNo1-50 results (default: 30)
The channel parameter is flexible. You can pass @3blue1brown, youtube.com/@3blue1brown, or UCYO_jab_esuFRV4b17AJtAw. All three work. TranscriptAPI resolves the channel internally.

Monitoring new videos with channel latest (free)
You might not need the full history. Sometimes you just want to know when a channel uploads something new.
Want to automate this completely? Our YouTube monitoring agent tutorial shows how to build a full Slack-integrated pipeline on top of this endpoint.
The channel latest endpoint
The /youtube/channel/latest endpoint returns the 15 most recent videos from any channel. It's free, powered by RSS, and includes exact publish timestamps.
curl "https://transcriptapi.com/api/v2/youtube/channel/latest?channel=@mkbhd" \
-H "Authorization: Bearer YOUR_API_KEY"
You get titles, URLs, publish dates, view counts, and ratings. All for zero credits.
Setting up a monitoring workflow
Here's a simple pattern for tracking new uploads:
import requests
import json
from pathlib import Path
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://transcriptapi.com/api/v2"
headers = {"Authorization": f"Bearer {API_KEY}"}
TRACKED_FILE = "tracked_videos.json"
def load_tracked():
if Path(TRACKED_FILE).exists():
return json.loads(Path(TRACKED_FILE).read_text())
return []
def save_tracked(video_ids):
Path(TRACKED_FILE).write_text(json.dumps(video_ids))
def check_for_new_videos(channel):
response = requests.get(
f"{BASE_URL}/youtube/channel/latest",
params={"channel": channel},
headers=headers
)
latest = response.json()
tracked = load_tracked()
new_videos = [v for v in latest if v["videoId"] not in tracked]
if new_videos:
for video in new_videos:
print(f"New upload: {video['title']}")
# Pull transcript, send notification, etc.
transcript = requests.get(
f"{BASE_URL}/youtube/transcript",
params={"video_url": video["videoId"]},
headers=headers
)
if transcript.status_code == 200:
process_transcript(transcript.json())
tracked.extend([v["videoId"] for v in new_videos])
save_tracked(tracked)
# Run hourly via cron
check_for_new_videos("@mkbhd")
The monitoring check itself costs nothing. You only spend credits when you pull transcripts from new videos. That's a smart way to keep costs low while staying on top of content.

Building a channel analysis tool
Now let's put these endpoints together for something practical.
Content audit
Want to understand a channel's content strategy? List all videos and analyze the patterns.
import requests
from collections import Counter
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://transcriptapi.com/api/v2"
headers = {"Authorization": f"Bearer {API_KEY}"}
# Get all videos
all_videos = []
params = {"channel": "@hubaborherman"}
while True:
response = requests.get(
f"{BASE_URL}/youtube/channel/videos",
params=params,
headers=headers
)
data = response.json()
all_videos.extend(data["videos"])
if not data.get("has_more"):
break
params = {"continuation": data["continuation_token"]}
# Analyze publishing patterns
print(f"Total videos: {len(all_videos)}")
# Group by year
years = Counter()
for v in all_videos:
year = v["publishDate"][:4]
years[year] += 1
for year, count in sorted(years.items()):
print(f" {year}: {count} videos")
Competitive channel comparison
Compare two or more channels side by side:
List videos from each competitor channel
Compare publishing frequency (who posts more often?)
Search each channel for your key topics (who covers what?)
Pull transcripts from overlapping topics to compare depth and angle
This kind of analysis would take days manually. With TranscriptAPI's channel endpoints, you can automate the data collection part and spend your time on the actual analysis.
Full pipeline: channel videos to transcripts
Here's the complete pattern. List a channel's videos, then pull transcripts from each one:
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://transcriptapi.com/api/v2"
headers = {"Authorization": f"Bearer {API_KEY}"}
# Step 1: List all videos (channel/videos)
all_videos = []
params = {"channel": "@lexfridman"}
while True:
resp = requests.get(
f"{BASE_URL}/youtube/channel/videos",
params=params,
headers=headers
)
data = resp.json()
all_videos.extend(data["videos"])
if not data.get("has_more"):
break
params = {"continuation": data["continuation_token"]}
# Step 2: Get transcripts for each video
for video in all_videos[:10]: # Start with first 10
t_resp = requests.get(
f"{BASE_URL}/youtube/transcript",
params={
"video_url": video["videoId"],
"format": "text",
"send_metadata": True
},
headers=headers
)
if t_resp.status_code == 200:
data = t_resp.json()
print(f"Got transcript for: {data.get('title', 'Unknown')}")
elif t_resp.status_code == 422:
print(f"No captions for: {video['videoId']}")
This costs 1 credit per page of channel videos plus 1 credit per transcript. Failed transcript requests (like 422 for no captions) cost 0 credits. You only pay for what works.
For a deeper dive into pulling transcripts from entire channels, see our guide on extracting transcripts from YouTube channels.
Error handling for channel endpoints
Channel endpoints can fail in predictable ways. Here's how to handle them:
404: The channel doesn't exist or was deleted. Check the channel URL
422: Invalid channel format. Make sure you're passing a valid handle, URL, or UC... ID
429: You've hit the rate limit. Monthly plans allow 200 requests per minute. Annual plans allow 300. Check the
Retry-Afterheader408/503: Temporary server issue. Retry with exponential backoff
import time
def get_channel_videos_safe(channel, max_retries=3):
for attempt in range(max_retries):
response = requests.get(
f"{BASE_URL}/youtube/channel/videos",
params={"channel": channel},
headers=headers,
timeout=30
)
if response.status_code == 200:
return response.json()
if response.status_code in (408, 429, 503):
wait = int(response.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
continue
response.raise_for_status()
return None
Remember: failed requests are never charged. If a request returns any error code, that's 0 credits.
Frequently asked questions
Can I get subscriber counts or channel analytics from these endpoints?
No. TranscriptAPI's channel endpoints focus on video listing and search. For channel-level analytics like subscriber counts and total views, you'd need the YouTube Data API v3 or a third-party analytics platform. TranscriptAPI gives you the content data; analytics tools give you the audience data.
How many credits does it cost to list a channel with 1,000 videos?
About 10 credits. Each page returns roughly 100 videos, so 1,000 videos is 10 pages at 1 credit each. The channel resolve step is free. On the monthly plan at $5/1,000 credits, that's 5 cents.
Can I list videos from a YouTube channel I don't own?
Yes. TranscriptAPI can list videos from any public YouTube channel. Private and unlisted videos won't appear in the results, but everything the channel has made public is accessible.
What's the difference between channel/latest and channel/videos?
Channel latest (free) returns the 15 most recent uploads via RSS. It's perfect for monitoring and costs nothing. Channel videos (1 credit per page) returns the complete video catalog with pagination. Use latest for detecting new content. Use videos for full catalog access.
Can I combine channel endpoints with transcript extraction?
Yes, and this is one of the most common workflows. List videos from a channel, then pull transcripts for each one. Both endpoints use the same API key, same authentication, same credit system. See the "full pipeline" section above for a complete code example.
Start exploring YouTube channels
TranscriptAPI's channel endpoints make it simple to list, search, and monitor YouTube channel content. No Google Cloud setup. No quota management. No complex playlist-to-channel ID mapping.
Two of the four channel endpoints are completely free:
Channel resolve normalizes any handle or URL to a
UC...channel IDChannel latest returns the 15 most recent uploads with exact timestamps
The paid endpoints (channel videos and channel search) cost 1 credit per request.
Sign up at transcriptapi.com and get 100 free credits to start. No credit card required. Try listing your favorite channel's videos and see how fast it comes back.
Which channel would you analyze first?
For the full API reference including transcript extraction, search, and playlists, see our complete developer guide.
Frequently Asked Questions
- Do I need a channel ID, or can I pass a @handle directly?
- You can pass a @handle, a channel URL, a username, or a UC-format channel ID directly to any TranscriptAPI channel endpoint — it resolves the format internally, so there's no separate lookup step. A free resolve endpoint exists if you specifically want the canonical channel ID back, but it's optional, not a required first step.
- Why use TranscriptAPI's channel endpoints instead of the YouTube Data API v3?
- The YouTube Data API v3 takes at least three separate calls just to list a channel's videos — find the uploads playlist, paginate it, then fetch video details — and requires a Google Cloud project, OAuth, and a daily quota. TranscriptAPI's channel-videos endpoint does it in one call, returns paginated results with a continuation token, and accepts whatever channel identifier you already have. It's dramatically easier and drops straight into an existing workflow.
- How does pagination work when listing a channel with thousands of videos?
- Each response includes a continuation token and a has-more flag. While more pages remain, you pass the token back on the next call to fetch the following page. Each page returns roughly 100 videos and costs 1 credit, so a 1,000-video channel takes about 10 page calls (10 credits). Store the token between calls and you can pause and resume the job safely.



