How to Upload Videos with the YouTube Data API in 2026 (the Quota Math Just Changed)
Short answer: yes, you can upload video to YouTube from your own code, and the endpoint has not changed in years. videos.insert still does the job.
Longer answer: for most of the API's life, that one call was also the fastest way to burn through your daily quota. A single upload cost 1,600 units against a 10,000-unit daily default, which meant roughly six uploads a day before you were locked out until midnight Pacific. Reports through late 2025 and into 2026 point to that math changing more than once. If you built your integration around the old numbers, it is worth rereading this before you write another retry loop.
What you need before you write a single line of code
- A Google Cloud project with the YouTube Data API v3 enabled.
- An OAuth 2.0 client (web or installed app type, depending on where the upload runs).
- Consent from the channel owner for the
https://www.googleapis.com/auth/youtube.uploadscope, or the broaderyoutube.force-sslscope if you also need to manage captions, playlists, or comments. - A verified project if you want uploads that are visible to anyone other than the channel owner (more on this below).
- Patience for resumable upload logic. Video files are large, mobile connections drop, and the naive single-request upload will fail you eventually.
There is no app-only or server-to-server auth path here. Every upload happens on behalf of an authenticated YouTube channel through OAuth2. There is no service-account shortcut, no API-key-only mode. If your product uploads on behalf of users, each user goes through the consent screen once and you store a refresh token.
The videos.insert call: multipart and resumable
videos.insert takes two things: a metadata object (title, description, tags, category, privacy status) and the actual video bytes. You have two ways to send both.
Multipart upload sends metadata and video in a single request. It works, but for anything over a few dozen megabytes it is fragile. One dropped connection and you start the whole upload over.
Resumable upload is the one to actually build with. It is a two-step handshake:
POST https://www.googleapis.com/upload/youtube/v3/videos
?uploadType=resumable&part=snippet,status
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Type: video/*
X-Upload-Content-Length: <bytes>
{ "snippet": {...}, "status": {...} }
The response includes a Location header, a session URI you then PUT the video bytes to, in chunks, with the ability to query progress and resume from the last received byte if the connection drops. For anything you expect to run unattended (a scheduler, a batch job, a CI pipeline that publishes demo videos), resumable is the only sane choice.
See how TimeToPost can help you implement these strategies.
Quota math: old vs new, worked out
This is the part that actually changes your architecture, so let's do the numbers rather than wave at them.
Every Google Cloud project gets a default daily quota, historically 10,000 units, that resets at midnight Pacific time regardless of your local timezone. Every API call costs a fixed number of units from that pool: a videos.list call might cost 1 unit, a search.list call costs 100, and videos.insert was priced far above either of those because YouTube treats an upload as the most resource-intensive thing you can ask the API to do.
| Period | Cost of one videos.insert | Quota pool it draws from | Uploads you can actually do in a day |
|---|---|---|---|
| Historic (pre-Dec 2025) | 1,600 units | 10,000 units/day, shared with every other call your app makes | ~6, and that consumes 9,600 of your 10,000 units, leaving almost nothing for reads |
| Reportedly cut, Dec 4, 2025 [hedge, widely reported, not independently confirmed here] | ~100 units | Still the same shared 10,000-unit pool | ~100 uploads in theory, but every list, search, or update call you make competes with those uploads for the same pool |
| Reportedly split into its own bucket, Jun 1, 2026 [hedge, widely reported, present as a reported change] | ~100 units | A separate, dedicated upload allowance reported at roughly 100 calls/day, on top of the general 10,000-unit pool | ~100 uploads/day without those uploads eating into the quota your app needs for reads, updates, and everything else |
The practical read: if you built your scheduler in 2024 assuming six uploads a day was the ceiling, you were probably leaving quota on the table by mid-2026, but the exact cost YouTube charges for videos.insert today is something you should confirm against your own Google Cloud Console quota page before you rely on it, since these figures are reported changes rather than a stable published spec at the time of writing.
Either way, requesting a quota increase from Google is still the move if your product uploads video at any real volume. The application asks what you are building and why; approval can take days to a few weeks.
The unverified-project trap: private-only uploads
Here is the one that catches people who tested everything correctly and then shipped to real users. If your Google Cloud project was created after July 28, 2020, and has not been through YouTube API compliance audit, every video your app uploads is forced to privacyStatus: private, regardless of what your code requests.
That means your integration will appear to work in testing (you are the channel owner, you can see your own private video) and then fail silently for every other user, whose uploaded videos never become public or unlisted no matter what status you send. The fix is submitting your project for an audit through the API Services Compliance process in Cloud Console. Budget real calendar time for this before you promise customers automated publishing.
Required metadata and the 15-minute rule
At minimum, videos.insert needs:
snippet.categoryId, a numeric YouTube category ID. Omit it and the call fails validation.status.privacyStatus, one ofprivate,unlisted, orpublic.snippet.title, required even if you plan to edit it later.
One constraint trips up anyone uploading longer content: an account has to be phone-verified to upload videos longer than 15 minutes. Verification is a one-time step in YouTube Studio, but if your product onboards users programmatically, tell them up front, or you will get support tickets about uploads that silently truncate or fail for accounts stuck at the 15-minute ceiling.
Errors you will actually hit
quotaExceeded: you have used your daily allowance. Check the Cloud Console quota dashboard before assuming it is a bug, and remember the reset happens at midnight Pacific, not your local midnight.uploadLimitExceeded: separate from API quota, this is YouTube's per-channel daily upload cap, which exists independently of how much of your project's quota you have left.invalidCategoryId: a stale or wrong category ID. Pull the current list fromvideoCategories.listrather than hardcoding one.- Resumable session expiry: session URIs from the initial POST are not valid forever. If your batch job queues uploads and processes them later, do not cache a session URI across days.
Scheduling uploads instead of publishing immediately
You do not need to upload and go public in the same call. Set status.privacyStatus to private or unlisted at upload time, then use status.publishAt with an RFC 3339 timestamp to have YouTube flip the video to public automatically at a future time. This is the mechanism behind any tool that lets you queue a video today and have it go live next Tuesday at your best-performing time slot rather than the moment the render finishes.
That is also where a scheduler earns its keep instead of a raw API client: TimeToPost handles the resumable-upload plumbing, the OAuth refresh, and the publishAt scheduling so you queue a video once and stop thinking about quota units, session URIs, or midnight Pacific resets.
FAQ
Do I need a Google Cloud quota increase to upload more than a handful of videos a day?
Probably, if you are uploading at any real volume. Even with the reported 2025-2026 cost reductions on videos.insert, the default 10,000-unit pool is shared with every other call your app makes, so a busy integration still runs into the ceiling.
Why are my uploaded videos stuck as private even though I requested public?
Your Google Cloud project almost certainly has not passed YouTube's API audit. Projects created after July 28, 2020 default every upload to private until that audit clears, no matter what privacyStatus you send.
Can I upload without OAuth, using just an API key?
No. Uploads require an authenticated user via OAuth2 with the youtube.upload scope. API keys alone only work for public read-only endpoints.
What happens if my upload gets interrupted halfway through? If you used the resumable upload protocol, you query the session URI for the last received byte and resume from there. If you used simple multipart upload, you start over, which is the main reason to build on resumable from day one.
Do I really need phone verification just to post a 20-minute video? Yes. Any video over 15 minutes requires the uploading account to have completed phone verification in YouTube Studio, a one-time step that is worth doing before you build anything long-form into your workflow.
If your uploads are landing on YouTube Shorts specifically, the constraints are different again, worth checking against our YouTube Shorts scheduling guide before you script a batch job around this endpoint. If you are building the same kind of pipeline for TikTok, our TikTok API guide covers the equivalent upload flow on that side, and our YouTube best-time data is worth pairing with publishAt so scheduled videos land when your channel's audience is actually online. Our posting schedule generator can turn that data into an actual calendar.