YouTube comments contain product feedback, audience sentiment, and content ideas that are difficult to extract at scale. The official YouTube Data API has tight quota limits and requires OAuth setup for most comment operations. The Scavio API provides a simpler path: POST with a video ID and receive structured comment data including author, text, like count, reply count, and publish date. This tutorial builds a reusable Python script that fetches all available comments for a video and writes them to a CSV file suitable for analysis in spreadsheets or pandas.
Prerequisites
- Python 3.8 or higher installed
- requests library installed
- A Scavio API key from scavio.dev
- A YouTube video ID to test with
Walkthrough
Step 1: Fetch comments for a video
POST to the Scavio endpoint with the YouTube platform and the video ID. The response includes a comments array with structured data for each comment.
import os
import requests
API_KEY = os.environ.get("SCAVIO_API_KEY", "your_scavio_api_key")
def fetch_comments(video_id: str) -> list[dict]:
r = requests.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": API_KEY},
json={"platform": "youtube", "action": "comments", "video_id": video_id}
)
r.raise_for_status()
return r.json().get("comments", [])Step 2: Normalize and clean comment data
Extract the fields you need from each comment object. Strip newlines from comment text to avoid breaking CSV rows.
def normalize_comment(comment: dict) -> dict:
return {
"author": comment.get("author", ""),
"text": comment.get("text", "").replace("\n", " ").strip(),
"likes": comment.get("likes", 0),
"replies": comment.get("reply_count", 0),
"date": comment.get("published_at", "")
}Step 3: Write comments to CSV
Use csv.DictWriter to output the normalized comments. Include a header row with column names.
import csv
def write_csv(comments: list[dict], output: str) -> None:
fields = ["author", "text", "likes", "replies", "date"]
with open(output, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fields)
writer.writeheader()
writer.writerows(comments)
print(f"Wrote {len(comments)} comments to {output}")Step 4: Run the full export pipeline
Chain the functions together. Accept a video ID as input, fetch, normalize, and export.
video_id = "dQw4w9WgXcQ"
raw = fetch_comments(video_id)
normalized = [normalize_comment(c) for c in raw]
write_csv(normalized, f"comments_{video_id}.csv")
print(f"Exported {len(normalized)} comments for video {video_id}")Python Example
import os
import csv
import requests
API_KEY = os.environ.get("SCAVIO_API_KEY", "your_scavio_api_key")
ENDPOINT = "https://api.scavio.dev/api/v1/search"
def fetch_comments(video_id: str) -> list[dict]:
r = requests.post(
ENDPOINT,
headers={"x-api-key": API_KEY},
json={"platform": "youtube", "action": "comments", "video_id": video_id}
)
r.raise_for_status()
return r.json().get("comments", [])
def normalize(comment: dict) -> dict:
return {
"author": comment.get("author", ""),
"text": comment.get("text", "").replace("\n", " ").strip(),
"likes": comment.get("likes", 0),
"replies": comment.get("reply_count", 0),
"date": comment.get("published_at", "")
}
def export_to_csv(video_id: str, output: str = "") -> None:
if not output:
output = f"comments_{video_id}.csv"
raw = fetch_comments(video_id)
comments = [normalize(c) for c in raw]
fields = ["author", "text", "likes", "replies", "date"]
with open(output, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fields)
writer.writeheader()
writer.writerows(comments)
print(f"Exported {len(comments)} comments to {output}")
if __name__ == "__main__":
export_to_csv("dQw4w9WgXcQ")JavaScript Example
const fs = require("fs");
const API_KEY = process.env.SCAVIO_API_KEY || "your_scavio_api_key";
const ENDPOINT = "https://api.scavio.dev/api/v1/search";
async function fetchComments(videoId) {
const res = await fetch(ENDPOINT, {
method: "POST",
headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ platform: "youtube", action: "comments", video_id: videoId })
});
const data = await res.json();
return data.comments || [];
}
async function exportToCsv(videoId) {
const raw = await fetchComments(videoId);
const header = "author,text,likes,replies,date";
const rows = raw.map(c => {
const text = (c.text || "").replace(/[\n\r]/g, " ").replace(/"/g, '""');
return `"${c.author || ""}","${text}",${c.likes || 0},${c.reply_count || 0},"${c.published_at || ""}"`;
});
fs.writeFileSync(`comments_${videoId}.csv`, [header, ...rows].join("\n"));
console.log(`Exported ${raw.length} comments`);
}
exportToCsv("dQw4w9WgXcQ").catch(console.error);Expected Output
{
"video_id": "dQw4w9WgXcQ",
"comments": [
{
"author": "MusicFan2026",
"text": "This song will never get old.",
"likes": 42,
"reply_count": 3,
"published_at": "2026-01-15T08:30:00Z"
},
{
"author": "RetroVibes",
"text": "Still the greatest rickroll of all time.",
"likes": 18,
"reply_count": 1,
"published_at": "2026-02-20T14:12:00Z"
}
]
}