Skip to content
DMpop

Instagram comment webhook not working

No commentwebhooks?Check these.

If no comment webhooks arrive at all, it's almost always setup: Meta only sends comments notifications to a Live app with Advanced Access, for a public professional account your app has subscribed with subscribed_apps. If most arrive but a few don't, that's Instagram: some comments never fire a webhook, so you need a polling fallback.

Updated

Meta · subscribe an account
# Subscribe your app to one account's comments# (Instagram API with Instagram Login, from Meta's webhook setup guide)curl -i -X POST "https://graph.instagram.com/v27.0/<IG_ID>/subscribed_apps?subscribed_fields=comments,messages&access_token=<INSTAGRAM_USER_ACCESS_TOKEN>"# Success{ "success": true }

Instagram webhooks not firing at all: Meta's requirements

Nothing arrives.Start here.

Every row is a requirement from Meta's own Instagram Platform docs. Miss one and comment notifications never reach your callback, even if the dashboard's Test button works.

Meta's requirements for Instagram comment webhooks
RequirementWhat Meta saysSource
A Live appMeta: “Your app must be published or Live to receive notifications for app users.”Webhooks setup
Advanced Access“Advanced Access is required for comments and live_comments notifications.” Advanced Access needs App Review and Business Verification.Webhooks setup, Overview
A public account“The account that owns the media must be public. Private accounts do not receive comment or mention notifications.”Webhooks setup
A professional accountBusiness or Creator. The API doesn't serve personal accounts.Overview
The field selected for the appTick comments in the App Dashboard. Every subscribed account gets every field you select; you can't pick per account.Webhooks setup
The app subscribed on the accountA POST /<IG_ID>/subscribed_apps with subscribed_fields, using that account's token. Returns {"success": true}.Webhooks setup
The right permissionsInstagram Login: instagram_business_basic + instagram_business_manage_comments. Facebook Login: instagram_basic, instagram_manage_comments and the Pages permissions.Webhook fields
A token that matches the setupInstagram Login uses an Instagram user token on graph.instagram.com. Facebook Login and the newer Unified Login use graph.facebook.com. Mixing them fails.Webhooks setup
A verified HTTPS callbackYour callback must pass Meta's verification request and serve a valid certificate. Self-signed certificates aren't supported.Webhooks setup

Quotes from Meta's developer documentation, checked 9 November 2026. Meta's setup guide also lists its own troubleshooting checklist, which this page follows. DMpop is not affiliated with Meta or Instagram.

Instagram comment webhook setup mistakes

Set up, butstill silent.

These pass the dashboard and still lose events. Most are in the callback itself.

The verification request returns JSON

Meta sends a GET with hub.mode=subscribe, hub.verify_token and hub.challenge. Check the token matches the one in the App Dashboard, then respond with the hub.challenge value itself. A JSON wrapper or a 403 means the callback never saves.

Signature checked on parsed JSON

Meta signs every payload with SHA256 and sends it in X-Hub-Signature-256 as sha256=<hex>. Compute the HMAC over the raw request bytes. Parsing and re-serialising the body changes the bytes, so every check fails and your server answers 401 to real events. Meta's guide says to use your app's App Secret; an Instagram Login app shows two secrets, and the doc doesn't say which. Our own handler accepts a match on either.

Slow work before the 200

Meta's setup guide asks for 200 OK over HTTPS and says to return success “before it starts slow work”. No timeout is published, so don't find it the hard way. Acknowledge, then queue the comment. A failed delivery is retried immediately, then a few more times over the next 36 hours, then dropped.

No dedupe

Notifications come in batches of up to 1,000 updates, batching isn't guaranteed, and the same event can arrive twice. Meta's private replies guide also warns that comments on boosted or ad posts may produce duplicate notifications. Key your work on the comment ID. For a comment-to-DM app this matters twice over: a comment gets only one private reply.

Testing with your own account

Comment from a second account. You can't send a private reply to yourself, so a handler that skips the account's own comments (as it should) looks broken when you test alone.

Ads and Live

A comment on a boosted post can arrive with the ad's media ID and an original_media_id pointing at the organic post. Match on both, or ad comments look like they never came. Live comments use a separate field, live_comments, and stop when the broadcast ends.

Instagram webhook handler example in Node.js

A handlerthat holds up.

Verification, signature check on raw bytes, acknowledge first, filter to comments, skip your own, dedupe by ID. Everything Meta's guide asks for, nothing else.

