Skip to main content
RapidDev - Software Development Agency
API AutomationsInstagramOAuth 2.0

How to Automate Instagram Comment Moderation using the API

Automate Instagram comment moderation using the Graph API: list comments with GET /{media-id}/comments, hide them with POST /{comment-id}?hidden=true, delete with DELETE /{comment-id}, and reply with POST /{comment-id}/replies?message=. There is no webhook for new comments — you must poll. The instagram_business_manage_comments scope requires separate App Review approval (2-4 weeks). The 200 calls/hour rate limit requires smart polling intervals across multiple posts.

Need help automating? Talk to an expert
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate7 min read30-60 minutesInstagramMay 2026RapidDev Engineering Team
TL;DR

Automate Instagram comment moderation using the Graph API: list comments with GET /{media-id}/comments, hide them with POST /{comment-id}?hidden=true, delete with DELETE /{comment-id}, and reply with POST /{comment-id}/replies?message=. There is no webhook for new comments — you must poll. The instagram_business_manage_comments scope requires separate App Review approval (2-4 weeks). The 200 calls/hour rate limit requires smart polling intervals across multiple posts.

API Quick Reference

Auth

OAuth 2.0

Rate limit

200 calls/hour per user

Format

JSON

SDK

Available

Understanding the Instagram Comment Moderation API

The Instagram Graph API v25.0 provides full comment moderation capabilities: listing comments, hiding them, deleting them, and replying to them. All operations use the instagram_business_manage_comments OAuth scope, which requires separate App Review submission from the publishing scope. The base URL is https://graph.instagram.com/v25.0.

The critical design constraint for comment moderation automation: Instagram provides no webhook or real-time notification for new comments. You must poll the /comments endpoint on each post at regular intervals to detect new comments. With a 200 calls/hour limit per user and potentially dozens of posts to monitor, you need intelligent polling that prioritizes recent and high-engagement posts rather than polling every post at equal frequency.

The moderation actions themselves are straightforward: hiding a comment (preferred over deleting, as it preserves context while removing visibility) uses POST /{comment-id}?hidden=true, which is reversible. Deleting with DELETE /{comment-id} is permanent. Replies use POST /{comment-id}/replies with a message parameter. Official docs: https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-media/comments

Base URLhttps://graph.instagram.com/v25.0

Setting Up Instagram Comment Moderation Authentication

Comment moderation requires the instagram_business_manage_comments scope, which must be separately approved through Meta App Review. This is distinct from the content publishing scope — even if you have publishing approved, you need a separate review for moderation. During development, add test accounts in App Dashboard > Roles > Test Users.

  1. 1Create or use an existing Business App at developers.facebook.com
  2. 2Add Instagram product if not already added
  3. 3In App Review > Permissions and Features, request instagram_business_basic and instagram_business_manage_comments
  4. 4For the review, prepare a screencast demonstrating your comment moderation use case (keyword filtering, spam detection, etc.)
  5. 5Implement OAuth redirect: https://www.facebook.com/v25.0/dialog/oauth?client_id={app-id}&redirect_uri={uri}&scope=instagram_business_basic,instagram_business_manage_comments
  6. 6Exchange authorization code for short-lived token at https://graph.facebook.com/v25.0/oauth/access_token
  7. 7Exchange for 60-day long-lived token: GET https://graph.instagram.com/access_token?grant_type=fb_exchange_token&client_id={app-id}&client_secret={secret}&fb_exchange_token={short-token}
  8. 8Store token and set up refresh job to run every 50 days
