alpaka206

YouTube Data API v3 활용법

date
Apr 27, 2026
slug
youtube-data-api-v3-upload
author
status
Public
tags
Blog
Github
Study
AI
summary
YouTube에 영상을 자동 업로드하는 서비스를 만들어보고 싶어서 YouTube Data API v3의 영상 업로드, SRT 자막 업로드, 다국어 제목/설명 등록 흐름을 공부해보았습니다.
type
Post
thumbnail
category
📗 Docs
updatedAt
May 5, 2026 04:41 PM

시작하며

YouTube에 영상을 자동으로 업로드하는 서비스를 만들어보고 싶어서 YouTube Data API v3에 대해 공부해보았습니다.
생각했던 서비스 흐름은 단순했습니다. 사용자가 영상을 만들거나 AI 더빙 결과물을 받으면, 그 파일을 다시 직접 YouTube Studio에 들어가서 업로드하지 않고 서비스 안에서 바로 YouTube에 올릴 수 있게 만드는 것이었습니다.
그런데 막상 구현하려고 보니 영상 업로드만 생각해서는 부족하였고, 실제로는 다음 세 가지가 함께 필요했습니다.
  1. 영상을 YouTube에 업로드하는 방법
  1. 자막 파일을 영상에 업로드하는 방법
  1. 다국어 제목과 설명 같은 메타데이터를 함께 등록하는 방법
이번 글에서는 dubtube 프로젝트를 만들며 공부한 내용을 기준으로, YouTube Data API v3에서 이 세 가지를 어떻게 처리할 수 있는지 정리해보았습니다.

전체 흐름

먼저 전체 구조는 다음과 같습니다.
  1. 사용자가 Google OAuth로 로그인합니다.
  1. 서버는 YouTube 업로드 권한이 있는 access token을 확보합니다.
  1. 서버 API가 영상 파일 또는 영상 URL을 받습니다.
  1. videos.insert로 YouTube 업로드 세션을 만듭니다.
  1. 반환된 upload URL에 실제 영상 파일을 PUT으로 업로드합니다.
  1. 업로드 결과로 videoId를 받습니다.
  1. SRT 자막이 있으면 captions.insert로 업로드합니다.
  1. 다국어 제목과 설명은 영상 업로드 시 localizations에 포함합니다.
여기서 YouTube Data API v3 호출을 브라우저에서 직접 처리하지 않고 서버에서 처리한 이유는 OAuth access token과 외부 파일 URL을 다루기 때문에, 클라이언트보다 서버에서 제어하는 편이 더 안전하다고 생각하였습니다.

1. 영상 올리는 법

YouTube에 영상을 올릴 때는 videos.insert를 사용합니다.
공식 endpoint는 다음 형태입니다.
POST https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status
일반 업로드보다 resumable upload 방식을 기준으로 공부했습니다. 영상 파일은 용량이 크기 때문에, metadata 요청과 실제 파일 업로드를 분리하는 방식이 더 적합할 것 같아서 위 방식으로 진행하였습니다.

1-1. 업로드 세션 만들기

