YouTube, no quota
A YouTube Data API alternative for when 100 searches a day is not enough
The official YouTube Data API gives each project 100 search.list calls a day in their own quota bucket, plus 10,000 units a day for its other endpoints. Every page of search results is another call, so about 100 searches a day is the ceiling before you have to apply for more. This Actor reads the same public pages any visitor sees, so there is no key to create and no daily quota to track. You pay $2 per 1,000 videos instead.
- $2 per 1,000 videos
- No API key
- No daily quota
- Comments and dislike estimates included
The quota math
| API call | Default allowance | Calls per day |
|---|---|---|
search.list (up to 50 results per page) | Its own bucket: 100 calls a day | 100, and each extra page of results is one more call |
videos.list (up to 50 IDs per call) | 1 unit of the 10,000 | up to 10,000 |
commentThreads.list | 1 unit of the 10,000 | up to 10,000 |
channels.list, playlistItems.list | 1 unit of the 10,000 | up to 10,000 |
Search is the bottleneck. Anything built around discovery hits the wall first: keyword monitoring, trend research, lead lists, and AI agents that search whenever a user asks a question. To get more, Google asks for a compliance audit first: you fill in the YouTube API Services Audit and Quota Extension Form, and a member of the API team contacts you (Google's Quota and Compliance Audits guide). Plan for a review, not an instant upgrade.
When you should stay on the official API
The official API is free, documented and backed by Google. Stay on it if:
- your volume fits inside the quota,
- you need data only the owner can see, such as your channel's analytics or your own private and unlisted videos,
- you need to write: upload, comment, manage playlists,
- or your contract or compliance team requires first-party data access.
This Actor only reads public data, and we can't promise Google's stability: when YouTube changes its pages, we have to adapt the Actor.
How your API calls map to this Actor
| What you did with the API | What to do here |
|---|---|
search.list with q, order, publishedAfter | searchTerms with sortBy (relevance, date, views, rating) and dateFilter (hour, today, week, month, year) |
channels.list + playlistItems.list for uploads | channels: a plain name like "Fireship", an @handle or a channel URL |
playlistItems.list | startUrls with the playlist link |
videos.list for statistics | startUrls with the video links |
commentThreads.list | maxComments on any of the above |
Two differences to note: the search upload-date filter works in YouTube's own buckets (last hour, today, this week, month or year) rather than arbitrary dates, and search filters apply to search terms only. For channels, publishedAfter takes an exact date or an age such as 30 days, and older videos are skipped without charge.
What it costs at volume
- A daily keyword monitor with 200 searches of 25 videos each is 5,000 rows, or $10 a day. On the official API, 200 searches a day is twice the default
search.listallowance. - A weekly competitor report on 50 channels, 30 latest videos each, with 10 top comments per video, is 1,500 rows, or $3 a week.
- An agent that searches 20 videos per question costs $0.04 per question.
Inputs that return nothing are not charged. An empty or over-filtered search (NO_RESULTS, DATE_FILTER_TOO_STRICT), an unknown channel or playlist, and an unavailable, private or deleted video go into the run's ERRORS record with the reason, and the status message counts them. If your pipeline reads those cases from the dataset, turn on errorRowsInDataset: they come back as dataset rows with an error field, as in older versions, and each one is then billed as a result.
Differences to plan for
- Field names. You get flat rows (
viewCount,likes,numberOfSubscribers,publishedAtas YYYY-MM-DD), not the API'ssnippetandstatisticsobjects.publishedAtis null when YouTube shows only a relative date;datekeeps the text YouTube displays. - Shorts. Off by default; turn on
includeShortsfor search. Shorts have no duration, and YouTube drops the Shorts shelf when a date filter or non-default sort is applied. For Shorts from channels, Shorts-only search or a list of Shorts links, with length and music, see the YouTube Shorts scraper. - Channel About data. Turn on
includeChannelAboutand every row also carries the channel's country, joined date, total views, links and social links, at no extra charge. - Subtitles. With
includeSubtitleson, the available subtitle languages are listed (best-effort); subtitle text is not reliable, so don't build on it. - Snapshots. Counts are what YouTube shows at run time.
- Dislikes are estimates. With
includeDislikes, thedislikesfield comes from Return YouTube Dislike, since the API itself no longer returns dislike counts publicly.
For AI agents and data pipelines
Agents are where the quota hurts most, because they search on demand. Point your agent at the Actor through Apify's MCP server and each user signs in with their own Apify account, so there's no shared key to leak or exhaust. The ChatGPT, Claude and Cursor guide has the pinned URLs.
Run it from code
The month's 50 most-viewed videos for a search term: 50 rows, $0.10.
// Save as run.mjs, then: npm i apify-client && APIFY_TOKEN=... node run.mjs
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yugenox/youtube-scraper').call({
searchTerms: [
"home espresso machine"
],
dateFilter: "month",
sortBy: "views",
maxItems: 50
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) console.log(item.title, item.viewCount, item.publishedAt);import os
from apify_client import ApifyClient # pip install apify-client
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yugenox/youtube-scraper").call(run_input={
"searchTerms": ["home espresso machine"],
"dateFilter": "month",
"sortBy": "views",
"maxItems": 50,
})
if run is None:
raise RuntimeError("Run did not finish")
for item in client.dataset(run.default_dataset_id).iterate_items():
print(item.get("title"), item.get("viewCount"), item.get("publishedAt"))# Small jobs: runs the Actor and returns the rows in one call (up to 5 minutes).
curl -X POST "https://api.apify.com/v2/acts/yugenox~youtube-scraper/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"searchTerms":["home espresso machine"],"dateFilter":"month","sortBy":"views","maxItems":50}'Questions people ask
Do I need a Google Cloud project or YouTube API key?
No. There is nothing to create or rotate. You need an Apify account to run the Actor, and that account is billed per result.
Is there any daily limit?
No daily quota. A channel or playlist can return thousands of videos (maxItems goes up to 20,000). A plain search term returns about 40 videos unless you turn on deepSearch, which keeps paging toward maxItems. Very large runs can vary with YouTube.
How fresh is the data?
Live. Each run reads YouTube at that moment, so view and like counts are current as of the run.
Is it legal to use this instead of the official API?
The Actor only collects public data that anyone can see without signing in, which is generally legal. You are responsible for how you use it, including privacy laws and YouTube's terms. Ask a lawyer if you are unsure.
What happens when YouTube changes something?
We update the Actor. If a run looks wrong, open an issue on the Issues tab with the run link.
Run it on your own data
Open the Actor on Apify, paste your input and press Start. You pay per result from your own Apify account, with no subscription to us. Or connect it to your AI assistant and ask in plain English.
Last updated 2026-10-06.