auth.py
1import requests
2import os
3
4IG_USER_ID = os.environ['IG_USER_ID']
5ACCESS_TOKEN = os.environ['IG_ACCESS_TOKEN']
6
7def verify_moderation_access():
8 """Verify comment moderation permissions are active."""
9 # Try to list comments on a recent post to verify access
10 # First get a recent post
11 resp = requests.get(
12 f'https://graph.instagram.com/v25.0/{IG_USER_ID}/media',
13 params={'fields': 'id', 'limit': 1, 'access_token': ACCESS_TOKEN}
14 )
15 resp.raise_for_status()
16 posts = resp.json().get('data', [])
17 if not posts:
18 print('No posts found to test with')
19 return
20 media_id = posts[0]['id']
21 comments_resp = requests.get(
22 f'https://graph.instagram.com/v25.0/{media_id}/comments',
23 params={'fields': 'id,text', 'access_token': ACCESS_TOKEN}
24 )
25 if comments_resp.status_code == 403:
26 raise PermissionError(
27 'Missing instagram_business_manage_comments scope. Submit App Review.'
28 )
29 comments_resp.raise_for_status()
30 print(f'Comment moderation access confirmed. Found {len(comments_resp.json().get("data", []))} comments on test post.')
31
32verify_moderation_access()

Security notes

  • Store access tokens in environment variables — never in source code or logs
  • The manage_comments scope allows hiding and deleting user content — treat it as a privileged operation and audit all actions
  • Log every hide/delete/reply action with comment ID, action type, reason, and timestamp
  • Never automatically delete comments without a human review step for edge cases — prefer hiding as a reversible first action
  • Implement token refresh automation every 50 days
  • Keep keyword and spam filter rules in a separate configuration file that can be updated without code changes

Key endpoints

GET/{ig-media-id}/comments

Returns comments on a specific Instagram post. Includes comment ID, text, username, and can include replies. Supports pagination for posts with many comments.

ParameterTypeRequiredDescription
fieldsstringoptionalUse 'id,text,username,timestamp,replies{id,text,username}' to get comment content, author, and nested replies.
limitnumberoptionalNumber of comments to return per page. Default 10, max 50.

Response

json
1{"data": [{"id": "17858893269000001", "text": "Great post!", "username": "user123", "timestamp": "2026-05-07T10:30:00+0000"}, {"id": "17858893269000002", "text": "Spam comment buy now!!!", "username": "spammer99"}], "paging": {"cursors": {"after": "abc123"}}}
POST/{ig-comment-id}

Hides or unhides a comment. Setting hidden=true makes the comment invisible to everyone except the commenter (they don't know it's hidden). This is reversible — prefer hiding over deletion for borderline content.

ParameterTypeRequiredDescription
hiddenbooleanrequiredSet to true to hide the comment, false to unhide.

Request

json
1{"hidden": true, "access_token": "EAAB..."}

Response

json
1{"success": true}
DELETE/{ig-comment-id}

Permanently deletes a comment. This action cannot be undone — use with caution. Prefer hiding for borderline content.

ParameterTypeRequiredDescription
access_tokenstringrequiredLong-lived token with instagram_business_manage_comments scope.

Response

json
1{"success": true}
POST/{ig-comment-id}/replies

Posts a reply to a comment. The reply appears nested under the original comment. Use for automated responses to questions or welcome messages.

ParameterTypeRequiredDescription
messagestringrequiredThe reply text. Can include @mentions and hashtags. Max 2,200 characters.

Request

json
1{"message": "Thanks for your comment!", "access_token": "EAAB..."}

Response

json
1{"id": "17858893269000003"}

Step-by-step automation

1

Get Recent Posts to Monitor

Why: You cannot monitor all posts equally — fetching your recent posts and prioritizing by recency/engagement lets you stay within the 200 calls/hour quota.

Fetch your most recent posts with basic engagement stats. For moderation purposes, focus on posts published in the last 7-14 days (older posts rarely get new comments) and sort by comment_count to prioritize active discussions. Store the list of posts and their last-polled timestamps to implement smart polling.

request.sh
1curl -s "https://graph.instagram.com/v25.0/${IG_USER_ID}/media?fields=id,timestamp,comments_count&limit=20&access_token=${ACCESS_TOKEN}"

Pro tip: Build a 'polling priority queue' where posts with high comment_count or recent publish time get polled more frequently. A post published 2 hours ago should be polled every 5 minutes; a post from 10 days ago can be polled hourly.

Expected result: Array of posts from the last 14 days sorted by comment count, each with id, timestamp, and comments_count.

2

Fetch and Filter New Comments

Why: Polling all comments every run is wasteful — tracking which comments have already been processed prevents re-processing and preserves quota.

