Back to Blog

Instagram Comment Moderation API: Automate Your Comments

Learn to automate Instagram comments using the Graph API. Build moderation systems, reply programmatically, and manage comments at scale with TypeScript.

By

+8

Post everywhere. One API.

Try Free

Managing comments across multiple Instagram posts becomes overwhelming as your audience grows. Instagram comment moderation through the Graph API lets you build automated systems that fetch, filter, reply to, and moderate comments programmatically. This guide walks you through implementing a complete comment management solution using TypeScript.

Whether you're building a social media dashboard, a customer support tool, or an automated engagement system, understanding the Instagram comment API is essential. We'll cover everything from basic authentication to advanced moderation workflows with sentiment analysis.

API Access Requirements

Before you can automate Instagram comments, you need proper API access configured. The Instagram Graph API requires a Facebook Developer account and an approved app with specific permissions.

Required Permissions

Your app needs these OAuth scopes to work with comments:

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
];

Environment Setup

Create a .env file with your credentials:

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 Exchange Implementation

Instagram tokens start as short-lived (1 hour) and must be exchanged for long-lived tokens (60 days):

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

Note: Long-lived tokens must be refreshed before they expire. Set up a cron job to refresh tokens at least 7 days before expiration.

Fetching Comments on Posts

The foundation of any Instagram comment moderation system is retrieving comments efficiently. The API supports pagination for handling posts with thousands of comments.

Basic Comment Retrieval

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

Fetching All Comments with Pagination

For posts with many comments, implement pagination to retrieve everything:

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

Replying to Comments Programmatically

The ability to reply to Instagram comments API programmatically enables automated engagement, customer support bots, and scaled community management.

Public Reply Implementation

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 Reply (Direct Message)

Instagram allows sending a private DM to comment authors. This is useful for customer support scenarios:

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

Note: Instagram only allows ONE private reply per comment, and it must be sent within 7 days of the comment being posted. Plan your automation accordingly.

Hiding and Deleting Comments

Effective Instagram comment moderation requires the ability to hide inappropriate comments or delete your own replies.

Hide and Unhide Comments

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

Delete Comments

You can only delete comments you've made (your own replies):

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

Comment Filtering and Moderation Rules

Building an automated moderation system requires defining rules for what content to flag, hide, or respond to.