Node 18+ · webhook endpoint
// Node 18+, no dependencies. One endpoint for Meta's// verification request (GET) and event notifications (POST).import { createServer } from "node:http";import { createHmac, timingSafeEqual } from "node:crypto";const VERIFY_TOKEN = process.env.META_VERIFY_TOKEN;const APP_SECRET = process.env.META_APP_SECRET;const seen = new Set(); // use your database in productionfunction signatureOk(raw, header) {  if (typeof header !== "string") return false;  const expected = Buffer.from(    "sha256=" + createHmac("sha256", APP_SECRET).update(raw).digest("hex")  );  const got = Buffer.from(header);  return got.length === expected.length && timingSafeEqual(got, expected);}createServer((req, res) => {  const url = new URL(req.url, "https://example.com");  // 1. Verification: echo hub.challenge as plain text  if (req.method === "GET") {    const ok =      url.searchParams.get("hub.mode") === "subscribe" &&      url.searchParams.get("hub.verify_token") === VERIFY_TOKEN;    res.writeHead(ok ? 200 : 403, { "Content-Type": "text/plain" });    res.end(ok ? url.searchParams.get("hub.challenge") : "");    return;  }  // 2. Notifications: sign-check the raw bytes, not re-serialised JSON  const chunks = [];  req.on("data", (chunk) => chunks.push(chunk));  req.on("end", () => {    const raw = Buffer.concat(chunks);    if (!signatureOk(raw, req.headers["x-hub-signature-256"])) {      res.writeHead(401).end();      return;    }    // 3. Acknowledge first. Slow work goes to a queue.    res.writeHead(200).end("EVENT_RECEIVED");    const body = JSON.parse(raw.toString("utf8"));    if (body.object !== "instagram") return;    for (const entry of body.entry ?? []) {      for (const change of entry.changes ?? []) {        if (change.field !== "comments") continue;        const c = change.value;        if (!c?.id || c.from?.id === entry.id) continue; // your own comment        if (seen.has(c.id)) continue; // Meta can deliver twice        seen.add(c.id);        enqueue({          accountId: entry.id,          commentId: c.id,          text: c.text ?? "",          userId: c.from?.id,          mediaId: c.media?.id,        });      }    }  });}).listen(3000);function enqueue(job) {  console.log("comment", job); // hand off to your worker here}

The payload for Instagram Login looks like Meta's comments example: object: "instagram", then entry[].changes[] with field: "comments" and a value holding id, text, from.id, from.username and media.id. entry[].id is the account that owns the post.

In production, swap the Set for a unique index on comment ID, and put a queue between the handler and anything that calls Meta. Then a slow private reply or a rate limit never delays the 200.

On a serverless host, “respond, then keep working” may not survive the function freezing. Write the event to a queue or table before you respond, and do the rest in a worker.

Sending the DM is the next step: a private reply to the comment ID. The errors it can return are on Instagram API errors.

Instagram webhook missing some comments

Most arrive.Some never do.

Here the setup is fine and Meta still doesn't send everything. Meta documents some of the gaps. Others it doesn't, and those come from what we see running DMpop.

Documented by Meta

  • Comments on media owned by a private account.
  • Live comments after the broadcast ends.
  • The webhooks overview adds that there's no history: “Webhooks do not provide a historical notification store”. A missed event isn't replayed later.

What we see in practice

  • Collapsed comments, the ones behind “load more” on a busy post.
  • Some comments from non-followers and low-signal accounts.
  • Comments Instagram filters.
  • Comments removed by the account's Hidden Words or spam filter. These may not come back from the comments API either, so polling can't see them. Relaxing that filter in Instagram's settings widens what any tool can catch.

Meta doesn't publish this second list, and it can change. Treat comment webhooks as fast but best-effort, and close the gap with polling.

Polling fallback for missed Instagram comments

Poll to catchwhat's missed.

DMpop runs a narrow sweep next to its webhooks. Here's how it works, so you can build the same.

  1. Every 5 minutes, for each active campaign, read its post's recent comments, newest first, with each comment's replies.
  2. Look back 72 hours. A private reply must go out within 7 days of the comment, so older comments aren't worth the calls.
  3. Keep a comment only if it matches the keyword, isn't the account's own, and has no reply from the account yet.
  4. Skip anything already in the log, so a comment the webhook delivered isn't sent twice.
  5. Oldest first, 30 at most per campaign per sweep. The rest wait for the next sweep.
