YouTube API Daily Limit: Complete Guide to Quota Restrictions and Upload Limits in 2026
Understanding the YouTube API Daily Limit is critical for developers and creators building automated video publishing tools. Unlike other platforms that use a simple “requests per hour” or “posts per day” model, YouTube employs a complex Quota Unit system where different actions “cost” different amounts regarding your daily allowance.
In this guide, we will break down how the YouTube API Daily Limit and quota system works, the specific costs of uploading videos effectively limiting you to just a few posts per day by default, and how to request more quota. We will also provide technical implementation details for resumable uploads using Python.
YouTube Data API Quick Reference
The YouTube Data API uses a Quota Unit system rather than simple rate limits. Every API request, including invalid ones, incurs a cost of at least one unit. The quota resets daily at Midnight Pacific Time (PT).
Understanding the YouTube API Daily Limit
The YouTube Data API (v3) does not treat all API requests equally. Instead of a fixed number of calls, your project is assigned a daily quota allocation (default 10,000 units). Each API method you call deducts a specific number of units from this total. This is the core of how the YouTube API Daily Limit functions.
While reading data is cheap, writing data (especially uploading videos) is very expensive. Below is the cost breakdown for common operations according to the official YouTube API documentation:
| Resource | Method | Quota Cost | Description |
|---|---|---|---|
| Videos | insert |
1,600 | Uploading a video file |
| Captions | insert |
400 | Uploading a caption track |
| Captions | update |
450 | Updating a caption track |
| Search | list |
100 | Searching for videos/channels |
| Videos | list |
1 | Retrieving video metadata |
| Videos | update |
50 | Updating video metadata |
| Videos | rate |
50 | Adding a like/dislike |
| Videos | delete |
50 | Deleting a video |
| Thumbnails | set |
50 | Uploading a custom thumbnail |
| Playlists | insert |
50 | Creating a new playlist |
| PlaylistItems | insert |
50 | Adding a video to a playlist |
| Comments | insert |
50 | Posting a comment |
| Subscriptions | insert |
50 | Subscribing to a channel |
| ChannelBanners | insert |
50 | Uploading a channel banner |
| Watermarks | set |
50 | Setting a channel watermark |
| Activities | list |
1 | Retrieving channel activities |
| Channels | list |
1 | Retrieving channel information |
| Captions | list |
50 | Listing caption tracks |
search.list that returns multiple pages of results, each request to retrieve an additional page incurs the full quota cost. Paginating through 10 pages of search results costs 1,000 units total.
YouTube API Daily Limit: The Effective Upload Cap
For most users and simple applications, the default YouTube API Daily Limit of 10,000 units results in a very strict upload limit. If your application only performs video uploads and nothing else, the calculation is:
Thus, effectively, you can only upload 6 videos per day with a standard API project due to the YouTube API Daily Limit. If you also upload a custom thumbnail (50 units) and check if the video was uploaded (1 unit), your budget tightens further.
403 quotaExceeded error for all subsequent write requests until the reset occurs.
Python Code Example: Uploading a Video
Below is a standardized Python script demonstrating how to upload a video using the google-api-python-client. This script handles the authentication flow and video metadata insertion.
#!/usr/bin/python
import httplib
import httplib2
import os
import random
import sys
import time
from apiclient.discovery import build
from apiclient.errors import HttpError
from apiclient.http import MediaFileUpload
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import argparser, run_flow
# Explicitly tell the underlying HTTP transport library not to retry
httplib2.RETRIES = 1
# Maximum number of times to retry before giving up.
MAX_RETRIES = 10
# Always retry when these exceptions are raised.
RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, httplib.NotConnected,
httplib.IncompleteRead, httplib.ImproperConnectionState,
httplib.CannotSendRequest, httplib.CannotSendHeader,
httplib.ResponseNotReady, httplib.BadStatusLine)
RETRIABLE_STATUS_CODES = [500, 502, 503, 504]
CLIENT_SECRETS_FILE = "client_secrets.json"
YOUTUBE_UPLOAD_SCOPE = "https://www.googleapis.com/auth/youtube.upload"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
VALID_PRIVACY_STATUSES = ("public", "private", "unlisted")
def get_authenticated_service(args):
flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE,
scope=YOUTUBE_UPLOAD_SCOPE,
message=MISSING_CLIENT_SECRETS_MESSAGE)
storage = Storage("%s-oauth2.json" % sys.argv[0])
credentials = storage.get()
return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
http=credentials.authorize(httplib2.Http()))
def initialize_upload(youtube, options):
tags = None
if options.keywords:
tags = options.keywords.split(",")
body=dict(
snippet=dict(
title=options.title,
description=options.description,
tags=tags,
categoryId=options.category
),
status=dict(
privacyStatus=options.privacyStatus
)
)
insert_request = youtube.videos().insert(
part=",".join(body.keys()),
body=body,
media_body=MediaFileUpload(options.file, chunksize=-1, resumable=True)
)
resumable_upload(insert_request)
def resumable_upload(insert_request):
response = None
error = None
retry = 0
while response is None:
try:
print "Uploading file..."
status, response = insert_request.next_chunk()
if response is not None:
if 'id' in response:
print "Video id '%s' was successfully uploaded." % response['id']
else:
exit("The upload failed with an unexpected response: %s" % response)
except HttpError, e:
if e.resp.status in RETRIABLE_STATUS_CODES:
error = "A retriable HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
else:
raise
except RETRIABLE_EXCEPTIONS, e:
error = "A retriable error occurred: %s" % e
if error is not None:
print error
retry += 1
if retry > MAX_RETRIES:
exit("No longer attempting to retry.")
max_sleep = 2 ** retry
sleep_seconds = random.random() * max_sleep
print "Sleeping %f seconds and then retrying..." % sleep_seconds
time.sleep(sleep_seconds)
if __name__ == '__main__':
argparser.add_argument("--file", required=True, help="Video file to upload")
argparser.add_argument("--title", help="Video title", default="Test Video")
argparser.add_argument("--description", help="Video description", default="Test Description")
argparser.add_argument("--category", default="22", help="Numeric video category.")
argparser.add_argument("--keywords", help="Video keywords, comma separated", default="")
argparser.add_argument("--privacyStatus", choices=VALID_PRIVACY_STATUSES,
default="public", help="Video privacy status.")
args = argparser.parse_args()
youtube = get_authenticated_service(args)
try:
initialize_upload(youtube, args)
except HttpError, e:
print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
Resumable Uploads Mechanism
For large video files or unreliable networks, the YouTube API supports resumable uploads. This protocol allows you to resume an upload after a network interruption without starting over, saving time and bandwidth. This is essential for:
- Large video files that take significant time to upload
- Mobile applications with unstable connections
- Automated systems that need reliable uploads
The resumable upload process follows a specific sequence of HTTP requests:
Step 1: Initiate a Resumable Session
Send a POST request to start the session. The part parameter specifies which resource properties you’re setting and which you want returned.
POST /upload/youtube/v3/videos?uploadType=resumable&part=snippet,status,contentDetails HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer AUTH_TOKEN
Content-Length: 278
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Length: 3000000
X-Upload-Content-Type: video/*
{
"snippet": {
"title": "My video title",
"description": "My video description",
"tags": ["cool", "video"],
"categoryId": 22
},
"status": {
"privacyStatus": "private"
}
}
Step 2: Save the Resumable Session URI
If successful, the API returns a 200 OK response with a Location header containing the unique upload URI:
HTTP/1.1 200 OK
Location: https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&upload_id=xa298sd_f&part=snippet,status,contentDetails
Content-Length: 0
Step 3: Upload the Video File
Send a PUT request to the URI from Step 2 with the binary video data:
PUT {UPLOAD_URL} HTTP/1.1
Authorization: Bearer AUTH_TOKEN
Content-Length: 3000000
Content-Type: video/*
[BINARY_FILE_DATA]
Step 4: Handle Interruptions
If the upload is interrupted, check the status by sending an empty PUT request with a special Content-Range header:
PUT {UPLOAD_URL} HTTP/1.1
Authorization: Bearer AUTH_TOKEN
Content-Length: 0
Content-Range: bytes */3000000
The API responds with 308 Resume Incomplete and a Range header indicating how many bytes were received:
308 Resume Incomplete
Content-Length: 0
Range: bytes=0-999999
Step 5: Resume the Upload
Resume by sending only the remaining bytes:
PUT {UPLOAD_URL} HTTP/1.1
Authorization: Bearer AUTH_TOKEN
Content-Length: 2000000
Content-Range: bytes 1000000-2999999/3000000
[REMAINING_BINARY_DATA]
Content-Range headers. Each intermediate chunk receives a 308 Resume Incomplete response until the final chunk completes with 201 Created.
API Authentication Requirements
The YouTube Data API has specific authentication requirements depending on the type of operation:
- Every request must specify an API key (via the
keyparameter) OR provide an OAuth 2.0 token. - Insert, update, and delete requests require an OAuth 2.0 authorization token.
- Requests for private user data (like private videos or watch history) require OAuth 2.0 authorization.
Your API key is available in the Google Cloud Console’s API Access pane for your project. For OAuth 2.0 flows, you’ll need to configure a client_secrets.json file with your application credentials.
How to Increase Your Quota
If the YouTube API Daily Limit of 6 videos per day is insufficient for your needs (which is common for agencies or platforms), you must apply for a Quota Extension via the Google Cloud Console. This process is not automatic and involves a compliance audit.
- Go to Google Cloud Console > IAM & Admin > Quotas.
- Locate the “YouTube Data API v3” service.
- Select the “Queries per day” quota.
- Click “Edit Quotas” and follow the instructions to request an increase.
Note that Google will audit your application to ensure it complies with the API Terms of Service, specifically regarding user data policy and privacy.
Best Practices for Managing the YouTube API Daily Limit
To avoid hitting the YouTube API Daily Limit, follow these technical best practices:
Cache Responses
Do not call videos.list repeatedly for static data. Store metadata locally to save 1 unit per call.
Avoid Polling
Instead of polling for updates (which consumes quota), set up Push Notifications (PubSub) to receive updates efficiently.
Use Partial Resources
Use the fields parameter to retrieve only the data you need. While this doesn’t reduce quota cost, it improves performance.
Handle Errors Gracefully
Implement exponential backoff logic for 5xx errors, but stop immediately upon receiving a 403 quotaExceeded.
Available API Resources
The YouTube Data API is organized by resource types. Each resource represents a type of item on YouTube (videos, playlists, channels, etc.) and supports specific methods. Understanding which methods contribute to the YouTube API Daily Limit is essential:
Videos
Core resource for uploading, listing, updating, deleting, and rating videos.
insert, list, update, delete, rate, getRating, reportAbuse
Playlists
Create and manage video collections. Includes special lists like uploads and favorites.
insert, list, update, delete
PlaylistItems
Add, remove, or reorder videos within a playlist.
insert, list, update, delete
Channels
Retrieve channel information and update branding settings.
list, update
Captions
Upload, download, update, and delete caption tracks for videos.
insert, list, update, delete, download
Comments / CommentThreads
Read, post, and moderate comments on videos and channels.
insert, list, update, delete, setModerationStatus
Subscriptions
Manage channel subscriptions for the authenticated user.
insert, list, delete
Thumbnails
Upload custom thumbnail images for videos.
set
Search
Search for videos, channels, and playlists. Costly at 100 units per call.
list
Members / MembershipsLevels
List channel members and membership pricing levels.
list
Watermarks
Set or remove watermark images that appear on channel videos.
set, unset
Activities
Retrieve activity feeds showing uploads, likes, shares, etc.
list
MadeForKids Compliance (COPPA)
When working with content designated as “MadeForKids” (MFK), special care is required. YouTube labels content specifically directed towards children, and interactions with this content have legal implications under the U.S. Children’s Online Privacy Protection Act (COPPA).
If you embed a YouTube video designated MadeForKids on your site or app, you are required by Section III.E.4.j of the Developer Policies to:
- Turn off tracking for that player
- Ensure all data collection is compliant with COPPA and other applicable laws
Checking MadeForKids Status via API
You can check the MadeForKids status of any video at any time via the YouTube Data API by querying the video resource:
GET https://www.googleapis.com/youtube/v3/videos?part=status&id={VIDEO_ID}&key={API_KEY}
The response will include the status.madeForKids property:
{
"kind": "youtube#videoListResponse",
"items": [{
"id": "VIDEO_ID",
"status": {
"madeForKids": true,
"selfDeclaredMadeForKids": true
}
}]
}
# Python: Check MadeForKids status
import requests
API_KEY = "YOUR_API_KEY"
VIDEO_ID = "dQw4w9WgXcQ"
url = f"https://www.googleapis.com/youtube/v3/videos"
params = {
"part": "status",
"id": VIDEO_ID,
"key": API_KEY
}
response = requests.get(url, params=params)
data = response.json()
if data.get("items"):
video = data["items"][0]
made_for_kids = video.get("status", {}).get("madeForKids", False)
if made_for_kids:
print(f"Video {VIDEO_ID} is designated MadeForKids - COPPA applies")
# Disable tracking, personalized ads, etc.
else:
print(f"Video {VIDEO_ID} is NOT designated MadeForKids")
else:
print("Video not found")
Additional Code Examples
List Videos from a Channel
Retrieve videos from a specific channel. This is a common operation that costs only 1-2 units per call:
# Python: List videos from a channel
import requests
API_KEY = "YOUR_API_KEY"
CHANNEL_ID = "UCxxxxxxxxxxxxxx"
# First, get the uploads playlist ID
url = "https://www.googleapis.com/youtube/v3/channels"
params = {
"part": "contentDetails",
"id": CHANNEL_ID,
"key": API_KEY
}
response = requests.get(url, params=params)
channel_data = response.json()
uploads_playlist_id = channel_data["items"][0]["contentDetails"]["relatedPlaylists"]["uploads"]
# Then, get videos from the uploads playlist
url = "https://www.googleapis.com/youtube/v3/playlistItems"
params = {
"part": "snippet",
"playlistId": uploads_playlist_id,
"maxResults": 50,
"key": API_KEY
}
response = requests.get(url, params=params)
videos = response.json()
for item in videos.get("items", []):
video_id = item["snippet"]["resourceId"]["videoId"]
title = item["snippet"]["title"]
print(f"{video_id}: {title}")
Update Video Metadata
Update the title, description, or tags of an existing video. Costs 50 units:
# Python: Update video metadata (requires OAuth 2.0)
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
# Assumes you have valid OAuth credentials
credentials = Credentials.from_authorized_user_file('token.json')
youtube = build('youtube', 'v3', credentials=credentials)
VIDEO_ID = "your_video_id"
# First, get the current video details
video_response = youtube.videos().list(
part="snippet",
id=VIDEO_ID
).execute()
if video_response["items"]:
video = video_response["items"][0]
snippet = video["snippet"]
# Update the metadata
snippet["title"] = "Updated Video Title"
snippet["description"] = "This is the updated description."
snippet["tags"] = ["updated", "tags", "here"]
# Push the update
update_response = youtube.videos().update(
part="snippet",
body={
"id": VIDEO_ID,
"snippet": snippet
}
).execute()
print(f"Updated video: {update_response['snippet']['title']}")
Set Custom Thumbnail
Upload a custom thumbnail for a video. Costs 50 units:
# Python: Upload custom thumbnail (requires OAuth 2.0)
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from google.oauth2.credentials import Credentials
credentials = Credentials.from_authorized_user_file('token.json')
youtube = build('youtube', 'v3', credentials=credentials)
VIDEO_ID = "your_video_id"
THUMBNAIL_FILE = "thumbnail.jpg" # Must be JPEG, PNG, GIF, BMP, or WebP
# Upload the thumbnail
request = youtube.thumbnails().set(
videoId=VIDEO_ID,
media_body=MediaFileUpload(THUMBNAIL_FILE, mimetype='image/jpeg')
)
response = request.execute()
print(f"Thumbnail set: {response['items'][0]['default']['url']}")
Add Video to Playlist
Add a video to an existing playlist. Costs 50 units:
# Python: Add video to playlist (requires OAuth 2.0)
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
credentials = Credentials.from_authorized_user_file('token.json')
youtube = build('youtube', 'v3', credentials=credentials)
PLAYLIST_ID = "PLxxxxxxxxxxxxxx"
VIDEO_ID = "video_id_to_add"
request = youtube.playlistItems().insert(
part="snippet",
body={
"snippet": {
"playlistId": PLAYLIST_ID,
"resourceId": {
"kind": "youtube#video",
"videoId": VIDEO_ID
}
}
}
)
response = request.execute()
print(f"Added to playlist at position {response['snippet']['position']}")
Comparison: YouTube vs Instagram vs TikTok
Frequently Asked Questions About the YouTube API Daily Limit
Common Questions About YouTube API Quotas
Why is my upload limit so low?
The default quota is meant for development and small-scale use. Uploading video requires significant server resources, hence the high “cost” of 1,600 points per upload. You can increase this by submitting a quota increase request and verifying your app with Google.
Does deleting a video return my quota?
No. Deleting a video actually costs an additional 50 units. All API actions (Create, Read, Update, Delete) consume quota units that do not replenish until the next daily reset.
Can I just use multiple API keys?
Trying to bypass quotas by creating multiple projects or API keys for the same application is a violation of the YouTube API Terms of Service and can result in your application being permanently banned.
What happens when I paginate through search results?
Each page of results costs the full 100 units. If you paginate through 10 pages of search results, you will consume 1,000 units total. This is why caching and limiting pagination is critical.
How expensive are caption operations?
Caption operations are costly: listing captions costs 50 units, inserting a new caption costs 400 units, and updating an existing caption costs 450 units. Plan your caption workflow carefully.
Do invalid requests still consume quota?
Yes. According to Google’s documentation, all API requests including invalid ones incur a quota cost of at least one point. This means malformed requests or authentication failures still count against your daily limit.
Automate Within Limits Using Repostit
Managing the strict YouTube API Daily Limit of 6 videos typically requires complex logic and careful scheduling. Repostit handles this complexity for you.
Automate Your YouTube Uploads Safely
Let Repostit manage your content distribution within the YouTube Data API Quota Limit while maximizing your reach across all platforms.
✓ Smart quota tracking ✓ Resumable uploads ✓ Cross-platform scheduling
Conclusion

The YouTube API Daily Limit is one of the most restrictive social API limits for new applications, effectively capping uploads at roughly 6 videos per day. Understanding the unit-cost model is essential for any developer integrating with YouTube. By optimizing your calls, using caching strategies, and requesting quota increases when necessary, you can build robust applications that scale alongside your channel’s growth.