먼저 영상의 metadata를 담아 YouTube에 업로드 세션을 생성합니다.
요청 body에는 video resource 형태로 snippetstatus를 넣습니다.
const metadata = { snippet: { title: '업로드할 영상 제목', description: '업로드할 영상 설명', tags: ['AI dubbing', 'YouTube Data API'], categoryId: '22', defaultLanguage: 'ko', defaultAudioLanguage: 'ko', }, status: { privacyStatus: 'private', selfDeclaredMadeForKids: false, }, }
그리고 다음과 같은 header를 함께 보냅니다.
const initRes = await fetch( 'https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status', { method: 'POST', headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json; charset=UTF-8', 'X-Upload-Content-Length': String(videoBlob.size), 'X-Upload-Content-Type': videoBlob.type || 'video/mp4', }, body: JSON.stringify(metadata), }, )
이 요청이 성공하면 YouTube는 응답 header의 Location 값으로 실제 업로드 URL을 내려줍니다.

1-2. 실제 영상 파일 업로드하기

업로드 세션을 만들었다면, 이제 Location으로 받은 URL에 실제 영상 파일을 PUT으로 업로드합니다.
const uploadUrl = initRes.headers.get('Location') const putRes = await fetch(uploadUrl, { method: 'PUT', headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': videoBlob.type || 'video/mp4', }, body: videoBlob, })
업로드가 성공하면 응답으로 YouTube video resource가 반환됩니다. 여기서 id 값을 꺼내면 이후 자막 업로드나 Studio 링크 생성에 사용할 수 있습니다.
const result = await putRes.json() const videoId = result.id
이 흐름을 정리하면 다음과 같습니다.
metadata POST -> Location header로 upload URL 수신 -> upload URL에 video blob PUT -> videoId 수신
공식 문서 기준으로 videos.insert는 업로드와 metadata 설정을 함께 처리할 수 있습니다. 다만 2020년 7월 28일 이후 생성된 미검증 API 프로젝트에서 업로드한 영상은 기본적으로 비공개 상태로 제한될 수 있으므로, 실제 서비스로 운영하려면 YouTube API Services의 프로젝트 검증과 심사 절차도 고려해야 한다고 합니다.

2. 자막 올리는 법

영상 업로드가 끝났다면 다음은 자막입니다. 자막은 영상 업로드 API와 별도입니다. YouTube Data API v3에서는 captions.insert를 사용해 특정 영상에 caption track을 추가합니다.
endpoint는 다음 형태입니다.
POST https://www.googleapis.com/upload/youtube/v3/captions?uploadType=multipart&part=snippet
자막 업로드에는 두 가지 정보가 필요합니다.
  1. 자막 metadata
  1. 실제 SRT 파일 내용
metadata에는 최소한 videoId, language, name이 필요합니다.
const metadata = { snippet: { videoId, language: 'en', name: 'English', }, }
그리고 실제 자막 내용은 SRT 형식으로 준비합니다.
1 00:00:00,000 --> 00:00:02,000 Hello, everyone. 2 00:00:02,000 --> 00:00:04,000 This video was dubbed automatically.
captions.insert는 metadata와 자막 파일을 같이 보내야 하므로 multipart/related 요청을 구성했습니다.
const boundary = `caption_boundary_${Date.now()}` const body = `--${boundary}\r\n` + `Content-Type: application/json; charset=UTF-8\r\n\r\n` + JSON.stringify(metadata) + `\r\n--${boundary}\r\n` + `Content-Type: application/x-subrip\r\n\r\n` + srtContent + `\r\n--${boundary}--` const res = await fetch( 'https://www.googleapis.com/upload/youtube/v3/captions?uploadType=multipart&part=snippet', { method: 'POST', headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': `multipart/related; boundary=${boundary}`, }, body, }, )
여기서 주의할 점이 있습니다.
같은 영상에 같은 언어와 같은 이름의 caption track이 이미 있으면 충돌이 발생할 수 있습니다. 그래서 서비스에서는 replace 옵션이 필요하다면 먼저 기존 caption 목록을 조회하고, 같은 언어의 자막을 삭제한 뒤 새 자막을 올리는 방식으로 처리할 수 있습니다.
또 하나는 SRT 시간 정보입니다. 예전에는 YouTube가 transcript를 자동 sync하는 옵션을 제공했지만, 현재 sync 파라미터는 deprecated 상태입니다. 그래서 자동화 서비스에서는 가능하면 시작 시간과 종료 시간이 들어간 정상적인 SRT를 만들어 업로드하는 편이 안전합니다.

3. 다국어 제목과 설명(localizations) 올리는 법

AI 더빙 서비스를 만든다면 단순히 영상만 다른 언어로 만드는 것으로 끝나지 않습니다. 제목과 설명도 언어별로 보여줄 수 있어야 합니다. YouTube Data API v3의 video resource에는 localizations 객체가 있습니다. 이 객체를 사용하면 언어 코드별 제목과 설명을 등록할 수 있습니다.
예를 들어 한국어를 기본 metadata로 두고, 영어와 일본어 metadata를 추가하고 싶다면 다음과 같이 구성할 수 있습니다.
const metadata = { snippet: { title: 'AI 더빙 테스트 영상', description: '한국어 기본 설명입니다.', categoryId: '22', defaultLanguage: 'ko', defaultAudioLanguage: 'ko', }, status: { privacyStatus: 'private', selfDeclaredMadeForKids: false, }, localizations: { en: { title: 'AI Dubbing Test Video', description: 'This is the English description.', }, ja: { title: 'AI吹き替えテスト動画', description: 'これは日本語の説明です。', }, }, }
이때 요청 URL의 part에도 localizations를 포함해야 합니다.
POST https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status,localizations
즉, 다국어 제목과 설명을 함께 올리고 싶다면 영상 업로드 세션을 만들 때부터 localizations를 포함하는 것이 가장 자연스럽습니다.
정리하면 다음과 같습니다.
목적
사용하는 필드
기본 제목
snippet.title
기본 설명
snippet.description
기본 언어
snippet.defaultLanguage
기본 오디오 언어
snippet.defaultAudioLanguage
다국어 제목
localizations.{language}.title
다국어 설명
localizations.{language}.description
언어 코드는 en, ko, ja처럼 BCP-47 언어 코드를 사용합니다.

서버 API에서 처리한 이유

이 기능은 클라이언트에서 바로 YouTube Data API v3를 호출하도록 만들 수도 있습니다. 하지만 저는 서버 API route를 두는 구조가 더 적합하다고 생각했습니다.
이유는 다음과 같습니다.
  1. OAuth access token을 서버에서 통제할 수 있습니다.
  1. 외부 영상 URL을 서버가 fetch할 때 허용 도메인을 제한할 수 있습니다.
  1. YouTube Data API v3 에러를 서비스에서 사용하는 에러 형태로 변환할 수 있습니다.
  1. 업로드, 자막, metadata 처리를 하나의 흐름으로 묶기 쉽습니다.
특히 외부 URL을 받아 서버가 대신 fetch하는 기능에서는 SSRF 방어가 필요합니다. 그래서 모든 URL을 허용하지 않고, 서비스에서 생성한 영상 결과 URL이나 신뢰할 수 있는 스토리지 도메인만 허용하는 방식이 필요합니다.

구현하면서 헷갈렸던 점

처음에 헷갈렸던 부분은 자막과 다국어 metadata가 서로 다른 개념이라는 점입니다.
자막은 captions.insert로 올립니다. 시청자가 자막 버튼을 눌러 선택하는 텍스트 트랙입니다.
반면 다국어 제목과 설명은 videos.insert 또는 videos.update에서 localizations로 다룹니다. 사용자의 언어 환경에 따라 YouTube가 보여줄 metadata입니다.
즉, 다국어 영상을 자동화하려면 최소한 다음 세 가지를 따로 생각해야 합니다.
  1. 영상 파일
  1. 자막 트랙
  1. 다국어 metadata
이 세 가지를 분리해서 생각하면 YouTube Data API v3 구조가 훨씬 이해하기 쉬웠습니다.

마무리

이번에 YouTube 자동 업로드 기능을 공부하면서, 단순히 영상을 올린다는 기능 안에도 여러 단계가 있다는 것을 알게 되었습니다.
영상은 videos.insert로 올리고, 자막은 captions.insert로 올리며, 다국어 제목과 설명은 localizations로 관리합니다. 겉으로는 하나의 업로드 기능처럼 보이지만 실제 구현에서는 각각의 resource와 endpoint가 다릅니다.

참고 자료