Meta · recent comments with replies
# The fallback: recent comments on one post, with repliescurl "https://graph.instagram.com/v27.0/<IG_MEDIA_ID>/comments?fields=id,text,timestamp,from,replies{from}&limit=50" \  -H "Authorization: Bearer <INSTAGRAM_USER_ACCESS_TOKEN>"

Why the cap: the comments API is rate limited, and Meta's comment moderation guide says it “strongly” recommends webhooks to avoid that. When we hit the limit, Meta answers with error code 368, which we treat as a rate limit and retry later. Polling is the safety net, not the main path.

Those numbers are DMpop's defaults, not Meta rules. Tune them to your volume.

Instagram webhook debugging checklist

Ten checks,in order.

  1. Press Test next to comments in the App Dashboard. No request at your server? It's the callback URL, HTTPS or verification.
  2. Check your logs for 401s. A signature mismatch looks exactly like “Meta stopped sending”.
  3. Confirm the app is Live, not in Development mode.
  4. Confirm Advanced Access for the comments permission. It needs App Review and Business Verification.
  5. Confirm the account is a public Business or Creator account.
  6. Call POST /<IG_ID>/subscribed_apps again with subscribed_fields=comments and that account's current token. Expect {"success": true}.
  7. Check the token's host: graph.instagram.com for Instagram Login, graph.facebook.com for Facebook or Unified Login.
  8. Comment from a different account, on a post the account owns, with a plain word.
  9. Check you return 200 before doing any work, and that nothing upstream (a proxy, a WAF, a bot filter) blocks Meta's requests.
  10. Still missing a few? Compare against GET /<IG_MEDIA_ID>/comments. Present there but no webhook: add polling. Absent there too: check Hidden Words.

Or skip the plumbing

Already built.One API call.

If what you need is comment-to-DM inside your own product or script, DMpop already runs the webhooks, the polling fallback, dedupe, the 750-an-hour queue and the logs on its approved Meta app. Your code creates a campaign with one request to the REST API, or an assistant does it through the MCP server. Full reference in the developer docs.

Building it yourself? Read Instagram API permissions and Meta App Review for Instagram next, then Instagram DM limits.

Questions

Webhook questions,answered.

Why am I not getting Instagram comment webhooks at all?

Check Meta's requirements in order: the app is Live, it has Advanced Access (comment notifications need it), the account is a public professional account, comments is selected in the App Dashboard, and you called POST /<IG_ID>/subscribed_apps for that account with comments in subscribed_fields. If the Test button works but real comments don't, the account subscription or access level is the usual gap.

Do Instagram comment webhooks work in Development mode?

Meta's setup guide says the app must be published, or Live, to receive notifications for app users, and that comments and live_comments notifications need Advanced Access. Plan on testing real comment delivery with a Live app.

Why do some comments arrive and others don't?

Meta doesn't send a webhook for every comment. In our experience the gaps are collapsed 'load more' comments, some comments from non-followers or low-signal accounts, and comments Instagram filters. Meta doesn't document this list, so treat webhooks as best-effort and poll recent comments as a fallback.

Which secret signs Instagram webhooks?

Meta's guide says the payload is signed with SHA256 using your app's App Secret, sent in the X-Hub-Signature-256 header as sha256=<hex>. An app using Instagram Login shows both a Meta app secret and an Instagram app secret in the dashboard, and the doc doesn't say which one applies. DMpop's own handler accepts a match on either.

How fast must my webhook endpoint respond?

Meta asks for a 200 OK over HTTPS and says to return success before you start slow work. It doesn't publish a timeout. Failed deliveries are retried immediately, then a few more times over 36 hours, and dropped after that.

Can I get a webhook for comments on my own posts that I write?

Your own comments can arrive, but you can't send a private reply to yourself. Skip comments where from.id equals the account's ID, and test with a second Instagram account.

Do comments on boosted posts and ads send webhooks?

Yes. They can arrive with the ad's media ID, plus original_media_id pointing at the organic post, so match on both. Meta also notes that comments on boosted or ad posts may produce duplicate notifications, so dedupe by comment ID.

API on every plan

Skip the webhooks.Let the DM pop.

DMpop runs the webhooks and the polling safety net for you. Get an API key on any plan: Free sends 1,000 DMs a month, and paid plans start at ₹99.