For each post, fetch comments with fields including text and username. Compare against your database of already-processed comment IDs. For new comments, run them through your moderation rules: keyword blocklist for obvious spam/toxicity, and pattern matching for promotional content. Store processed comment IDs to avoid re-checking them.

request.sh
1curl -s "https://graph.instagram.com/v25.0/${MEDIA_ID}/comments?fields=id,text,username,timestamp&limit=50&access_token=${ACCESS_TOKEN}"

Pro tip: Prefer hiding over deletion for borderline content. Hidden comments are still stored in your database and can be reviewed/unhidden later. Permanent deletion is appropriate only for obvious spam or content that violates policy.

Expected result: Each comment classified as 'hide', 'delete', 'reply', or 'ok' based on your moderation rules.

3

Execute Moderation Actions

Why: Hiding or deleting comments requires separate API calls per comment — batch them efficiently to minimize quota usage.

For each classified comment: hide it (POST /{comment-id}?hidden=true), delete it (DELETE /{comment-id}), or reply to it (POST /{comment-id}/replies?message=...). Add a small delay between actions to avoid triggering rate limits. Log every action with comment ID, action type, and reason.

request.sh
1# Hide a comment
2curl -X POST \
3 "https://graph.instagram.com/v25.0/${COMMENT_ID}?hidden=true&access_token=${ACCESS_TOKEN}"
4
5# Delete a comment
6curl -X DELETE \
7 "https://graph.instagram.com/v25.0/${COMMENT_ID}?access_token=${ACCESS_TOKEN}"
8
9# Reply to a comment
10curl -X POST \
11 "https://graph.instagram.com/v25.0/${COMMENT_ID}/replies" \
12 -d "message=Thanks for your question!" \
13 -d "access_token=${ACCESS_TOKEN}"

Pro tip: Use a daily moderation summary report: count total comments reviewed, hidden, deleted, and replied to. This helps tune your keyword filters and identify trending spam patterns.

Expected result: Array of action results logging what was done to each comment. Spam is hidden/deleted, questions receive automated replies.

Complete working code

Complete comment moderation bot: fetches recent posts, polls for new comments since last run, classifies them using keyword and URL detection rules, executes moderation actions, and logs all decisions. Runs as a cron job every 15 minutes.

automate_ig_moderation.py
1#!/usr/bin/env python3
2"""Instagram Comment Moderation Bot - runs every 15 minutes via cron."""
3import os
4import re
5import time
6import json
7import logging
8import requests
9from datetime import datetime, timedelta, timezone
10
11logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
12log = logging.getLogger(__name__)
13
14IG_USER_ID = os.environ['IG_USER_ID']
15ACCESS_TOKEN = os.environ['IG_ACCESS_TOKEN']
16STATE_FILE = '/tmp/ig_moderation_state.json'
17BASE = 'https://graph.instagram.com/v25.0'
18
19BLOCKLIST = ['spam', 'buy now', 'dm me', 'follow for follow', 'click link', 'free money', 'earn from home']
20URL_RE = re.compile(r'https?://|bit\.ly|t\.me|wa\.me', re.I)
21
22def ig_get(path, params):
23 params['access_token'] = ACCESS_TOKEN
24 r = requests.get(f'{BASE}{path}', params=params, timeout=30)
25 r.raise_for_status()
26 return r.json()
27
28def load_state():
29 try:
30 with open(STATE_FILE) as f:
31 return json.load(f)
32 except FileNotFoundError:
33 return {'processed_ids': [], 'last_run': None}
34
35def save_state(state):
36 with open(STATE_FILE, 'w') as f:
37 json.dump(state, f)
38
39def get_recent_posts():
40 data = ig_get(f'/{IG_USER_ID}/media', {'fields': 'id,timestamp,comments_count', 'limit': 20})
41 cutoff = datetime.now(timezone.utc) - timedelta(days=14)
42 posts = [p for p in data['data'] if datetime.fromisoformat(p['timestamp'].replace('Z', '+00:00')) > cutoff]
43 return sorted(posts, key=lambda p: p.get('comments_count', 0), reverse=True)[:10]
44
45def classify(text):
46 lower = text.lower()
47 if URL_RE.search(text) and any(k in lower for k in BLOCKLIST):
48 return 'delete'
49 if any(k in lower for k in BLOCKLIST):
50 return 'hide'
51 return 'ok'
52
53def moderate():
54 state = load_state()
55 processed = set(state.get('processed_ids', []))
56 posts = get_recent_posts()
57 total_actions = 0
58 for post in posts:
59 comments_data = ig_get(f'/{post["id"]}/comments', {'fields': 'id,text,username', 'limit': 50})
60 for comment in comments_data.get('data', []):
61 if comment['id'] in processed:
62 continue
63 processed.add(comment['id'])
64 action = classify(comment.get('text', ''))
65 if action == 'hide':
66 try:
67 requests.post(f'{BASE}/{comment["id"]}', params={'hidden': 'true', 'access_token': ACCESS_TOKEN}, timeout=10)
68 log.info(f'Hidden comment {comment["id"]} from @{comment["username"]}')
69 total_actions += 1
70 except Exception as e:
71 log.error(f'Hide failed: {e}')
72 elif action == 'delete':
73 try:
74 requests.delete(f'{BASE}/{comment["id"]}', params={'access_token': ACCESS_TOKEN}, timeout=10)
75 log.info(f'Deleted comment {comment["id"]} from @{comment["username"]}')
76 total_actions += 1
77 except Exception as e:
78 log.error(f'Delete failed: {e}')
79 time.sleep(0.3)
80 time.sleep(0.5) # Between posts
81 # Keep only last 10k IDs to prevent state file bloat
82 state['processed_ids'] = list(processed)[-10000:]
83 state['last_run'] = datetime.now(timezone.utc).isoformat()
84 save_state(state)
85 log.info(f'Run complete: {total_actions} actions taken')
86 return total_actions
87
88if __name__ == '__main__':
89 moderate()

