L'API YouTube Comments permet aux développeurs de créer des outils d'engagement puissants qui récupèrent, publient et modèrent les commentaires de manière programmatique. Que vous construisiez un tableau de bord de médias sociaux, un outil de gestion de communauté ou un système de réponse automatisé, comprendre les ressources de commentaires de l'API YouTube Data est essentiel pour créer des intégrations efficaces.
Ce guide couvre tout ce dont vous avez besoin pour implémenter une gestion robuste des commentaires YouTube dans vos applications, de la configuration de l'authentification aux stratégies d'optimisation de quota qui maintiennent votre intégration en bon fonctionnement.

Introduction à l'API YouTube Data v3
L'API YouTube Data v3 fournit un accès programmatique aux fonctionnalités principales de YouTube, y compris les téléchargements de vidéos, la gestion des playlists et les opérations sur les commentaires. Pour la gestion des commentaires spécifiquement, l'API expose deux ressources principales :
- CommentThreads : Commentaires de premier niveau sur les vidéos, incluant les métadonnées sur le nombre de réponses
- Comments : Commentaires individuels, incluant les réponses aux commentaires de premier niveau
L'API suit les conventions RESTful et retourne des réponses JSON. Toutes les opérations sur les commentaires nécessitent une authentification OAuth 2.0 car elles impliquent des données et actions spécifiques à l'utilisateur.
// 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 Authentification OAuth 2.0
Les opérations sur les commentaires YouTube nécessitent différents niveaux d'authentification selon l'action :
| Opération | API Key | OAuth 2.0 |
|---|---|---|
| Lire les commentaires publics | ✅ | ✅ |
| Lire les commentaires sur ses propres vidéos | ❌ | ✅ |
| Publier des commentaires | ❌ | ✅ |
| Répondre aux commentaires | ❌ | ✅ |
| Supprimer des commentaires | ❌ | ✅ |
| Modérer les commentaires | ❌ | ✅ |
Pour toute opération d'écriture ou accès aux données privées, vous devez utiliser OAuth 2.0. Voici comment configurer le flux 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();
}
Note : Le scope
youtube.force-sslest requis pour les opérations sur les commentaires. Sans lui, les requêtes d'écriture échoueront avec une erreur 403.
Comprendre le Quota de l'API YouTube (10 000 Unités/Jour)
Le système de quota de l'API YouTube est l'un des concepts les plus importants à comprendre avant de construire toute intégration. Chaque requête API consomme des unités de quota, et vous êtes limité à 10 000 unités par jour par défaut.
Voici la répartition des coûts de quota pour les opérations liées aux commentaires :
| Opération | Coût en Quota |
|---|---|
| commentThreads.list | 1 unité |
| comments.list | 1 unité |
| commentThreads.insert | 50 unités |
| comments.insert (réponse) | 50 unités |
| comments.delete | 50 unités |
| comments.update | 50 unités |
| comments.setModerationStatus | 50 unités |
Avec 10 000 unités par jour, vous pouvez effectuer approximativement :
- 10 000 opérations de lecture, OU
- 200 opérations d'écriture, OU
- Une combinaison des deux
// 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 };
}
Note : Le quota se réinitialise à minuit, heure du Pacifique (PT). Si vous atteignez les limites de quota, vos requêtes échoueront jusqu'à la réinitialisation. Planifiez vos opérations en conséquence.
Ressources CommentThreads vs Comments
Comprendre la différence entre ces deux ressources est crucial pour une gestion efficace des commentaires YouTube.
CommentThreads représentent les commentaires de premier niveau sur une vidéo. Chaque thread contient :
- Le commentaire original (topLevelComment)
- Le nombre de réponses
- Optionnellement, un sous-ensemble de réponses
Comments représentent les commentaires individuels, qui peuvent être soit :
- Des commentaires de premier niveau (accessibles via CommentThreads)
- Des réponses aux commentaires de premier niveau
Utilisez CommentThreads lorsque vous voulez :
- Récupérer tous les commentaires de premier niveau sur une vidéo
- Obtenir le nombre de commentaires et les informations de base sur les réponses
- Publier un nouveau commentaire de premier niveau
Utilisez Comments lorsque vous voulez :
- Récupérer toutes les réponses à un commentaire spécifique
- Publier une réponse à un commentaire existant
- Mettre à jour ou supprimer un commentaire spécifique
// 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[];
};
}
Récupérer les Commentaires Vidéo avec l'API YouTube Comments
La récupération des commentaires est l'opération la plus courante. Voici une implémentation complète qui gère la pagination et le décodage des entités 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,
},
};
}
Publier des Réponses aux Commentaires
Répondre aux commentaires nécessite l'endpoint comments.insert avec l'ID du commentaire parent :
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 };
}
Opérations de Modération des Commentaires
YouTube fournit des capacités de modération pour les propriétaires de chaînes afin de gérer les commentaires sur leurs vidéos :
type ModerationStatus = 'heldForReview' | 'published' | 'rejected';
interface ModerationResult {
succes