This workflow corresponds to n8n.io template #16300 — we link there as the canonical source.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "Auto-reply to Instagram and Facebook comments with a public reply and DM",
"nodes": [
{
"id": "webhook",
"name": "Webhook (Meta)",
"type": "n8n-nodes-base.webhook",
"onError": "continueRegularOutput",
"position": [
0,
400
],
"parameters": {
"path": "meta-auto-reply",
"options": {},
"responseMode": "responseNode",
"multipleMethods": true
},
"typeVersion": 2.1
},
{
"id": "config",
"name": "Configuration (EDIT ME)",
"type": "n8n-nodes-base.set",
"position": [
300,
400
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "c1",
"name": "access_token",
"type": "string",
"value": "PASTE_YOUR_ACCESS_TOKEN_HERE"
},
{
"id": "c2",
"name": "verify_token",
"type": "string",
"value": "my-secret-token-123"
},
{
"id": "c3",
"name": "keyword",
"type": "string",
"value": ""
},
{
"id": "c4",
"name": "comment_reply",
"type": "string",
"value": "Thanks for the comment! \ud83d\ude4c Check your DMs \ud83d\udce9"
},
{
"id": "c5",
"name": "dm_message",
"type": "string",
"value": "Hey! Thanks for commenting. Here's the link I promised: https://your-website.com \ud83d\ude80"
},
{
"id": "c6",
"name": "api_version",
"type": "string",
"value": "23.0"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "verify",
"name": "Meta Verification?",
"type": "n8n-nodes-base.if",
"position": [
600,
400
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "is-subscribe",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.query ? ($json.query['hub.mode'] || '') : '' }}",
"rightValue": "subscribe"
},
{
"id": "token-matches",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.query ? ($json.query['hub.verify_token'] || '') : '' }}",
"rightValue": "={{ $json.verify_token }}"
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "respond-challenge",
"name": "Respond hub.challenge",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
900,
240
],
"parameters": {
"options": {},
"respondWith": "text",
"responseBody": "={{ $json.query['hub.challenge'] }}"
},
"typeVersion": 1.4
},
{
"id": "respond-200",
"name": "Respond 200 OK",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
900,
400
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "noData"
},
"typeVersion": 1.4
},
{
"id": "extract",
"name": "Extract Comment",
"type": "n8n-nodes-base.code",
"position": [
1200,
400
],
"parameters": {
"jsCode": "// Extracts IG/FB comments from the Meta webhook payload and builds\n// ready-to-use Graph API requests (public reply + private DM).\n// Skips: own comments (echo / auto-replies) and comments that don't\n// match the keyword filter (if set).\nconst item = $input.first().json;\nconst body = item.body || {};\nif (!body.entry || (body.object !== 'instagram' && body.object !== 'page')) return [];\n\nconst normalize = (t) => (t || '').toLowerCase().trim().replace(/\\s+/g, '');\nconst keyword = normalize(item.keyword);\nconst out = [];\n\nfor (const entry of body.entry) {\n const accountId = String(entry.id);\n for (const change of entry.changes || []) {\n const v = change.value || {};\n let commentId, text, fromId, fromName, platform;\n\n if (body.object === 'instagram' && change.field === 'comments') {\n platform = 'instagram';\n commentId = v.id;\n text = v.text || '';\n fromId = v.from && v.from.id;\n fromName = (v.from && v.from.username) || '';\n } else if (body.object === 'page' && change.field === 'feed' && v.item === 'comment' && v.verb === 'add') {\n platform = 'facebook';\n commentId = v.comment_id;\n text = v.message || '';\n fromId = v.from && v.from.id;\n fromName = (v.from && v.from.name) || '';\n } else {\n continue; // other events (DMs, likes, stories etc.) are ignored\n }\n\n if (!commentId || !fromId) continue;\n if (String(fromId) === accountId) continue; // own comment -> loop protection\n if (keyword && !normalize(text).includes(keyword)) continue;\n\n const host = platform === 'instagram' ? 'graph.instagram.com' : 'graph.facebook.com';\n const base = `https://${host}/v${item.api_version}`;\n\n const replyText = item.comment_reply || '';\n const dmText = item.dm_message || '';\n\n out.push({\n json: {\n platform,\n account_id: accountId,\n comment_id: commentId,\n comment_text: text,\n from_id: String(fromId),\n from_name: fromName,\n // ready-to-use request: public reply under the comment\n reply_url: replyText\n ? (platform === 'instagram' ? `${base}/${commentId}/replies` : `${base}/${commentId}/comments`)\n : '',\n reply_payload: { message: replyText },\n // ready-to-use request: private message (private reply)\n dm_url: dmText ? `${base}/${accountId}/messages` : '',\n dm_payload: { recipient: { comment_id: commentId }, message: { text: dmText } },\n },\n });\n }\n}\nreturn out;"
},
"typeVersion": 2
},
{
"id": "if-comment",
"name": "Send Public Reply?",
"type": "n8n-nodes-base.if",
"position": [
1500,
240
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "has-if-comment",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.reply_url }}",
"rightValue": ""
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "if-dm",
"name": "Send DM?",
"type": "n8n-nodes-base.if",
"position": [
1500,
560
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "has-if-dm",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.dm_url }}",
"rightValue": ""
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "http-comment",
"name": "Reply to Comment",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
1800,
240
],
"parameters": {
"url": "={{ $json.reply_url }}",
"method": "POST",
"options": {},
"jsonBody": "={{ $json.reply_payload }}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $('Configuration (EDIT ME)').first().json.access_token }}"
}
]
}
},
"typeVersion": 4.3
},
{
"id": "http-dm",
"name": "Send DM (private reply)",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
1800,
560
],
"parameters": {
"url": "={{ $json.dm_url }}",
"method": "POST",
"options": {},
"jsonBody": "={{ $json.dm_payload }}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $('Configuration (EDIT ME)').first().json.access_token }}"
}
]
}
},
"typeVersion": 4.3
},
{
"id": "Sticky Note",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-60,
-500
],
"parameters": {
"color": 1,
"width": 600,
"height": 600,
"content": "## Auto-Reply to Instagram & Facebook Comments\n\nAutomatically reply under new Instagram or Facebook comments and send the commenter a private DM \u2014 no database, no queue, no third-party tool like ManyChat.\n\n### How it works\n- A **webhook** receives comment events from the Meta Graph API and answers Meta's verification handshake.\n- The workflow responds `200 OK` immediately, then parses the event, skips your own comments (loop protection) and any comment that does not match your optional keyword.\n- It posts a public reply under the comment and sends a private message, each via the Meta Graph API.\n\n### Setup\n1. Open **Configuration (EDIT ME)** and fill in your `access_token`, a `verify_token` of your choice, an optional `keyword`, and your reply + DM text.\n2. Activate the workflow and copy the **Production URL** from the *Webhook (Meta)* node.\n3. In your Meta app, add it as a webhook with the same `verify_token` and subscribe to `comments` (Instagram) and/or `feed` (Facebook Page). The app must be in **Live** mode.\n\n### Customization tips\nLeave the reply or DM text empty to skip that step. Set a keyword to trigger only on matching comments.\n"
},
"typeVersion": 1
},
{
"id": "Sticky Note1",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-60,
160
],
"parameters": {
"color": 7,
"width": 1140,
"height": 420,
"content": "## 1. Receive & verify the webhook\nMeta sends comment events here. The IF answers Meta's one-time verification (hub.challenge); every real event gets an immediate 200 OK. Add your tokens and reply text in **Configuration (EDIT ME)**.\n"
},
"typeVersion": 1
},
{
"id": "Sticky Note2",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1140,
160
],
"parameters": {
"color": 7,
"width": 860,
"height": 580,
"content": "## 2. Reply to the comment & send a DM\nParses the comment, skips your own (loop protection) and non-matching keywords, then posts a public reply and a private DM through the Meta Graph API.\n"
},
"typeVersion": 1
}
],
"settings": {
"executionOrder": "v1"
},
"connections": {
"Send DM?": {
"main": [
[
{
"node": "Send DM (private reply)",
"type": "main",
"index": 0
}
],
[]
]
},
"Respond 200 OK": {
"main": [
[
{
"node": "Extract Comment",
"type": "main",
"index": 0
}
]
]
},
"Webhook (Meta)": {
"main": [
[
{
"node": "Configuration (EDIT ME)",
"type": "main",
"index": 0
}
],
[
{
"node": "Configuration (EDIT ME)",
"type": "main",
"index": 0
}
]
]
},
"Extract Comment": {
"main": [
[
{
"node": "Send Public Reply?",
"type": "main",
"index": 0
},
{
"node": "Send DM?",
"type": "main",
"index": 0
}
]
]
},
"Meta Verification?": {
"main": [
[
{
"node": "Respond hub.challenge",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond 200 OK",
"type": "main",
"index": 0
}
]
]
},
"Send Public Reply?": {
"main": [
[
{
"node": "Reply to Comment",
"type": "main",
"index": 0
}
],
[]
]
},
"Configuration (EDIT ME)": {
"main": [
[
{
"node": "Meta Verification?",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow receives Meta webhooks for Instagram and Facebook Page comments, verifies the webhook subscription handshake, and then posts an optional public reply and/or sends a private DM to the commenter via the Meta Graph API. Receives an incoming webhook request from Meta…
Source: https://n8n.io/workflows/16300/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
A powerful workflow to scrape Reddit posts and comments by keywords and/or subreddit, with intelligent filtering and formatting. Search Reddit - Accepts keywords and/or subreddit parameters via webhoo
This n8n workflow is an automated Instagram DM responder that checks messages and replies with affiliate links based on keywords.
🚀 Discover trending and viral YouTube videos easily with this powerful n8n automation! This workflow helps you perform bulk research on YouTube videos related to any search term, analyzing engagement
Works on both n8n Cloud and self-hosted instances. This template uses the community node, which is installable on n8n Cloud and self-hosted setups.
This n8n workflow automatically monitors positive reactions on Facebook Page posts, stores them in Airtable and notifies your team in Slack to create a motivational “Wall of Love.” It runs on a schedu