Error handling

403{"error":{"code":10,"message":"Application does not have permission for this action","type":"OAuthException"}}
Cause

The instagram_business_manage_comments permission is not approved for your app or the account is not a Test User in Development mode.

Fix

Submit instagram_business_manage_comments for App Review with a screencast showing comment moderation use case. In development, add the Instagram account as a Test User via App Dashboard > Roles > Test Users.

Retry strategy

Do not retry — resolve App Review first.

400{"error":{"code":17,"message":"User request limit reached","type":"OAuthException"}}
Cause

Exceeded 200 API calls per hour. Comment moderation involving multiple posts and many comments per post is the primary cause — each comment fetch, hide, and delete is a separate API call.

Fix

Reduce polling frequency. Monitor only top 10 posts. Add 300-500ms delays between moderation actions. Check X-Business-Use-Case-Usage header and pause operations when call_count exceeds 80%.

Retry strategy

Exponential backoff starting at 60 seconds.

400{"error":{"code":100,"message":"Invalid parameter","type":"OAuthException"}}
Cause

The comment ID does not exist (already deleted by user, or the post was deleted) or the hidden parameter was passed incorrectly.

Fix

Catch this error and mark the comment as already handled in your state file. Don't retry — the comment is gone.

Retry strategy

Do not retry — mark as processed and continue.

400{"error":{"code":190,"message":"Invalid OAuth access token","type":"OAuthException"}}
Cause

The 60-day long-lived access token has expired or the user revoked app permissions.

Fix

Refresh via GET https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token={token}. If fully expired, re-authorize via OAuth.

Retry strategy

Do not retry — refresh or re-authorize first.

Rate Limits for Instagram Comment Moderation API

