Blog

YouTube Comments API: Guida Completa alla Gestione

Padroneggia la YouTube Comments API con esempi TypeScript per recuperare, pubblicare e moderare commenti. Include suggerimenti per l'ottimizzazione della quota.

Di

+8

Pubblica ovunque. Una API.

Try Free

La YouTube Comments API consente agli sviluppatori di creare potenti strumenti di engagement che recuperano, pubblicano e moderano commenti in modo programmatico. Che tu stia costruendo una dashboard per social media, uno strumento di gestione della community o un sistema di risposta automatizzato, comprendere le risorse per i commenti della YouTube Data API è essenziale per creare integrazioni efficaci.

Questa guida copre tutto ciò di cui hai bisogno per implementare una robusta gestione dei commenti YouTube nelle tue applicazioni, dalla configurazione dell'autenticazione alle strategie di ottimizzazione della quota che mantengono la tua integrazione funzionante senza problemi.

Architettura YouTube Comments API

Introduzione alla YouTube Data API v3

La YouTube Data API v3 fornisce accesso programmatico alle funzionalità principali di YouTube, inclusi caricamenti video, gestione delle playlist e operazioni sui commenti. Per la gestione dei commenti in particolare, l'API espone due risorse principali:

  • CommentThreads: Commenti di primo livello sui video, inclusi metadati sul conteggio delle risposte
  • Comments: Commenti individuali, incluse le risposte ai commenti di primo livello

L'API segue le convenzioni RESTful e restituisce risposte JSON. Tutte le operazioni sui commenti richiedono l'autenticazione OAuth 2.0 poiché coinvolgono dati e azioni specifici dell'utente.

// 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 Autenticazione OAuth 2.0

Le operazioni sui commenti di YouTube richiedono diversi livelli di autenticazione a seconda dell'azione:

OperazioneAPI KeyOAuth 2.0
Leggere commenti pubblici
Leggere commenti sui propri video
Pubblicare commenti
Rispondere ai commenti
Eliminare commenti
Moderare commenti

Per qualsiasi operazione di scrittura o accesso a dati privati, devi utilizzare OAuth 2.0. Ecco come configurare il flusso OAuth:

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();
}

Nota: Lo scope youtube.force-ssl è richiesto per le operazioni sui commenti. Senza di esso, le richieste di scrittura falliranno con un errore 403.

Comprendere la Quota dell'API YouTube (10.000 Unità/Giorno)

Il sistema di quota dell'API YouTube è uno dei concetti più importanti da comprendere prima di costruire qualsiasi integrazione. Ogni richiesta API consuma unità di quota, e sei limitato a 10.000 unità al giorno per impostazione predefinita.

Ecco la ripartizione dei costi di quota per le operazioni relative ai commenti:

OperazioneCosto Quota
commentThreads.list1 unità
comments.list1 unità
commentThreads.insert50 unità
comments.insert (risposta)50 unità
comments.delete50 unità
comments.update50 unità
comments.setModerationStatus50 unità

Con 10.000 unità al giorno, puoi eseguire approssimativamente:

  • 10.000 operazioni di lettura, OPPURE
  • 200 operazioni di scrittura, OPPURE
  • Una combinazione di entrambe
// 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 };
}

Nota: La quota si resetta a mezzanotte Pacific Time (PT). Se raggiungi i limiti di quota, le tue richieste falliranno fino al reset. Pianifica le tue operazioni di conseguenza.

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

Risorse CommentThreads vs Comments

Comprendere la differenza tra queste due risorse è cruciale per una gestione efficiente dei commenti YouTube.

CommentThreads rappresentano i commenti di primo livello su un video. Ogni thread contiene:

  • Il commento originale (topLevelComment)
  • Conteggio delle risposte
  • Opzionalmente, un sottoinsieme di risposte

Comments rappresentano commenti individuali, che possono essere:

  • Commenti di primo livello (accessibili tramite CommentThreads)
  • Risposte ai commenti di primo livello

Usa CommentThreads quando vuoi:

  • Recuperare tutti i commenti di primo livello su un video
  • Ottenere conteggi dei commenti e informazioni di base sulle risposte
  • Pubblicare un nuovo commento di primo livello

Usa Comments quando vuoi:

  • Recuperare tutte le risposte a un commento specifico
  • Pubblicare una risposta a un commento esistente
  • Aggiornare o eliminare un commento specifico
// 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[];
  };
}

Recuperare i Commenti dei Video con la YouTube Comments API

Recuperare i commenti è l'operazione più comune. Ecco un'implementazione completa che gestisce la paginazione e la decodifica delle entità HTML:

// 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,
    },
  };
}

Pubblicare Risposte ai Commenti

Rispondere ai commenti richiede l'endpoint comments.insert con l'ID del commento padre:

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('I commenti sono disabilitati su questo video');
      }
      if (errorBody.includes('forbidden')) {
        throw new Error('Non hai il permesso di commentare su questo video');
      }
    }
    
    if (response.status === 400) {
      if (errorBody.includes('processingFailure')) {
        throw new Error('Elaborazione del commento fallita. Il commento potrebbe contenere contenuti proibiti.');
      }
    }
    
    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 };
}

Operazioni di Moderazione dei Commenti

YouTube fornisce funzionalità di moderazione per i proprietari dei canali per gestire i commenti sui loro video:

type ModerationStatus = 'heldForReview' | 'published' | 'rejected';

interface ModerationResult {
  succes

Una API. 13+ piattaforme.

Integra i social in minuti, non settimane.

Progettato per sviluppatori. Apprezzato dalle agenzie. Fidato da 6.325 utenti.