Die YouTube Comments API ermöglicht es Entwicklern, leistungsstarke Engagement-Tools zu erstellen, die Kommentare programmatisch abrufen, posten und moderieren. Ob Sie ein Social-Media-Dashboard, ein Community-Management-Tool oder ein automatisiertes Antwortsystem entwickeln – das Verständnis der Kommentar-Ressourcen der YouTube Data API ist essentiell für die Erstellung effektiver Integrationen.
Dieser Leitfaden behandelt alles, was Sie für die Implementierung einer robusten YouTube-Kommentarverwaltung in Ihren Anwendungen benötigen, von der Authentifizierungseinrichtung bis hin zu Quota-Optimierungsstrategien, die Ihre Integration reibungslos am Laufen halten.

Einführung in die YouTube Data API v3
Die YouTube Data API v3 bietet programmatischen Zugriff auf die Kernfunktionen von YouTube, einschließlich Video-Uploads, Playlist-Verwaltung und Kommentaroperationen. Speziell für die Kommentarverwaltung stellt die API zwei primäre Ressourcen bereit:
- CommentThreads: Top-Level-Kommentare zu Videos, einschließlich Metadaten über Antwortanzahlen
- Comments: Einzelne Kommentare, einschließlich Antworten auf Top-Level-Kommentare
Die API folgt RESTful-Konventionen und gibt JSON-Antworten zurück. Alle Kommentaroperationen erfordern OAuth 2.0-Authentifizierung, da sie benutzerspezifische Daten und Aktionen beinhalten.
// Base configuration for YouTube API requests
const YOUTUBE_API_BASE = 'https://www.googleapis.com/youtube/v3';
interface YouTubeApiConfig {
accessToken: string;
baseUrl: string;
}
const config: YouTubeApiConfig = {
accessToken: process.env.YOUTUBE_ACCESS_TOKEN || '',
baseUrl: YOUTUBE_API_BASE,
};
API Key vs OAuth 2.0-Authentifizierung
YouTubes Kommentaroperationen erfordern unterschiedliche Authentifizierungsstufen je nach Aktion:
| Operation | API Key | OAuth 2.0 |
|---|---|---|
| Öffentliche Kommentare lesen | ✅ | ✅ |
| Kommentare auf eigenen Videos lesen | ❌ | ✅ |
| Kommentare posten | ❌ | ✅ |
| Auf Kommentare antworten | ❌ | ✅ |
| Kommentare löschen | ❌ | ✅ |
| Kommentare moderieren | ❌ | ✅ |
Für jede Schreiboperation oder den Zugriff auf private Daten müssen Sie OAuth 2.0 verwenden. So richten Sie den OAuth-Flow ein:
interface OAuthConfig {
clientId: string;
clientSecret: string;
redirectUri: string;
scopes: string[];
}
const oauthConfig: OAuthConfig = {
clientId: process.env.YOUTUBE_CLIENT_ID || '',
clientSecret: process.env.YOUTUBE_CLIENT_SECRET || '',
redirectUri: 'https://yourapp.com/auth/youtube/callback',
scopes: [
'https://www.googleapis.com/auth/youtube.force-ssl',
'https://www.googleapis.com/auth/youtube',
],
};
function getAuthUrl(state?: string): string {
const params = new URLSearchParams({
client_id: oauthConfig.clientId,
redirect_uri: oauthConfig.redirectUri,
scope: oauthConfig.scopes.join(' '),
response_type: 'code',
access_type: 'offline',
prompt: 'consent',
});
if (state) {
params.append('state', state);
}
return `https://accounts.google.com/o/oauth2/auth?${params.toString()}`;
}
async function exchangeCodeForToken(code: string): Promise<{
access_token: string;
refresh_token: string;
expires_in: number;
}> {
const response = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
code,
client_id: oauthConfig.clientId,
client_secret: oauthConfig.clientSecret,
redirect_uri: oauthConfig.redirectUri,
grant_type: 'authorization_code',
}),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Token exchange failed: ${response.status} ${errorText}`);
}
return response.json();
}
Hinweis: Der
youtube.force-ssl-Scope ist für Kommentaroperationen erforderlich. Ohne ihn schlagen Schreibanfragen mit einem 403-Fehler fehl.
Verständnis des YouTube API-Quotas (10.000 Einheiten/Tag)
Das YouTube API-Quota-System ist eines der wichtigsten Konzepte, die Sie verstehen müssen, bevor Sie eine Integration erstellen. Jede API-Anfrage verbraucht Quota-Einheiten, und Sie sind standardmäßig auf 10.000 Einheiten pro Tag begrenzt.
Hier ist die Aufschlüsselung der Quota-Kosten für kommentarbezogene Operationen:
| Operation | Quota-Kosten |
|---|---|
| commentThreads.list | 1 Einheit |
| comments.list | 1 Einheit |
| commentThreads.insert | 50 Einheiten |
| comments.insert (Antwort) | 50 Einheiten |
| comments.delete | 50 Einheiten |
| comments.update | 50 Einheiten |
| comments.setModerationStatus | 50 Einheiten |
Mit 10.000 Einheiten pro Tag können Sie ungefähr durchführen:
- 10.000 Leseoperationen, ODER
- 200 Schreiboperationen, ODER
- Eine Kombination aus beidem
// Quota tracking utility
interface QuotaTracker {
used: number;
limit: number;
operations: Map;
}
const quotaCosts: Record = {
'commentThreads.list': 1,
'comments.list': 1,
'commentThreads.insert': 50,
'comments.insert': 50,
'comments.delete': 50,
'comments.update': 50,
'comments.setModerationStatus': 50,
};
function createQuotaTracker(dailyLimit: number = 10000): QuotaTracker {
return {
used: 0,
limit: dailyLimit,
operations: new Map(),
};
}
function trackQuotaUsage(
tracker: QuotaTracker,
operation: string
): { allowed: boolean; remaining: number } {
const cost = quotaCosts[operation] || 1;
if (tracker.used + cost > tracker.limit) {
return { allowed: false, remaining: tracker.limit - tracker.used };
}
tracker.used += cost;
const currentCount = tracker.operations.get(operation) || 0;
tracker.operations.set(operation, currentCount + 1);
return { allowed: true, remaining: tracker.limit - tracker.used };
}
Hinweis: Das Quota wird um Mitternacht Pacific Time (PT) zurückgesetzt. Wenn Sie Quota-Limits erreichen, schlagen Ihre Anfragen bis zum Reset fehl. Planen Sie Ihre Operationen entsprechend.
CommentThreads vs Comments-Ressourcen
Das Verständnis des Unterschieds zwischen diesen beiden Ressourcen ist entscheidend für eine effiziente YouTube-Kommentarverwaltung.
CommentThreads repräsentieren Top-Level-Kommentare zu einem Video. Jeder Thread enthält:
- Den ursprünglichen Kommentar (topLevelComment)
- Antwortanzahl
- Optional eine Teilmenge von Antworten
Comments repräsentieren einzelne Kommentare, die entweder sein können:
- Top-Level-Kommentare (zugänglich über CommentThreads)
- Antworten auf Top-Level-Kommentare
Verwenden Sie CommentThreads, wenn Sie:
- Alle Top-Level-Kommentare zu einem Video abrufen möchten
- Kommentaranzahlen und grundlegende Antwortinformationen erhalten möchten
- Einen neuen Top-Level-Kommentar posten möchten
Verwenden Sie Comments, wenn Sie:
- Alle Antworten auf einen bestimmten Kommentar abrufen möchten
- Eine Antwort auf einen bestehenden Kommentar posten möchten
- Einen bestimmten Kommentar aktualisieren oder löschen möchten
// Type definitions for YouTube comment structures
interface YouTubeCommentSnippet {
authorDisplayName: string;
authorProfileImageUrl: string;
authorChannelId: { value: string };
textDisplay: string;
textOriginal: string;
likeCount: number;
publishedAt: string;
updatedAt: string;
}
interface YouTubeComment {
id: string;
snippet: YouTubeCommentSnippet;
}
interface YouTubeCommentThread {
id: string;
snippet: {
videoId: string;
topLevelComment: YouTubeComment;
totalReplyCount: number;
isPublic: boolean;
};
replies?: {
comments: YouTubeComment[];
};
}
Video-Kommentare mit der YouTube Comments API abrufen
Das Abrufen von Kommentaren ist die häufigste Operation. Hier ist eine vollständige Implementierung, die Paginierung und HTML-Entity-Dekodierung behandelt:
// Helper to decode HTML entities from YouTube API responses
function decodeHtmlEntities(text: string): string {
if (!text) return text;
return text
.replace(/'/g, "'")
.replace(/"/g, '"')
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/'/g, "'")
.replace(///g, '/')
.replace(/ /g, ' ');
}
interface CommentData {
commentId: string;
comment: string;
created: string;
from: {
id: string;
name: string;
picture: string;
};
likeCount: number;
replyCount: number;
platform: 'youtube';
platformPostId: string;
replies: CommentData[];
}
interface GetCommentsOptions {
limit?: number;
pageToken?: string;
}
interface GetCommentsResult {
comments: CommentData[];
pagination: {
hasMore: boolean;
pageToken?: string;
};
}
async function getVideoComments(
accessToken: string,
videoId: string,
options: GetCommentsOptions = {}
): Promise {
const maxResults = Math.min(options.limit || 25, 100);
const params = new URLSearchParams({
part: 'snippet,replies',
videoId: videoId,
maxResults: maxResults.toString(),
});
if (options.pageToken) {
params.append('pageToken', options.pageToken);
}
const response = await fetch(
`${YOUTUBE_API_BASE}/commentThreads?${params.toString()}`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);
if (!response.ok) {
const errorBody = await response.text();
throw new Error(`Failed to fetch comments: ${response.status} ${errorBody}`);
}
const data = await response.json();
const comments: CommentData[] = (data.items || []).map(
(thread: YouTubeCommentThread) => {
const topComment = thread.snippet.topLevelComment.snippet;
const replies: CommentData[] = (thread.replies?.comments || []).map(
(reply: YouTubeComment) => ({
commentId: reply.id,
comment: decodeHtmlEntities(reply.snippet.textDisplay),
created: reply.snippet.publishedAt,
from: {
id: reply.snippet.authorChannelId?.value || '',
name: reply.snippet.authorDisplayName,
picture: reply.snippet.authorProfileImageUrl,
},
likeCount: reply.snippet.likeCount || 0,
replyCount: 0,
platform: 'youtube' as const,
platformPostId: thread.snippet.videoId,
replies: [],
})
);
return {
commentId: thread.snippet.topLevelComment.id,
comment: decodeHtmlEntities(topComment.textDisplay),
created: topComment.publishedAt,
from: {
id: topComment.authorChannelId?.value || '',
name: topComment.authorDisplayName,
picture: topComment.authorProfileImageUrl,
},
likeCount: topComment.likeCount || 0,
replyCount: thread.snippet.totalReplyCount || 0,
platform: 'youtube' as const,
platformPostId: thread.snippet.videoId,
replies,
};
}
);
return {
comments,
pagination: {
hasMore: !!data.nextPageToken,
pageToken: data.nextPageToken,
},
};
}
Kommentarantworten posten
Das Antworten auf Kommentare erfordert den comments.insert-Endpoint mit der übergeordneten Kommentar-ID:
interface ReplyResult {
replyId: string;
text: string;
publishedAt: string;
}
async function replyToComment(
accessToken: string,
parentCommentId: string,
text: string
): Promise {
const response = await fetch(
`${YOUTUBE_API_BASE}/comments?part=snippet`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
snippet: {
parentId: parentCommentId,
textOriginal: text,
},
}),
}
);
if (!response.ok) {
const errorBody = await response.text();
// Handle specific error cases
if (response.status === 403) {
if (errorBody.includes('commentsDisabled')) {
throw new Error('Comments are disabled on this video');
}
if (errorBody.includes('forbidden')) {
throw new Error('You do not have permission to comment on this video');
}
}
if (response.status === 400) {
if (errorBody.includes('processingFailure')) {
throw new Error('Comment processing failed. The comment may contain prohibited content.');
}
}
throw new Error(`Failed to post reply: ${response.status} ${errorBody}`);
}
const data = await response.json();
return {
replyId: data.id,
text: data.snippet.textDisplay,
publishedAt: data.snippet.publishedAt,
};
}
// Post a new top-level comment on a video
async function postComment(
accessToken: string,
videoId: string,
text: string
): Promise<{ commentId: string }> {
const response = await fetch(
`${YOUTUBE_API_BASE}/commentThreads?part=snippet`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
snippet: {
videoId,
topLevelComment: {
snippet: {
textOriginal: text,
},
},
},
}),
}
);
if (!response.ok) {
const errorBody = await response.text();
throw new Error(`Failed to post comment: ${response.status} ${errorBody}`);
}
const data = await response.json();
return { commentId: data.id };
}
Kommentar-Moderationsoperationen
YouTube bietet Moderationsfunktionen für Kanalbesitzer zur Verwaltung von Kommentaren auf ihren Videos:
type ModerationStatus = 'heldForReview' | 'published' | 'rejected';
interface ModerationResult {
succes