ScopeLimitWindow
Per user (app+user pair)200 API callsper hour (rolling)
Private replies on comments750 private repliesper hour per business account
retry-handler.ts
1import time
2import requests
3
4def safe_moderation_call(method, url, max_retries=3, **kwargs):
5 for attempt in range(max_retries):
6 r = getattr(requests, method)(url, timeout=20, **kwargs)
7 if r.status_code == 400:
8 code = r.json().get('error', {}).get('code')
9 if code in (17, 4, 32):
10 wait = 60 * (2 ** attempt)
11 print(f'Rate limited. Waiting {wait}s')
12 time.sleep(wait)
13 continue
14 if code == 100: # Comment deleted by user
15 return None
16 return r
17 raise Exception('Rate limit retries exceeded')
  • Budget your 200 calls/hour: 10 posts × 1 comment fetch = 10 calls; remaining 190 calls = budget for up to 190 moderation actions per hour
  • Use a processed comment ID cache to avoid re-fetching and re-classifying the same comments on every run
  • Poll recent posts (last 7 days) more frequently than older posts — most toxic comments arrive within hours of posting
  • Add 300-500ms delays between each moderation action (hide/delete/reply) to avoid triggering secondary rate limits
  • Log all moderation actions to a database to build a training dataset for improving your keyword filters over time

Security checklist

  • Store access tokens in environment variables — never in source code or version control
  • Log every moderation action (comment ID, action type, reason, timestamp) in an immutable audit log
  • Never auto-delete comments without a confidence threshold — use hiding as the default action and review hidden comments periodically
  • Keep your keyword blocklist in a configuration file that can be updated without a deployment
  • Implement a review queue for borderline cases rather than making binary hide/delete decisions automatically
  • Ensure the instagram_business_manage_comments scope is only used in your backend — never expose the token to frontend code
  • Rotate access tokens if your server is compromised and notify the account owner to review recent moderation actions

Automation use cases

Spam Comment Filter

intermediate

Automatically hide or delete comments matching keyword patterns (URLs, promotional phrases, follow-for-follow), running every 15 minutes across all active posts.

Auto-Reply to FAQs

intermediate

Detect common question patterns (shipping, pricing, availability) in comments and automatically post a helpful reply template, reducing manual response time.

Competitor Mention Monitor

beginner

Alert moderators when comments mention competitor brand names, allowing quick human response rather than automated action.

Multi-Account Moderation Dashboard

advanced

Aggregate comments across multiple Instagram Business accounts into a single moderation queue with bulk action capabilities.

No-code alternatives

Don't want to write code? These platforms can automate the same workflows visually.

Zapier

Free tier (limited); Starter from $19.99/month

Zapier can monitor Instagram comments and trigger moderation workflows in other tools, though direct comment hiding/deletion requires API credentials.

Pros
  • + No code required for alerting workflows
  • + Can route flagged comments to Slack for human review
  • + Easy to set up
Cons
  • - Cannot directly hide/delete comments without custom code step
  • - Higher cost for frequent polling
  • - Limited moderation logic

Make (formerly Integromat)

Free tier (1,000 ops/month); Core from $9/month

Make's Instagram module supports comment operations with more complex filtering logic than Zapier and lower per-operation costs.

Pros
  • + More affordable than Zapier
  • + Complex conditional routing
  • + Better for bulk operations
Cons
  • - Same API limitations
  • - Steeper learning curve
  • - Meta App Review still required

n8n

Free (self-hosted); Cloud from $20/month

n8n self-hosted allows building complete moderation pipelines with HTTP request nodes, custom JavaScript for classification, and database logging.

Pros
  • + Free self-hosted
  • + Full control over moderation logic
  • + Can integrate with ML spam classifiers
Cons
  • - Requires server infrastructure
  • - More setup than no-code tools
  • - Instagram node has limited comment support

Best practices

  • Prefer hiding over deleting for borderline content — hidden comments can be reviewed and unhidden, while deleted comments are permanent
  • Build a state file or database tracking processed comment IDs to prevent re-processing the same comments on every polling run
  • Never make fully automated permanent deletions on high-confidence-only content — even the best keyword filters produce false positives
  • Poll recent posts (published in last 48 hours) every 5-10 minutes; poll older posts much less frequently (hourly or less) to stay within rate limits
  • Log all moderation actions with the original comment text, applied rule, and timestamp — this creates a training dataset for improving rules
  • Set up a human review queue for comments that score borderline on your classifier, rather than making automated decisions on uncertain cases
  • Test your blocklist and rules against historical comment data before deploying to avoid accidentally hiding legitimate comments at launch

Ask AI to help

Copy one of these prompts to get a personalized, working implementation.

ChatGPT / Claude Prompt

