Blog

YouTube Comments API: Vollständiger Leitfaden zur Verwaltung

Meistern Sie die YouTube Comments API mit TypeScript-Beispielen zum Abrufen, Posten und Moderieren von Kommentaren. Inklusive Tipps zur Quota-Optimierung.

Von

+8

Überall posten. Eine API.

Try Free

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.

YouTube Comments API Architektur

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:

OperationAPI KeyOAuth 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:

OperationQuota-Kosten
commentThreads.list1 Einheit
comments.list1 Einheit
commentThreads.insert50 Einheiten
comments.insert (Antwort)50 Einheiten
comments.delete50 Einheiten
comments.update50 Einheiten
comments.setModerationStatus50 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.

Build faster with Late

One API call to post everywhere. No OAuth headaches. No platform-specific code.

Free tier • No credit card • 99.97% uptime

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

Eine API. 13+ Plattformen.

Social Media Features in Minuten integrieren, nicht Wochen.

Für Entwickler gemacht. Von Agenturen geschätzt. Von 6.325 Nutzern vertraut.