Das Verwalten von Kommentaren über mehrere Instagram-Posts hinweg wird überwältigend, wenn dein Publikum wächst. Instagram-Kommentarmoderation über die Graph API ermöglicht es dir, automatisierte Systeme zu erstellen, die Kommentare programmatisch abrufen, filtern, beantworten und moderieren. Diese Anleitung führt dich durch die Implementierung einer vollständigen Kommentarverwaltungslösung mit TypeScript.
Ob du ein Social-Media-Dashboard, ein Kundensupport-Tool oder ein automatisiertes Engagement-System erstellst – das Verständnis der Instagram Comment API ist essentiell. Wir behandeln alles von der grundlegenden Authentifizierung bis hin zu fortgeschrittenen Moderations-Workflows mit Sentiment-Analyse.
API-Zugriffsanforderungen
Bevor du Instagram-Kommentare automatisieren kannst, benötigst du einen ordnungsgemäß konfigurierten API-Zugang. Die Instagram Graph API erfordert ein Facebook-Entwicklerkonto und eine genehmigte App mit spezifischen Berechtigungen.
Erforderliche Berechtigungen
Deine App benötigt diese OAuth-Scopes, um mit Kommentaren zu arbeiten:
const INSTAGRAM_SCOPES = [
'instagram_business_basic', // Basic account access
'instagram_business_content_publish', // Publish content
'instagram_business_manage_comments', // Read and manage comments
'instagram_business_manage_messages', // Required for private replies
];
Umgebungseinrichtung
Erstelle eine .env-Datei mit deinen Anmeldedaten:
INSTAGRAM_CLIENT_ID=your_client_id
INSTAGRAM_CLIENT_SECRET=your_client_secret
INSTAGRAM_ACCESS_TOKEN=your_long_lived_token
INSTAGRAM_USER_ID=your_business_account_id
Token-Austausch-Implementierung
Instagram-Tokens beginnen als kurzlebige Tokens (1 Stunde) und müssen gegen langlebige Tokens (60 Tage) ausgetauscht werden:
interface TokenResponse {
access_token: string;
token_type: string;
expires_in: number;
}
async function exchangeForLongLivedToken(
shortLivedToken: string,
clientSecret: string
): Promise<TokenResponse> {
const baseUrl = 'https://graph.instagram.com';
const response = await fetch(
`${baseUrl}/access_token?` +
`grant_type=ig_exchange_token&` +
`client_secret=${clientSecret}&` +
`access_token=${shortLivedToken}`,
{ method: 'GET' }
);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Token exchange failed: ${response.status} - ${errorText}`);
}
return response.json();
}
async function refreshLongLivedToken(
currentToken: string
): Promise<TokenResponse> {
const baseUrl = 'https://graph.instagram.com';
const response = await fetch(
`${baseUrl}/refresh_access_token?` +
`grant_type=ig_refresh_token&` +
`access_token=${currentToken}`,
{ method: 'GET' }
);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Token refresh failed: ${response.status} - ${errorText}`);
}
return response.json();
}
Hinweis: Langlebige Tokens müssen vor ihrem Ablauf aktualisiert werden. Richte einen Cron-Job ein, um Tokens mindestens 7 Tage vor Ablauf zu aktualisieren.
Kommentare von Posts abrufen
Die Grundlage jedes Instagram-Kommentarmoderation-Systems ist das effiziente Abrufen von Kommentaren. Die API unterstützt Paginierung für die Verarbeitung von Posts mit Tausenden von Kommentaren.
Grundlegendes Abrufen von Kommentaren
interface InstagramUser {
id: string;
username: string;
}
interface InstagramComment {
commentId: string;
comment: string;
created: string;
from: InstagramUser;
likeCount: number;
replyCount: number;
hidden: boolean;
platform: 'instagram';
replies: InstagramComment[];
}
interface CommentResponse {
comments: InstagramComment[];
pagination: {
hasMore: boolean;
cursor?: string;
};
}
async function getMediaComments(
accessToken: string,
mediaId: string,
options?: { limit?: number; cursor?: string }
): Promise<CommentResponse> {
const baseUrl = 'https://graph.instagram.com';
const limit = Math.min(options?.limit || 25, 50);
let url = `${baseUrl}/${mediaId}/comments?` +
`fields=id,text,timestamp,username,hidden,` +
`from{id,username},like_count,` +
`replies{id,text,timestamp,username,hidden,from{id,username},like_count}&` +
`limit=${limit}&access_token=${accessToken}`;
if (options?.cursor) {
url += `&after=${options.cursor}`;
}
const response = await fetch(url);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Failed to fetch comments: ${response.status} - ${errorText}`);
}
const data = await response.json();
// Build lookup map for complete comment data
const commentDataById = new Map<string, any>();
(data.data || []).forEach((comment: any) => {
commentDataById.set(comment.id, comment);
});
// Identify reply IDs to filter from top-level
const allReplyIds = new Set<string>();
(data.data || []).forEach((comment: any) => {
(comment.replies?.data || []).forEach((reply: any) => {
allReplyIds.add(reply.id);
});
});
// Filter to only top-level comments
const topLevelComments = (data.data || [])
.filter((comment: any) => !allReplyIds.has(comment.id));
const comments: InstagramComment[] = topLevelComments.map((comment: any) => ({
commentId: comment.id,
comment: comment.text,
created: comment.timestamp,
from: {
id: comment.from?.id,
username: comment.from?.username || comment.username,
},
likeCount: comment.like_count || 0,
replyCount: comment.replies?.data?.length || 0,
hidden: comment.hidden || false,
platform: 'instagram',
replies: (comment.replies?.data || []).map((reply: any) => {
const fullReplyData = commentDataById.get(reply.id) || reply;
return {
commentId: reply.id,
comment: fullReplyData.text || reply.text,
created: fullReplyData.timestamp || reply.timestamp,
from: {
id: fullReplyData.from?.id || reply.from?.id,
username: fullReplyData.from?.username || reply.from?.username,
},
likeCount: fullReplyData.like_count || reply.like_count || 0,
hidden: fullReplyData.hidden || false,
platform: 'instagram',
replies: [],
replyCount: 0,
};
}),
}));
return {
comments,
pagination: {
hasMore: !!data.paging?.next,
cursor: data.paging?.cursors?.after,
},
};
}
Alle Kommentare mit Paginierung abrufen
Für Posts mit vielen Kommentaren implementiere Paginierung, um alles abzurufen:
async function getAllComments(
accessToken: string,
mediaId: string,
maxComments: number = 1000
): Promise<InstagramComment[]> {
const allComments: InstagramComment[] = [];
let cursor: string | undefined;
while (allComments.length < maxComments) {
const response = await getMediaComments(accessToken, mediaId, {
limit: 50,
cursor,
});
allComments.push(...response.comments);
if (!response.pagination.hasMore || !response.pagination.cursor) {
break;
}
cursor = response.pagination.cursor;
// Rate limiting: wait between requests
await new Promise(resolve => setTimeout(resolve, 100));
}
return allComments.slice(0, maxComments);
}
Programmatisch auf Kommentare antworten
Die Möglichkeit, programmatisch über die Instagram Comments API zu antworten, ermöglicht automatisiertes Engagement, Kundensupport-Bots und skaliertes Community-Management.
Implementierung öffentlicher Antworten
interface ReplyResult {
replyId: string;
success: boolean;
error?: string;
}
async function replyToComment(
accessToken: string,
commentId: string,
message: string
): Promise<ReplyResult> {
const baseUrl = 'https://graph.instagram.com';
try {
const response = await fetch(
`${baseUrl}/${commentId}/replies`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message,
access_token: accessToken,
}),
}
);
if (!response.ok) {
const errorText = await response.text();
return {
replyId: '',
success: false,
error: `Reply failed: ${response.status} - ${errorText}`,
};
}
const data = await response.json();
return {
replyId: data.id,
success: true,
};
} catch (error) {
return {
replyId: '',
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
Private Antwort (Direktnachricht)
Instagram ermöglicht das Senden einer privaten DM an Kommentarautoren. Dies ist nützlich für Kundensupport-Szenarien:
interface PrivateReplyResult {
messageId: string;
success: boolean;
error?: string;
}
async function sendPrivateReply(
accessToken: string,
igUserId: string,
commentId: string,
message: string
): Promise<PrivateReplyResult> {
const baseUrl = 'https://graph.instagram.com';
try {
const response = await fetch(
`${baseUrl}/${igUserId}/messages`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
},
body: JSON.stringify({
recipient: {
comment_id: commentId,
},
message: {
text: message,
},
}),
}
);
if (!response.ok) {
const errorText = await response.text();
// Handle specific error cases
if (errorText.includes('551') || errorText.toLowerCase().includes('already')) {
return {
messageId: '',
success: false,
error: 'A private reply has already been sent to this comment. Instagram only allows one private reply per comment.',
};
}
if (errorText.includes('10903')) {
return {
messageId: '',
success: false,
error: 'Comment is older than 7 days. Private replies must be sent within 7 days.',
};
}
return {
messageId: '',
success: false,
error: `Private reply failed: ${response.status} - ${errorText}`,
};
}
const data = await response.json();
return {
messageId: data.message_id || data.id,
success: true,
};
} catch (error) {
return {
messageId: '',
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
Hinweis: Instagram erlaubt nur EINE private Antwort pro Kommentar, und sie muss innerhalb von 7 Tagen nach dem Posten des Kommentars gesendet werden. Plane deine Automatisierung entsprechend.
Kommentare ausblenden und löschen
Effektive Instagram-Kommentarmoderation erfordert die Möglichkeit, unangemessene Kommentare auszublenden oder eigene Antworten zu löschen.
Kommentare ein- und ausblenden
async function hideComment(
accessToken: string,
commentId: string
): Promise<{ success: boolean; error?: string }> {
const baseUrl = 'https://graph.instagram.com';
try {
const response = await fetch(
`${baseUrl}/${commentId}?hide=true&access_token=${accessToken}`,
{ method: 'POST' }
);
if (!response.ok) {
const errorText = await response.text();
return {
success: false,
error: `Hide failed: ${response.status} - ${errorText}`,
};
}
return { success: true };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
async function unhideComment(
accessToken: string,
commentId: string
): Promise<{ success: boolean; error?: string }> {
const baseUrl = 'https://graph.instagram.com';
try {
const response = await fetch(
`${baseUrl}/${commentId}?hide=false&access_token=${accessToken}`,
{ method: 'POST' }
);
if (!response.ok) {
const errorText = await response.text();
return {
success: false,
error: `Unhide failed: ${response.status} - ${errorText}`,
};
}
return { success: true };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
Kommentare löschen
Du kannst nur Kommentare löschen, die du selbst verfasst hast (deine eigenen Antworten):
async function deleteComment(
accessToken: string,
commentId: string
): Promise<{ success: boolean; error?: string }> {
const baseUrl = 'https://graph.instagram.com';
try {
const response = await fetch(
`${baseUrl}/${commentId}?access_token=${accessToken}`,
{ method: 'DELETE' }
);
if (!response.ok) {
const errorText = await response.text();
return {
success: false,
error: `Delete failed: ${response.status} - ${errorText}`,
};
}
return { success: true };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
Kommentarfilterung und Moderationsregeln
Der Aufbau eines automatisierten Moderationssystems erfordert die Definition von Regeln dafür, welche Inhalte markiert, ausgeblendet oder beantwortet werden sollen.
Moderationsregel-Engine
interface ModerationRule {
id: string;
name: string;
type: 'keyword' | 'regex' | 'sentiment' | 'spam';
pattern?: string;
keywords?: string[];
action: 'hide' | 'flag' | 'delete' | 'reply';
replyTemplate?: string;
enabled: boolean;
}
interface ModerationResult {
commentId: string;
triggered: boolean;
matchedRules: string[];
action: 'hide' | 'flag' | 'delete' | 'reply' | 'none';
replyMessage?: string;
}
class CommentModerator {
private rules: ModerationRule[];
constructor(rules: ModerationRule[]) {
this.rules = rules.filter(r => r.enabled);
}
evaluate(comment: InstagramComment): ModerationResult {
const matchedRules: string[]