I'm building an Instagram comment moderation bot using the Instagram Graph API v25.0. The bot fetches comments via GET /{media-id}/comments?fields=id,text,username, classifies them using keyword matching, then calls POST /{comment-id}?hidden=true to hide spam. My current keyword list is too broad — I'm hiding legitimate comments. Help me: 1) build a better comment classifier that uses contextual rules (URL + keyword = spam, but URL alone = maybe legitimate), 2) implement a confidence score system with thresholds for auto-hide vs. human-review vs. auto-delete, 3) structure the polling scheduler to prioritize high-engagement recent posts within the 200 calls/hour limit.

Lovable / V0 Prompt

Build a React comment moderation dashboard for Instagram. It needs: a queue view showing unreviewed flagged comments with their post thumbnail, commenter username, comment text, and AI-assigned spam score; bulk action buttons (Hide All Spam, Approve All) and per-comment actions (Hide, Delete, Approve, Reply); a filter panel to show comments by post, action status, and score threshold; a reply composer for selected comments; and a statistics card showing comments reviewed today, hidden, deleted, and auto-approved. Use Supabase to store the moderation queue and Supabase Edge Functions to call the Instagram API.

Frequently asked questions

Is there a webhook for new Instagram comments so I don't have to poll?

No — the Instagram Graph API does not provide webhooks for new comments. You must poll GET /{media-id}/comments at regular intervals to detect new comments. The Meta Webhooks product covers some Instagram events (mentions, story interactions) but comment webhooks are not available for most Business accounts. Design your polling with smart prioritization (recent posts more frequently) to stay within the 200 calls/hour limit.

What's the difference between hiding and deleting a comment?

Hiding (POST /{comment-id}?hidden=true) makes a comment invisible to all users except the original commenter, who does not know their comment is hidden. The comment still exists in the API and can be unhidden by setting hidden=false. Deleting (DELETE /{comment-id}) permanently removes the comment — it cannot be recovered. Best practice: hide borderline content first, review it periodically, and only delete clearly harmful content.

What happens when I hit the 200 calls/hour rate limit?

You'll receive HTTP 400 with error code 17 (User request limit reached). Each API operation — fetching comments, hiding, deleting, replying — consumes one call. For a bot monitoring 10 posts with 50 comments each per run, that's already 10 calls just for fetching. Implement a processed-ID cache so you don't re-fetch already-reviewed comments, and use exponential backoff (starting at 60 seconds) when rate limited.

Can I automate comment replies at scale?

Yes, but with care. The API allows replies via POST /{comment-id}/replies?message=. Meta monitors for automated or repetitive replies and can flag your account for spam-like behavior. Keep reply messages varied, reply only to genuine questions (not all comments), and limit reply volume to what would be human-realistic for your account size. Also note the 750 private replies per hour limit for business accounts.

Do I need a separate App Review for comment moderation vs. post publishing?

Yes. The instagram_business_manage_comments scope requires a separate App Review submission from instagram_business_content_publish. Even if you already have publishing approved, you must submit a new review specifically for the manage_comments permission, including a new screencast demonstrating your comment moderation use case. Each review typically takes 2-4 weeks.

Can RapidDev build an Instagram comment moderation bot?

Yes — RapidDev has built comment moderation systems combining keyword filtering, ML-based spam detection, and human review queues for brand accounts. We handle the Meta App setup and approval process, build the classification logic, and deliver a moderation dashboard. Book a free consultation at rapidevelopers.com.

Can I use AI (like OpenAI or Claude) to classify Instagram comments?

Yes, and it's much more effective than keyword matching alone. After fetching comments, send each comment text to an LLM with a classification prompt (rate this comment: spam, toxic, promotional, question, positive, neutral) and use the response to drive moderation decisions. LLM classification is especially good at catching sophisticated spam that bypasses simple keyword lists. Budget for API costs: at roughly 50 comments per post and $0.001/classification with a cheap model, the costs are minimal.

RapidDev

Need this automated?

Our team has built 600+ apps with API automations. We can build this for you.

Book a free consultation

Skip the coding — we'll build it for you

Our experts have built 600+ API automations. From prototype to production in days, not weeks.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.