YouTube videos.insert requires resumable upload: POST for a session URI, then PUT video chunks in multiples of 256 KB. The critical gotcha since July 28, 2020: ALL videos uploaded via unaudited API projects are FORCED to private and cannot be made public — you must pass the YouTube API Compliance Audit first. The youtube.upload scope is Restricted and also requires the audit. Quota cost is disputed (100 vs 1,600 units) — verify in Cloud Console. With 10,000 units/day, you may only get 6–100 uploads per day.
| Fact | Value |
|---|---|
| Platform | YouTube |
| Rate limits | 10,000 quota units/day per project (not per user), resets midnight Pacific… |
| Difficulty | Advanced |
| Time required | 60–120 minutes |
| Last updated | May 2026 |
API Quick Reference
10,000 quota units/day per project (not per user), resets midnight Pacific Time. Separate per-100s rate limits visible in Cloud Console.
REST only
YouTube Data API v3 — Video Upload Automation
YouTube videos.insert uses resumable upload — a two-phase protocol required for large files. Phase 1: POST request to get a session URI. Phase 2: PUT the video bytes in chunks that are multiples of 256 KB. The session URI stays valid for 1 week. For failures mid-upload, resume by sending a range query. The most important compliance requirement: as of July 28, 2020, ALL video uploads from unaudited API projects are permanently forced to private status. The uploaded video cannot be made public through the API or YouTube Studio unless the GCP project passes the YouTube API Compliance Audit. This affects any project created after July 28, 2020 that has not been audited.
https://www.googleapis.com/upload/youtube/v3Authentication
Key endpoints
Phase 1: Initiate resumable upload session. Send video metadata in the body, receive a Location header with the session URI. The session URI is valid for 1 week.
Phase 2: Upload the video binary. Send in chunks that are MULTIPLES OF 256 KB. For resuming after failure, first send a range query to find where to resume.
Update video metadata after upload: change title, description, tags, privacy status, or thumbnails. Costs 50 quota units.
Set a custom thumbnail for an uploaded video. Requires a verified YouTube channel (phone-verified). Image must be under 2 MB, at least 640x360 pixels, max 1280x720.
Check upload status and get processing progress after upload. Use to poll until uploadStatus changes from 'uploaded' to 'processed'.
Step-by-step automation
Step 1: Set Up OAuth Authentication
Configure OAuth 2.0 with youtube.upload scope. Remember: service accounts do NOT work with YouTube APIs.
1# Get authorization URL — open in browser2https://accounts.google.com/o/oauth2/v2/auth?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code&scope=https://www.googleapis.com/auth/youtube.upload&access_type=offline&prompt=consent34# Exchange authorization code for tokens5curl -X POST https://oauth2.googleapis.com/token \6 -H 'Content-Type: application/x-www-form-urlencoded' \7 -d 'code=AUTH_CODE&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&redirect_uri=REDIRECT_URI&grant_type=authorization_code'Step 2: Initiate Resumable Upload Session
Phase 1 of upload: send video metadata and file info to get a session URI. The session URI is used in Phase 2 to send the actual video bytes.
1# Phase 1: Initiate upload session (no video bytes yet)2curl -X POST \3 -H 'Authorization: Bearer ACCESS_TOKEN' \4 -H 'Content-Type: application/json' \5 -H 'X-Upload-Content-Type: video/mp4' \6 -H 'X-Upload-Content-Length: 157286400' \7 'https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status' \8 -d '{9 "snippet": {10 "title": "My Automated Upload",11 "description": "Uploaded via YouTube API",12 "tags": ["tutorial", "automation"],13 "categoryId": "22"14 },15 "status": {16 "privacyStatus": "private",17 "selfDeclaredMadeForKids": false18 }19 }'20# Response: 200 with Location header containing session_uriStep 3: Execute Upload with Progress Tracking
Phase 2: Upload the video bytes with progress tracking. The google-api-python-client handles chunking automatically. For Node.js, implement manual chunking.
1# Phase 2: Upload first chunk2curl -X PUT SESSION_URI \3 -H 'Content-Length: 8388608' \4 -H 'Content-Range: bytes 0-8388607/157286400' \5 --data-binary @chunk_0_8mb.bin6# Response 308 = more chunks needed7# Response 200/201 = complete89# Resume after interruption (find where to resume)10curl -X PUT SESSION_URI \11 -H 'Content-Length: 0' \12 -H 'Content-Range: bytes */157286400'13# Response includes Range: bytes=0-N showing what was receivedStep 4: Update Metadata After Upload
Update video title, description, or privacy status after upload. Costs 50 quota units per call.
1# Update video metadata after upload2curl -X PUT \3 -H 'Authorization: Bearer ACCESS_TOKEN' \4 -H 'Content-Type: application/json' \5 'https://www.googleapis.com/youtube/v3/videos?part=snippet,status' \6 -d '{7 "id": "VIDEO_ID",8 "snippet": {9 "title": "Updated Title",10 "description": "Updated description with more detail.",11 "categoryId": "22",12 "tags": ["updated", "tag"]13 },14 "status": {15 "privacyStatus": "public"16 }17 }'Step 5: Check Processing Status
After upload, YouTube processes the video (transcoding, thumbnail generation). Poll processingDetails until uploadStatus is 'processed'.
1# Check processing status2curl -H 'Authorization: Bearer ACCESS_TOKEN' \3 'https://www.googleapis.com/youtube/v3/videos?part=status,processingDetails&id=VIDEO_ID'Complete working code
Full video upload pipeline: validates the file, uploads with resumable protocol, sets a custom thumbnail, updates metadata, and waits for processing. Includes compliance audit status checking.
Error handling
Your GCP project has not passed the YouTube API Compliance Audit. Since July 28, 2020, ALL videos uploaded via unaudited projects are permanently locked to private status, regardless of the privacyStatus field you send. This affects any project created after that date without an audit.
You've hit the 10,000 daily quota limit. With videos.insert costing potentially 1,600 units, this means as few as 6 uploads can exhaust the daily budget. The quota resets at midnight Pacific Time.
Common causes: unsupported video format, file corrupt, total file size doesn't match X-Upload-Content-Length header, or chunk size not a multiple of 256 KB.
Resumable upload session URIs expire after 1 week. If you created the session and waited more than 7 days before completing the upload, the session is gone.
Normal for long videos or high platform load. YouTube processing time scales with video length, resolution, and codec. A 4K 1-hour video can take 30+ minutes to process.
Rate limits & throttling
Security checklist
- Always start uploads with privacyStatus='private' — make videos public only after reviewing the uploaded content, even if your project has passed the audit
- Store OAuth tokens and credentials files with restricted file permissions (chmod 600) and outside the web root
- Never commit credentials.json or token.json to version control — add them to .gitignore immediately
- Implement upload size validation before initiating a session — reject files over YouTube's 256 GB limit and unsupported formats
- For automated upload pipelines, validate video titles and descriptions for policy compliance before uploading to avoid strikes or channel termination
- Set selfDeclaredMadeForKids correctly — uploading COPPA-regulated children's content without this flag can result in legal liability and channel termination
- Log all uploads with video IDs, timestamps, and uploader identity for audit trails
- Implement webhook or polling notifications to your team when uploads complete — do not leave uploaded videos unreviewed
Automation use cases
No-code alternatives
Don't want to write code? These platforms can automate the same workflows visually.
Zapier
YouTube integration in Zapier includes a 'Upload Video' action. Triggers can be new files in Google Drive, Dropbox, or Box. Handles OAuth automatically and abstracts the resumable upload protocol.
Make (Integromat)
YouTube 'Upload a Video' module handles the full upload. More flexible than Zapier for complex metadata templates and multi-step scenarios (upload > thumbnail > update description). Monitors upload progress.
n8n
YouTube node with video upload support. HTTP Request nodes can handle custom resumable upload scenarios. Best for complex automation with error handling and conditional logic.
Best practices
- Submit the YouTube API Compliance Audit before building any upload automation — without it, every uploaded video is permanently locked as private regardless of your privacyStatus setting
- Always use resumable upload (uploadType=resumable) for video files — simple upload (uploadType=media) is limited to 5 MB and will fail for any real video
- Use chunk sizes that are exact multiples of 256 KB (262,144 bytes) — the last chunk can be any size, but all intermediate chunks must be multiples
- Start uploads with privacyStatus='private' and change to public after review — even for automated pipelines, a review step reduces policy violation risk
- Set selfDeclaredMadeForKids accurately — this is a legal requirement under COPPA/GDPR for child-directed content
- Store resumable upload session URIs in a database with creation timestamps — valid for 1 week, allowing you to resume interrupted uploads rather than starting over
- Verify the actual videos.insert quota cost in Cloud Console — the disputed 100 vs 1,600 unit cost makes a major difference in your upload capacity planning
- Use categoryId from videoCategories.list with your regionCode — categories vary by region, and some category IDs are not assignable (assignable=false)
Ask AI to help
Copy one of these prompts to get a personalized, working implementation.
I'm building a YouTube video upload automation using YouTube Data API v3. Key requirements: (1) resumable upload protocol (POST for session URI, PUT chunks in 256KB multiples), (2) privacyStatus must be 'private' until after YouTube API Compliance Audit, (3) check processing status via videos.list with processingDetails part, (4) handle 10,000 unit/day quota (videos.insert disputed cost: 100 vs 1,600 units), (5) retry on 500/503 errors with exponential backoff. Use Python with google-api-python-client MediaFileUpload. OAuth only — no service accounts.
Build a video upload tool for content creators. UI: drag-and-drop file upload, form for title/description/tags/category/privacy, thumbnail upload, submit button. After submit: show upload progress bar (percentage), then processing status indicator. When complete, show the YouTube video URL. Backend calls YouTube Data API v3 resumable upload. Warn the user if the video gets locked as private (Compliance Audit requirement). Store upload history in Supabase.
Frequently asked questions
Why are all my uploaded videos locked as private even though I set privacyStatus='public'?
Your GCP project has not passed the YouTube API Compliance Audit. Since July 28, 2020, all videos uploaded via the API from unaudited projects are automatically forced to private status. This applies regardless of what privacyStatus you send. Submit the YouTube API Services Compliance Audit form at console.cloud.google.com. Until your project is audited and approved, you cannot make API-uploaded videos public — not via the API and not via YouTube Studio.
How many videos can I upload per day with the YouTube Data API?
It depends on the disputed quota cost for videos.insert. If the cost is 100 units, you can upload 100 videos/day on the 10,000 unit free quota. If it's 1,600 units (which many sources report), you can only upload 6 videos/day. Check your actual consumption in Cloud Console > APIs & Services > Quotas after a test upload. For more than 10,000 units/day, submit the YouTube API Services Audit and Quota Extension Form.
What is resumable upload and why is it required?
Resumable upload is a two-phase protocol: Phase 1 sends video metadata and gets a session URI. Phase 2 sends the actual video bytes in chunks to that URI. It's required because video files are too large for simple HTTP POST requests, and it allows you to resume a failed upload from where it stopped rather than starting over. Session URIs are valid for 1 week. Chunk sizes must be multiples of 256 KB (262,144 bytes).
Can I use a service account to upload videos on behalf of multiple YouTube channels?
No. Service accounts are not supported by any YouTube API — they return NoLinkedYouTubeAccount because a service account has no YouTube channel. For multi-channel upload automation, each channel's owner must authorize your app via OAuth, and you must store separate refresh tokens for each channel. There is no workaround for this limitation.
What categoryId should I use for my videos?
Call videoCategories.list with your target regionCode to get the list of valid categories and their assignable status. Common IDs: 22 = People & Blogs, 10 = Music, 20 = Gaming, 28 = Science & Technology, 27 = Education, 24 = Entertainment. Not all categories are assignable (assignable=false) and some categories vary by region.
Can RapidDev help build a video upload pipeline for my platform?
Yes. If you need to automate video publishing to YouTube as part of a content workflow — pulling from Google Drive, applying consistent metadata templates, setting thumbnails, and tracking processing status — RapidDev can build that pipeline. We also help navigate the Compliance Audit requirements so your videos can actually go public.
What happens if my upload is interrupted halfway through?
For resumable uploads, you can recover. Send a PUT to the session URI with Content-Range: bytes */TOTAL_SIZE and Content-Length: 0 to get a 308 Resume Incomplete response with a Range header showing how many bytes the server received. Then resume the upload from byte (Range end + 1). Session URIs are valid for 1 week from creation — after that you must start over.
Need this automated?
Our team has built 600+ apps with API automations. We can build this for you.
Book a free consultation