How do I get all videos from a YouTube channel with an API?
Call GET /v1/youtube/profiles/@{handle}/videos and pass meta.cursors.next back as cursor until it is null. Each page lists the channel’s videos with title, length, views, and upload date. Sort with sort=newest, popular, or oldest. Pass since to stop at a date.
YouTube keeps Shorts and livestreams on their own tabs, and so does the API. Call /shorts and /livestreams on the same channel to get those too.
With the YouTube Data API you first look up the channel’s uploads playlist. Then you page through playlistItems.list, up to 50 videos for 1 quota unit. That list mixes videos and Shorts, and nothing marks which is which.
Checked October 2026 · request and response run against the API · no affiliate links
curl "https://api.openhandle.dev/v1/youtube/profiles/@synthetic_youtube/videos?sort=newest" \
-H "Authorization: Bearer $OPENHANDLE_API_KEY"import { OpenHandle } from '@openhandle/sdk';
const openhandle = new OpenHandle({ apiKey: process.env.OPENHANDLE_API_KEY! });
let page = await openhandle.youtube.profile('synthetic_youtube').videos.list({ sort: 'newest' });
while (true) {
for (const video of page.data) console.log(video.id, video.title);
const next = await page.next();
if (!next) break;
page = next;
}{
"platform": "youtube",
"resource": "post",
"capturedAt": "2026-10-26T18:33:16Z",
"source": "live",
"data": [
{
"id": "synthvid001",
"type": "video",
"title": "Synthetic video 1",
"url": "https://www.youtube.com/watch?v=synthvid001",
"approximateCreatedAt": "2026-10-25",
"createdAtLabel": "1 days ago",
"duration": 240,
"author": { "id": "UCsyntheticyoutube000001", "handle": "synthetic_youtube" },
"metrics": { "views": 1200000, "isApproximate": true }
}
],
"meta": { "cursors": { "next": "b3BhcXVlLWN1cnNvcg" } }
}Trimmed to one video and the fields this question needs. The channel is in the Test dataset, so you can run it on a free Test key.
Rounded counts and dates
A channel’s video list on YouTube shows labels like "1.2M views" and "1 day ago". We keep what YouTube shows: the rounded count with isApproximate: true, the label in createdAtLabel, and an estimated day in approximateCreatedAt. For the exact count and time, read the video with GET /v1/youtube/posts/{videoId}.
Every tab of a channel
| Tab | Openhandle call |
|---|---|
| Channel details | GET /v1/youtube/profiles/@handle |
| Videos | GET /v1/youtube/profiles/@handle/videos |
| Shorts | GET /v1/youtube/profiles/@handle/shorts |
| Live | GET /v1/youtube/profiles/@handle/livestreams |
| Playlists | GET /v1/youtube/profiles/@handle/playlists |
| Posts | GET /v1/youtube/profiles/@handle/community-posts |
| Search inside the channel | GET /v1/youtube/profiles/@handle/search?q=term |
Channels take an @handle or a channel ID that starts with UC. Start from a channel URL? POST /v1/urls/fetch accepts it.
When this does not work
These answers are definitive. Store them, do not retry them.
| Situation | Status | Code |
|---|---|---|
| The channel does not exist | 404 | PROFILE_NOT_FOUND |
| The cursor came from another channel or sort | 400 | CURSOR_MISMATCH |
{
"error": {
"code": "PROFILE_NOT_FOUND",
"message": "This profile was not found.",
"requestId": "req_01m5…",
"retryable": false
}
}Every new workspace starts with 100 free live requests, no card needed.
Read next
More YouTube questions
Send your agent ahead.
Paste the prompt into your agent and it sets everything up. Or come yourself, it takes five minutes.
100 free requests. No card needed.