Uploading Videos to YouTube API
There are two valid upload patterns depending on your runtime and file size constraints.
Approach A: Google API Client (googleapis) Upload
Good for standard Node services with local file access.
const response = await youtube.videos.insert({
part: ['snippet', 'status', 'localizations'],
requestBody,
media: { body: createReadStream(videoPath) },
});
Useful features:
- direct metadata + media call
- easy scheduled publishing (
publishAt) - straightforward retry wrappers
Approach B: Resumable Streaming Upload
Good for Worker/edge pipelines, large files, or R2 stream sources.
Session Init
const response = await fetch(
'https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status,contentDetails',
{ method: 'POST', headers, body: JSON.stringify(metadata) }
);
const uploadUrl = response.headers.get('Location');
Chunk Upload
- Use
256KBaligned chunks. - Send
Content-Rangeeach PUT. - On
308, parseRangeto reconcile acknowledged bytes.
if (response.status === 308) {
const range = response.headers.get('Range');
const match = range?.match(/bytes=0-(\d+)/);
bytesUploaded = match ? Number(match[1]) + 1 : bytesUploaded + chunk.length;
}
Metadata Defaults (Common News Pipeline)
- category
25 defaultLanguage='ja'containsSyntheticMedia=true- privacy policy-driven (
publicwhen clean,privateotherwise)
Thumbnail Upload (Recommended)
After main upload:
- upload JPEG thumbnail via
thumbnails/set - enforce 2MB limit with resize/quality fallback
- treat thumbnail failure as warning if main video is already uploaded
Which Approach to Choose
- Use Approach A for simple app servers and local files.
- Use Approach B for distributed pipelines, stream sources, and strict memory environments.