How to Export YouTube Comments to CSV Easily?
Need YouTube comment export automation? Learn how this Tampermonkey script helps with data extraction and CSV exporting fast.
Export YouTube Comments to CSV with a Simple Tampermonkey Script
Managing YouTube research manually takes time. This lightweight Tampermonkey script helps automate comment collection directly from the YouTube homepage and video feed.
The script scans videos automatically, extracts recent comments, captures author names and “time ago” values, then lets you export everything into CSV format with one click. It is useful for content research, audience analysis, lead generation research, trend monitoring, and social media data extraction workflows.
Unlike heavy browser extensions, this userscript keeps the interface clean with a floating dashboard and quick export buttons inside each video card. It also works well for creators, marketers, and developers working in web scraping, browser automation, and data extraction projects.
Features
- Auto-fetch YouTube comments
- Export comments into CSV
- Track comment timestamps
- Lightweight sidebar preview
- Bulk export support
- Simple Tampermonkey setup
- Useful for web automation workflows
This type of browser automation can save hours when collecting public engagement data for analysis or content research.
// ==UserScript==
// @name YouTube Comments Previewer (With Time & Export)
// @namespace http://tampermonkey.net/
// @version 2025-01-19
// @description Sidebar comment preview with "time ago" and CSV Export
// @author You
// @match https://www.youtube.com/*
// @require https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.4.1/papaparse.min.js
// @grant unsafeWindow
// @grant window.onurlchange
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
window.trustedTypes.createPolicy('default', {createHTML: (string, sink) => string})
let allFetchedData = [];
let processedIds = new Set();
const style = document.createElement('style');
style.textContent = `
.comment-sidebar {
background: #1a1a1a;
color: #efefef;
border-radius: 10px;
padding: 12px;
margin-top: 10px;
font-size: 12px;
max-height: 220px;
overflow-y: auto;
border: 1px solid #333;
display: flex;
flex-direction: column;
gap: 8px;
width: 90%;
box-shadow: inset 0 0 10px rgba(0,0,0,0.5);
}
.comment-item {
border-bottom: 1px solid #2a2a2a;
padding-bottom: 8px;
line-height: 1.4;
}
.comment-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 3px;
}
.comment-author {
color: #3ea6ff;
font-weight: bold;
font-size: 11px;
text-decoration: none;
}
.comment-time {
color: #aaa;
font-size: 10px;
font-style: italic;
}
.export-btn-mini {
background: #cc0000;
color: #fff;
border: none;
padding: 5px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 10px;
width: fit-content;
margin-top: 5px;
font-weight: bold;
}
.export-btn-mini:hover { background: #ff0000; }
.dashboard-container {
position: fixed;
bottom: 25px;
right: 25px;
z-index: 10000;
display: flex;
flex-direction: column;
gap: 10px;
}
.dashboard-btn {
color: white;
border: none;
padding: 12px 20px;
border-radius: 30px;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
font-weight: bold;
font-family: sans-serif;
transition: transform 0.2s;
}
.dashboard-btn:active { transform: scale(0.95); }
.btn-export { background: #28a745; }
.btn-clear { background: #555; font-size: 11px; padding: 8px 15px; }
`;
document.head.appendChild(style);
function downloadCSV(data, filename) {
if (!data || data.length === 0) {
alert("No data collected yet!");
return;
}
const csv = Papa.unparse(data);
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.setAttribute("download", filename);
link.click();
}
async function fetchComments(videoId) {
const apiKey = unsafeWindow.ytcfg?.get("INNERTUBE_API_KEY");
const clientVersion = "2.20240904.00.00";
if (!apiKey) return [];
try {
let r1 = await fetch(`https://www.youtube.com/youtubei/v1/next?key=${apiKey}`, {
method: "POST",
body: JSON.stringify({ context: { client: { clientName: "WEB", clientVersion } }, videoId })
});
let d1 = await r1.json();
const token = d1?.contents?.twoColumnWatchNextResults?.results?.results?.contents
?.find(c => c.itemSectionRenderer)?.itemSectionRenderer?.contents?.[0]
?.continuationItemRenderer?.continuationEndpoint?.continuationCommand?.token;
if (!token) return [];
let r2 = await fetch(`https://www.youtube.com/youtubei/v1/next?key=${apiKey}`, {
method: "POST",
body: JSON.stringify({ context: { client: { clientName: "WEB", clientVersion } }, continuation: token })
});
let d2 = await r2.json();
const mutations = d2.frameworkUpdates?.entityBatchUpdate?.mutations || [];
return mutations
.filter(m => m.payload?.commentEntityPayload)
.map(m => {
const props = m.payload.commentEntityPayload.properties;
return {
videoId: videoId,
author: props.authorButtonA11y || "Anonymous",
content: props.content?.content || "",
timeAgo: props.publishedTime || "just now" // Captures "2 days ago"
};
});
} catch (e) {
return [];
}
}
function injectDashboard() {
if (document.getElementById('comment-dashboard')) return;
const container = document.createElement('div');
container.id = 'comment-dashboard';
container.className = 'dashboard-container';
const clearBtn = document.createElement('button');
clearBtn.className = 'dashboard-btn btn-clear';
clearBtn.textContent = 'Clear Memory';
clearBtn.onclick = () => {
allFetchedData = [];
processedIds.clear();
alert("Memory Cleared");
};
const exportBtn = document.createElement('button');
exportBtn.className = 'dashboard-btn btn-export';
exportBtn.textContent = '💾 Export Overall CSV';
exportBtn.onclick = () => downloadCSV(allFetchedData, `youtube_all_comments.csv`);
container.append(clearBtn, exportBtn);
document.body.appendChild(container);
}
async function processGrid() {
const items = document.querySelectorAll('ytd-rich-item-renderer, ytd-video-renderer');
for (const item of items) {
const link = item.querySelector('a#video-title-link, a#thumbnail, a[href*="/watch"]');
if (!link) continue;
const url = new URL(link.href);
let vId = url.searchParams.get("v") || url.pathname.split('/').pop();
if (!vId || processedIds.has(vId) || item.querySelector('.comment-sidebar')) continue;
processedIds.add(vId);
const sidebar = document.createElement('div');
sidebar.className = 'comment-sidebar';
sidebar.innerHTML = '<span style="opacity:0.5; font-style:italic;">Scanning comments...</span>';
const infoContainer = item.querySelector('#content, #dismissible');
if (infoContainer) {
infoContainer.appendChild(sidebar);
}
fetchComments(vId).then(comments => {
if (comments.length === 0) {
sidebar.innerHTML = '<span style="opacity:0.5">No comments available.</span>';
return;
}
allFetchedData.push(...comments);
sidebar.innerHTML = '';
comments.slice(0, 3).forEach(c => {
const div = document.createElement('div');
div.className = 'comment-item';
div.innerHTML = `
<div class="comment-header">
<span class="comment-author">${c.author}</span>
<span class="comment-time">${c.timeAgo}</span>
</div>
<div class="comment-text">${c.content}</div>
`;
sidebar.appendChild(div);
});
const miniBtn = document.createElement('button');
miniBtn.className = 'export-btn-mini';
miniBtn.textContent = 'Export This Video';
miniBtn.onclick = (e) => {
e.preventDefault();
e.stopPropagation();
downloadCSV(comments, `comments_${vId}.csv`);
};
sidebar.appendChild(miniBtn);
});
}
}
injectDashboard();
setInterval(processGrid, 3000);
window.addEventListener("urlchange", () => {
// We don't clear allFetchedData here so the Overall Export stays large,
// but we clear processedIds to allow re-scans if the user navigates back.
processedIds.clear();
setTimeout(processGrid, 2000);
});
})();