How to export YouTube comments for every video on a topic
Find the videos with YouTube video search, then page through YouTube video comments under each one. The worked example is 9 calls and costs $0.02; a failed call is not charged.
Updated
The job: you sell a product, or plan to, and the review videos about it carry thousands of comments from buyers and doubters. Search for the videos people actually watch, then read the comments under each one into a single sheet. You end with one CSV where each row is a comment with its video, text, author, likes, reply count and date, ready for tagging by hand or for a model to group into complaints and praise.
No Google Cloud project, API key or quota request is involved. Each call is an HTTPS request with your key.
Step by step
Step 1: find the videos
Call YouTube video search with query and sort: relevance (the default), latest or most_viewed. One call returns about 20 videos for $0.004, each with id, title, url, the channel in author and metrics.views. Search leaves metrics.comments null, so choose videos by views.
curl -G "https://api.okdata.online/v1/youtube/videos/search" \
-H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'query=robot vacuum review' \
-d sort=most_viewed \
-d fields=id,title,author.name,metrics.views
Step 2: page through the comments
Pass a video's id to YouTube video comments. sort takes top (the default, YouTube's Top comments order) or latest (newest first). Use top to read what most viewers saw, latest to follow a video that is still collecting comments.
One call returns about 20 comments for $0.002. Each has id, text, author (name and username, the handle), likes, replies (how many replies sit under it) and published_at. For the next page, send page.next_cursor back as cursor, unchanged; stop when page.has_more is false.
curl -G "https://api.okdata.online/v1/youtube/videos/comments/list" \
-H "Authorization: Bearer $OKDATA_API_KEY" \
-d id=h4Lw0pZk3sE -d sort=top
Step 3: put it together in Python
The script keeps the four most viewed videos and reads MAX_PAGES pages under each. Every page is its own call, so the page cap is also your spending cap.
import csv
import os
import requests
API = "https://api.okdata.online"
HEADERS = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}
VIDEOS = 4
MAX_PAGES = 2 # comment pages per video; each page is one call
def get(path, **params):
body = requests.get(API + path, headers=HEADERS, params=params, timeout=60).json()
if body["code"] != "ok":
raise RuntimeError(f"{body['code']}: {body['message']} (charged: {body['charged']})")
return body
found = get("/v1/youtube/videos/search", query="robot vacuum review", sort="most_viewed")["data"]["items"]
videos = sorted(found, key=lambda v: v["metrics"]["views"] or 0, reverse=True)[:VIDEOS]
with open("youtube_comments.csv", "w", newline="", encoding="utf-8-sig") as f:
out = csv.writer(f)
out.writerow(["video_id", "video_title", "comment_id", "author", "likes", "replies", "published_at", "text"])
for v in videos:
cursor = None
for _ in range(MAX_PAGES):
body = get("/v1/youtube/videos/comments/list", id=v["id"], sort="top", **({"cursor": cursor} if cursor else {}))
for c in body["data"]["items"]:
out.writerow([v["id"], v["title"], c["id"], c["author"]["name"], c["likes"], c["replies"], c["published_at"], c["text"]])
if not body["page"]["has_more"]:
break
cursor = body["page"]["next_cursor"]
utf-8-sig writes a byte-order mark so Excel shows emoji and non-English text correctly. To go deeper, raise MAX_PAGES: ten pages under each of the four videos is 40 comment calls, $0.08 on top of the search.
Good to know
- Top-level comments only. You get each comment's reply count, not the replies themselves;
parent_idis always null here. - Dates are approximate.
published_atis worked out from labels such as "2 months ago", so older comments carry a rounded date. - No commenter location. YouTube does not show it, so
ip_locationis null and named inmeta.unavailable. - Removed videos are free. A video that no longer exists returns
not_foundand costs nothing. - The official quota. Google's quota calculator gives a new project 100
search.listcalls a day in their own bucket and 10,000 units a day for the other methods, reset at midnight Pacific time. commentThreads.list costs 1 unit and returns up to 100 threads per call. If you already have a Google project and mostly read comments, the official API is the cheaper choice; the search quota is where a topic-wide job usually runs out first. - Retries without paying twice. Send an
Idempotency-Keyheader with each call. The same request with the same key within 24 hours returns the stored answer withmeta.replayed: trueand no new charge.
For a single video's comments in a spreadsheet, see export YouTube comments to CSV. When the daily search limit is the problem, see the YouTube search quota answer.
What the example costs
One page of the most viewed robot vacuum review videos, then two pages of top comments under each of the four most viewed
| Endpoint | Calls | Price | Subtotal |
|---|---|---|---|
| YouTube video search | 1 | $0.004 | $0.004 |
| YouTube video comments | 8 | $0.002 | $0.016 |
| Total | 9 | $0.02 |
Prices in force when this page was built. A failed call costs nothing.
In your AI (MCP)
Connect the MCP server once, then say what you want. The agent finds these endpoints, reads their prices and calls them on your balance.
SaySearch YouTube for robot vacuum review, most viewed first. Take the four most viewed videos, get two pages of top comments under each, and give me one table: video, comment, author, likes, replies, date. Then list the complaints that come up more than once.
What the agent sends to the call tool first
{
"endpoint": "youtube.videos.search",
"params": {
"query": "claude code tutorial"
},
"idempotency_key": "<a new UUID>"
}