Google's default for a project that enables the YouTube Data API is 100 search.list calls a day. Each call costs 1 unit in its own search bucket, returns up to 50 results, and counts again for every extra page. We read Google's documentation on 2026-10-16.
What Google's pages say the quota is
Google's quota pages (last updated 2026-10-15) say: "Projects that enable the YouTube Data API have a default quota allocation of 100 search.list calls, 100 videos.insert calls, and 10,000 units per day combined for all other endpoints." The search.list reference adds: "Quota impact: 100 calls per day. A call to this method has a quota cost of 1 unit in the Search Queries quota bucket."
Two rules change the arithmetic:
- Pages count. "If your application calls a method, such as search.list, that returns multiple pages of results, each request to retrieve an additional page of results incurs the estimated quota cost."
- Invalid requests count. "All API requests, including invalid requests, incur a quota cost of at least one point."
The guides we read for this query on 2026-10-16 all still teach the older model, 100 units a search out of one 10,000-unit pool, and none mentions the June 2026 change. Google's revision history dates that cost to November 11, 2014 ("The quota cost for a call to the search.list method has changed to 100 units") and the bucket change to June 1, 2026: "API calls to the videos.insert and search.list methods will be charged to their own respective quota buckets." The daily count is the same, 100, but the 10,000 units no longer pay for searches.
Page size, filters and Shorts
maxResults takes 0 to 50 and defaults to 5. Google warns that "The API may return fewer items than the requested maxResults per page due to internal sorting or filtering, even if additional results are available", so follow nextPageToken.
Filters include type (video, channel or playlist), publishedAfter, publishedBefore, order, regionCode and videoDuration. There is no Shorts parameter. videoDuration=short means "Only include videos that are less than four minutes long", which is not the same set. For a channel's latest uploads Google says "do not use search.list" and points to playlistItems.list.
How to get more quota, and what you may store
The pages we read describe no way to buy quota and print no per-call price. The route is: "If you would like to request additional quota beyond the default allocation, you must first complete an audit to show that your project is in compliance with the YouTube API Services Terms of Service." You start the audit by submitting the Audit and Quota Extension Form; if you passed an audit in the last 12 months, the same form requests more quota. Google gives no review time.
Storage is limited. Google's developer policies say: "API Clients may temporarily store limited amounts of Non-Authorized Data for as long as is necessary for the purposes of the API Client but not longer than 30 calendar days." Non-Authorized Data is "API Data accessible by an API Client without User Credentials", which is what a search with an API key returns. After 30 days you delete or refresh it.
Search YouTube with ToolzerHub
We make ToolzerHub. Our YouTube API returns public YouTube search results as JSON with one API key and no Google Cloud project. GET /v2/youtube/search costs 1 credit per call (our OpenAPI file, 2026-10-16). This script runs several searches, pages each one, and writes the videos to CSV. Pass shorts instead of video to get Shorts only.
import csv
import os
import sys
import time
import requests
URL = "https://api.toolzerhub.com/v2/youtube/search"
HEADERS = {"x-api-key": os.environ.get("TOOLZERHUB_API_KEY", "")}
FIELDS = ["query", "video_id", "title", "channel", "handle", "views", "published", "length", "url"]
calls = 0
def cell(value):
# Spreadsheets run text that starts with = + - or @ as a formula; an apostrophe keeps it text.
if isinstance(value, str) and value[:1] in ("=", "+", "-", "@", "\t", "\r"):
return "'" + value
return value
def get(params, tries=5):
# 429 and 503 are retryable; the error body may say how long to wait.
global calls
for attempt in range(tries):
r = requests.get(URL, headers=HEADERS, params=params, timeout=90)
calls += 1
if r.status_code == 400: # bad parameter: skip this query, keep the rest of the run
print("bad request:", r.json()["error"]["message"].splitlines()[0])
return None
if r.status_code not in (429, 503) or attempt == tries - 1:
r.raise_for_status()
return r.json().get("data") # None when there is nothing to return
try:
wait = r.json()["error"]["details"]["retryAfter"]
except (ValueError, KeyError, TypeError):
wait = 5 * (attempt + 1)
time.sleep(min(wait, 60))
def videos(entries):
# Shelves such as the Shorts row hold their items one level down; ads are skipped.
for e in entries:
if e.get("type") in ("video", "shorts"):
yield e
elif isinstance(e.get("data"), list):
yield from videos(e["data"])
def row(query, v):
return {
"query": query,
"video_id": v["videoId"],
"title": (v.get("title") or "").replace("\n", " "),
"channel": v.get("channelTitle"),
"handle": v.get("channelHandle"),
"views": v.get("viewCount"),
"published": (v.get("publishedAt") or "")[:10],
"length": v.get("lengthText"),
"url": f"https://www.youtube.com/watch?v={v['videoId']}",
}
def main(queries, pages="3", kind="video", out="youtube_search.csv"):
seen = set()
with open(out, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=FIELDS)
writer.writeheader()
for query in [q.strip() for q in queries.split(",") if q.strip()]:
params = {"search_term": query, "result_kind": kind}
for _ in range(int(pages)):
data = get(params)
if not data or not data.get("data"):
break
for v in videos(data["data"]):
if v["videoId"] not in seen: # pages can overlap
seen.add(v["videoId"])
writer.writerow({k: cell(x) for k, x in row(query, v).items()})
if not data.get("page_cursor"):
break
params["page_cursor"] = data["page_cursor"]
print(f"wrote {len(seen)} videos to {out} in {calls} calls")
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.exit('usage: python youtube_search.py "python tutorial,lofi music" [pages_per_query] [video|shorts] [file.csv]')
if not HEADERS["x-api-key"]:
sys.exit("set TOOLZERHUB_API_KEY first")
main(*sys.argv[1:])
A 200 response with {"data": null} ends that query, a 400 is skipped with a message, and 429 and 503 are retried. cell() puts an apostrophe in front of text that starts with =, +, - or @, so a spreadsheet shows it as text; that is why handles start with '@.
Run the script
export TOOLZERHUB_API_KEY=your_key
python youtube_search.py "python tutorial, nasa artemis ,lofi music,,how to tie a tie" 3 video youtube_search.csv
Output on 2026-10-16, with a stray space and an empty item added to test the stripping:
wrote 239 videos to youtube_search.csv in 12 calls
It took 2 seconds: 239 videos from 112 distinct channel handles, median 1,297,907 views. One video matched two queries and was written once. A run with shorts on "python tutorial" wrote 46 Shorts in 2 calls.
What we measured
On 2026-10-16 we ran 10 searches ("python tutorial", "nasa artemis", "lofi music", "how to tie a tie" and six more). All 10 returned data in 0.1 to 1.1 seconds, 20 to 23 items on the first page.
- A page holds about 20 videos. The default mix adds playlists, courses, channels, a Shorts row and sometimes an ad;
result_kind=videoreturns videos only. - Paging has an end. "nasa artemis" ended after 31 calls with 588 videos, and "how to tie a tie" after 29 calls with 517 unique videos (533 returned, 16 repeats). Paged to the end later that day, "sourdough bread" gave 582 unique videos and "python tutorial" 593, each in 31 calls.
- Filters that worked:
result_kind(video, shorts, channel, playlist),published_within(today, week, month, year),length_filter(under 3 minutes, 3 to 20, over 20),sort_order(relevance, popularity),region_code,language_code. result_kind=shortsreturned only Shorts, all 60 seconds or shorter.result_kind=videonever returned a Shorts item, but short clips still appear as videos: 3 of 60 for "nasa artemis" were 46 to 60 seconds. ChecklengthTextif you need a hard cut.- Search results carry
viewCountbut no like count; likes come from/v2/youtube/video, 1 credit per call.publishedAtlooks derived from text like "2 years ago": older videos get the right year and an approximate day.
Google's default quota and ours, side by side
| Google default | ToolzerHub | |
|---|---|---|
| Free allowance | 100 search calls a day | 100 credits a month |
| Results per call | Up to 50 | About 20 |
| Free results | Up to 5,000 a day | About 2,000 a month |
| 1,000 calls a day | Needs an audit | 1,000 credits a day |
A job of 20 queries with 5 pages each is 100 calls. On Google that is the whole day's quota and up to 5,000 results. On ours it is 100 credits, about 2,000 results, 10 to 19 cents at $0.99 to $1.90 per 1,000 credits. One query paged to its end is about 30 credits: 3 to 6 cents. A run of 1,000 calls a day is 30,000 credits a month, which fits the $79 plan (60,000 credits). On Google it needs the audit and extension request first.
Where Google's API is the better pick
Google's default allowance is far larger than our free tier: about 3,000 search calls in a 30-day month against 100 credits. Its API is official, stable and documented. Use it for uploads, your own channel, captions you own, analytics and anything that needs your users' sign-in, and for under 100 searches a day. Use ours when you need more searches a day than the default before an audit, or a Shorts-only search.
We are not affiliated with Google or YouTube. For transcripts see our YouTube transcript API guide; for another API that moved to per-use pricing, what X charges.
Sources
- Google, YouTube Data API: Search.list reference (last updated 2026-10-15), https://developers.google.com/youtube/v3/docs/search/list, read 2026-10-16
- Google, YouTube Data API: Quota costs for API requests (last updated 2026-10-15), https://developers.google.com/youtube/v3/determine_quota_cost, read 2026-10-16
- Google, YouTube Data API: Quota and Compliance Audits (last updated 2026-10-15), https://developers.google.com/youtube/v3/guides/quota_and_compliance_audits, read 2026-10-16
- Google, YouTube Data API: Overview (Getting started), https://developers.google.com/youtube/v3/getting-started, read 2026-10-16
- Google, YouTube Data API: Revision history, https://developers.google.com/youtube/v3/revision_history, read 2026-10-16
- Google, YouTube API Services Developer Policies (last updated 2026-10-15), https://developers.google.com/youtube/terms/developer-policies, read 2026-10-16
- ToolzerHub YouTube reference, https://api.toolzerhub.com/openapi.json, checked 2026-10-16
- ToolzerHub pricing, https://toolzerhub.com/pricing, checked 2026-10-16