Moderation Rule 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[] = [];
    let highestPriorityAction: ModerationResult['action'] = 'none';
    let replyMessage: string | undefined;

    const actionPriority = { delete: 4, hide: 3, reply: 2, flag: 1, none: 0 };

    for (const rule of this.rules) {
      const matches = this.checkRule(rule, comment.comment);
      
      if (matches) {
        matchedRules.push(rule.id);
        
        if (actionPriority[rule.action] > actionPriority[highestPriorityAction]) {
          highestPriorityAction = rule.action;
          replyMessage = rule.replyTemplate;
        }
      }
    }

    return {
      commentId: comment.commentId,
      triggered: matchedRules.length > 0,
      matchedRules,
      action: highestPriorityAction,
      replyMessage,
    };
  }

  private checkRule(rule: ModerationRule, text: string): boolean {
    const lowerText = text.toLowerCase();

    switch (rule.type) {
      case 'keyword':
        return (rule.keywords || []).some(kw => 
          lowerText.includes(kw.toLowerCase())
        );

      case 'regex':
        if (!rule.pattern) return false;
        try {
          const regex = new RegExp(rule.pattern, 'i');
          return regex.test(text);
        } catch {
          return false;
        }

      case 'spam':
        return this.detectSpam(text);

      default:
        return false;
    }
  }

  private detectSpam(text: string): boolean {
    // Basic spam detection heuristics
    const spamIndicators = [
      // Excessive caps
      text.length > 10 && (text.match(/[A-Z]/g)?.length || 0) / text.length > 0.7,
      // Repeated characters
      /(.)\1{4,}/.test(text),
      // Too many links
      (text.match(/https?:\/\//g)?.length || 0) > 2,
      // Common spam phrases
      /\b(free|winner|click here|dm me|check bio)\b/i.test(text),
      // Excessive emojis
      (text.match(/[\u{1F600}-\u{1F64F}]/gu)?.length || 0) > 10,
    ];

    return spamIndicators.filter(Boolean).length >= 2;
  }
}

// Example usage
const moderator = new CommentModerator([
  {
    id: 'profanity',
    name: 'Profanity Filter',
    type: 'keyword',
    keywords: ['badword1', 'badword2'],
    action: 'hide',
    enabled: true,
  },
  {
    id: 'competitor-links',
    name: 'Competitor Links',
    type: 'regex',
    pattern: 'competitor\\.com',
    action: 'hide',
    enabled: true,
  },
  {
    id: 'questions',
    name: 'Auto-reply Questions',
    type: 'regex',
    pattern: '\\?$',
    action: 'reply',
    replyTemplate: 'Thanks for your question! Check our bio for more info or DM us.',
    enabled: true,
  },
  {
    id: 'spam-detection',
    name: 'Spam Filter',
    type: 'spam',
    action: 'hide',
    enabled: true,
  },
]);

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

Bulk Operations and Automation

To automate Instagram comments at scale, you need efficient batch processing with proper rate limiting.

Batch Comment Processor

interface BatchResult {
  processed: number;
  succeeded: number;
  failed: number;
  errors: Array<{ commentId: string; error: string }>;
}

class CommentBatchProcessor {
  private accessToken: string;
  private rateLimitDelay: number;

  constructor(accessToken: string, rateLimitDelay: number = 200) {
    this.accessToken = accessToken;
    this.rateLimitDelay = rateLimitDelay;
  }

  async processComments(
    comments: InstagramComment[],
    moderator: CommentModerator
  ): Promise<BatchResult> {
    const result: BatchResult = {
      processed: 0,
      succeeded: 0,
      failed: 0,
      errors: [],
    };

    for (const comment of comments) {
      const modResult = moderator.evaluate(comment);
      
      if (!modResult.triggered) {
        result.processed++;
        result.succeeded++;
        continue;
      }

      try {
        await this.executeAction(modResult);
        result.succeeded++;
      } catch (error) {
        result.failed++;
        result.errors.push({
          commentId: comment.commentId,
          error: error instanceof Error ? error.message : 'Unknown error',
        });
      }

      result.processed++;
      
      // Rate limiting
      await new Promise(resolve => setTimeout(resolve, this.rateLimitDelay));
    }

    return result;
  }

  private async executeAction(modResult: ModerationResult): Promise<void> {
    switch (modResult.action) {
      case 'hide':
        await hideComment(this.accessToken, modResult.commentId);
        break;

      case 'delete':
        await deleteComment(this.accessToken, modResult.commentId);
        break;

      case 'reply':
        if (modResult.replyMessage) {
          await replyToComment(
            this.accessToken,
            modResult.commentId,
            modResult.replyMessage
          );
        }
        break;

      case 'flag':
        // Log for manual review
        console.log(`Flagged comment ${modResult.commentId} for review`);
        break;
    }
  }
}

Automated Monitoring Job

interface MonitoringConfig {
  mediaIds: string[];
  checkIntervalMs: number;
  moderator: CommentModerator;
}

class CommentMonitor {
  private accessToken: string;
  private config: MonitoringConfig;
  private processedComments: Set<string>;
  private isRunning: boolean;

  constructor(accessToken: string, config: MonitoringConfig) {
    this.accessToken = accessToken;
    this.config = config;
    this.processedComments = new Set();
    this.isRunning = false;
  }

  async start(): Promise<void> {
    this.isRunning = true;
    console.log('Comment monitor started');

    while (this.isRunning) {
      for (const mediaId of this.config.mediaIds) {
        await this.checkMedia(mediaId);
      }

      await new Promise(resolve => 
        setTimeout(resolve, this.config.checkIntervalMs)
      );
    }
  }

  stop(): void {
    this.isRunning = false;
    console.log('Comment monitor stopped');
  }

  private async checkMedia(mediaId: string): Promise<void> {
    try {
      const response = await getMediaComments(this.accessToken, mediaId, {
        limit: 50,
      });

      const newComments = response.comments.filter(
        c => !this.processedComments.has(c.commentId)
      );

      if (newComments.length === 0) return;

      console.log(`Found ${newComments.length} new comments on ${mediaId}`);

      const processor = new CommentBatchProcessor(this.accessToken);
      await processor.processComments(newComments, this.config.moderator);

      // Mark as processed
      newComments.forEach(c => this.processedComments.add(c.commentId));
    } catch (error) {
      console.error(`Error checking media ${mediaId}:`, error);
    }
  }
}

Sentiment Analysis Integration

Adding sentiment analysis helps prioritize responses and identify unhappy customers.

interface SentimentResult {
  score: number;        // -1 to 1
  label: 'positive' | 'neutral' | 'negative';
  confidence: number;   // 0 to 1
}

// Simple keyword-based sentiment (replace with ML model for production)
function analyzeSentiment(text: string): SentimentResult {
  const positiveWords = [
    'love', 'amazing', 'great', 'awesome', 'beautiful', 'perfect',
    'thanks', 'thank you', 'excellent', 'wonderful', 'best', 'fantastic'
  ];
  
  const negativeWords = [
    'hate', 'terrible', 'awful', 'worst', 'bad', 'horrible',
    'disappointed', 'angry', 'frustrated', 'poor', 'waste', 'scam'
  ];

  const lowerText = text.toLowerCase();
  const words = lowerText.split(/\s+/);

  let positiveCount = 0;
  let negativeCount = 0;

  for (const word of words) {
    if (positiveWords.some(pw => word.includes(pw))) positiveCount++;
    if (negativeWords.some(nw => word.includes(nw))) negativeCount++;
  }

  const total = positiveCount + negativeCount;
  
  if (total === 0) {
    return { score: 0, label: 'neutral', confidence: 0.5 };
  }

  const score = (positiveCount - negativeCount) / total;
  const confidence = Math.min(total / 5, 1);

  let label: SentimentResult['label'];
  if (score > 0.2) label = 'positive';
  else if (score < -0.2) label = 'negative';
  else label = 'neutral';

  return { score, label, confidence };
}

// Enhanced moderation with sentiment
function createSentimentRule(): ModerationRule {
  return {
    id: 'negative-sentiment',
    name: 'Negative Sentiment Detector',
    type: 'sentiment',
    action: 'flag',
    enabled: true,
  };
}

Building a Comment Dashboard

Here's a complete example combining all components into a dashboard API:

interface DashboardStats {
  totalComments: number;
  hiddenComments: number;
  repliedComments: number;
  sentimentBreakdown: {
    positive: number;
    neutral: number;
    negative: number;
  };
}

interface CommentWithAnalysis extends InstagramComment {
  sentiment: SentimentResult;
  moderationResult: ModerationResult;
}

class CommentDashboard {
  private accessToken: string;
  private igUserId: string;
  private moderator: CommentModerator;

  constructor(
    accessToken: string,
    igUserId: string,
    moderator: CommentModerator
  ) {
    this.accessToken = accessToken;
    this.igUserId = igUserId;
    this.moderator = moderator;
  }

  async getCommentsWithAnalysis(
    mediaId: string
  ): Promise<CommentWithAnalysis[]> {
    const response = await getMediaComments(this.accessToken, mediaId, {
      limit: 50,
    });

    return response.comments.map(comment => ({
      ...comment,
      sentiment: analyzeSentiment(comment.comment),
      moderationResult: this.moderator.evaluate(comment),
    }));
  }

  async getStats(mediaId: string): Promise<DashboardStats> {
    const comments = await this.getCommentsWithAnalysis(mediaId);

    const stats: DashboardStats = {
      totalComments: comments.length,
      hiddenComments: comments.filter(c => c.hidden).length,
      repliedComments: comments.filter(c => c.replyCount > 0).length,
      sentimentBreakdown: {
        positive: 0,
        neutral: 0,
        negative: 0,
      },
    };

    comments.forEach(c => {
      stats.sentimentBreakdown[c.sentiment.label]++;
    });

    return stats;
  }

  async moderateAll(mediaId: string): Promise<BatchResult> {
    const response = await getMediaComments(this.accessToken, mediaId);
    const processor = new CommentBatchProcessor(this.accessToken);
    return processor.processComments(response.comments, this.moderator);
  }
}

Rate Limits and Quotas

Understanding Instagram's rate limits is crucial for any Instagram comment API integration.

EndpointRate LimitWindow
GET comments200 calls1 hour
POST reply60 calls1 hour
POST hide/unhide60 calls1 hour
DELETE comment60 calls1 hour
Private messages100 calls24 hours

Rate Limit Handler

class RateLimitedClient {
  private requestCounts: Map<string, { count: number; resetTime: number }>;
  private limits: Map<string, { max: number; windowMs: number }>;

  constructor() {
    this.requestCounts = new Map();
    this.limits = new Map([
      ['GET', { max: 200, windowMs: 3600000 }],
      ['POST', { max: 60, windowMs: 3600000 }],
      ['DELETE', { max: 60, windowMs: 3600000 }],
    ]);
  }

  async executeWithRateLimit<T>(
    method: string,
    fn: () => Promise<T>
  ): Promise<T> {
    const limit = this.limits.get(method) || { max: 60, windowMs: 3600000 };
    const key = method;
    const now = Date.now();

    let state = this.requestCounts.get(key);
    
    if (!state || now > state.resetTime) {
      state = { count: 0, resetTime: now + limit.windowMs };
      this.requestCounts.set(key, state);
    }

    if (state.count >= limit.max) {
      const waitTime = state.resetTime - now;
      console.log(`Rate limit reached for ${method}. Waiting ${waitTime}ms`);
      await new Promise(resolve => setTimeout(resolve, waitTime));
      state.count = 0;
      state.resetTime = Date.now() + limit.windowMs;
    }

    state.count++;
    return fn();
  }
}

Late's Comment Management Solution

Building and maintaining a robust Instagram comment moderation system requires significant engineering effort. Token management, rate limiting, error handling, and keeping up with API changes all demand ongoing attention.

Late provides a unified API that handles these complexities for you:

  • Unified Comment API: Manage comments across Instagram, TikTok, YouTube, and more through a single interface
  • Automatic Token Refresh: Never worry about expired tokens again
  • Built-in Rate Limiting: Smart request queuing that respects platform limits
  • Webhook Support: Real-time notifications for new comments
  • Moderation Tools: Pre-built filtering and auto-reply capabilities

Instead of maintaining separate integrations for each platform, Late's SDK lets you focus on building your product:

import { Late } from '@anthropic/late-sdk';

const late = new Late({ apiKey: process.env.LATE_API_KEY });

// Fetch comments from any platform with one API
const comments = await late.comments.list({
  accountId: 'your-instagram-account',
  postId: 'media-id',
});

// Reply works the same across platforms
await late.comments.reply({
  commentId: comments[0].id,
  message: 'Thanks for your comment!',
});

Check out Late's documentation to see how you can simplify your social media integrations and ship faster.

Miquel Palet - Author

Written by

Miquel Palet

Founder & CEO

Miquel is the founder of Late, building the most reliable social media API for developers. Previously built multiple startups and scaled APIs to millions of requests.

View all articles

Learn more about Late with AI

See what AI assistants say about Late API and this topic

One API. 13+ platforms.

Ship social media features in minutes, not weeks.

Built for developers. Loved by agencies. Trusted by 6,325 users.