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": "Facebook Comments to Chatwoot + Agent Reply to Facebook",
"nodes": [
{
"parameters": {
"path": "facebook-comments",
"responseMode": "responseNode",
"options": {}
},
"name": "Meta Verification Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
-1200,
-500
],
"id": "meta-verification-webhook"
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "{{$json.query[\"hub.verify_token\"]}}",
"value2": "YOUR_META_VERIFY_TOKEN"
}
]
}
},
"name": "Verify Meta Token",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
-960,
-500
],
"id": "verify-meta-token"
},
{
"parameters": {
"respondWith": "text",
"responseBody": "{{$json.query[\"hub.challenge\"]}}",
"options": {
"responseCode": 200
}
},
"name": "Return Meta Challenge",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
-720,
-580
],
"id": "return-meta-challenge"
},
{
"parameters": {
"respondWith": "text",
"responseBody": "Invalid verify token",
"options": {
"responseCode": 403
}
},
"name": "Reject Verification",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
-720,
-420
],
"id": "reject-verification"
},
{
"parameters": {
"httpMethod": "POST",
"path": "facebook-comments",
"options": {}
},
"name": "Facebook Comment Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
-1200,
100
],
"id": "facebook-comment-webhook"
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "{{$json.body.entry[0].changes[0].value.item}}",
"value2": "comment"
}
]
}
},
"name": "Only Facebook Comments",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
-960,
100
],
"id": "only-facebook-comments"
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "{{$json.body.entry[0].changes[0].value.from.id}}",
"operation": "notEqual",
"value2": "YOUR_FACEBOOK_PAGE_ID"
}
]
}
},
"name": "Ignore Page Own Comments",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
-720,
100
],
"id": "ignore-page-own-comments"
},
{
"parameters": {
"requestMethod": "GET",
"url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/search/contacts?q=fb_{{$node[\"Facebook Comment Webhook\"].json.body.entry[0].changes[0].value.from.id}}&page=1",
"jsonParameters": true,
"options": {},
"headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
},
"name": "Search Chatwoot Contact",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 2,
"position": [
-480,
100
],
"id": "search-chatwoot-contact"
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "{{($json.payload.contacts || []).length}}",
"operation": "larger",
"value2": 0
}
]
}
},
"name": "Contact Exists?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
-240,
100
],
"id": "contact-exists"
},
{
"parameters": {
"jsCode": "const contact = ($json.payload.contacts || [])[0];\n\nif (!contact) {\n throw new Error('No existing contact found in payload.contacts');\n}\n\nreturn [\n {\n json: {\n contact_id: contact.id\n }\n }\n];"
},
"name": "Use Existing Contact",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
0,
0
],
"id": "use-existing-contact"
},
{
"parameters": {
"requestMethod": "POST",
"url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/contacts",
"jsonParameters": true,
"options": {},
"bodyParametersJson": "{\n \"name\": \"{{$node['Facebook Comment Webhook'].json.body.entry[0].changes[0].value.from.name}}\",\n \"identifier\": \"fb_{{$node['Facebook Comment Webhook'].json.body.entry[0].changes[0].value.from.id}}\",\n \"additional_attributes\": {\n \"social_profiles\": {\n \"facebook\": \"https://facebook.com/{{$node['Facebook Comment Webhook'].json.body.entry[0].changes[0].value.from.id}}\"\n }\n }\n}",
"headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
},
"name": "Create Chatwoot Contact",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 2,
"position": [
0,
220
],
"id": "create-chatwoot-contact"
},
{
"parameters": {
"jsCode": "const contact = $json.payload.contact;\n\nif (!contact) {\n throw new Error('No new contact found in payload.contact');\n}\n\nreturn [\n {\n json: {\n contact_id: contact.id\n }\n }\n];"
},
"name": "Use New Contact",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
240,
220
],
"id": "use-new-contact"
},
{
"parameters": {
"jsCode": "const fb = $('Facebook Comment Webhook').first().json.body.entry[0].changes[0].value;\n\nconst contactId = $json.contact_id;\nconst userId = fb.from.id;\nconst postId = fb.post_id;\nconst commentId = fb.comment_id;\nconst threadKey = `fb_post_${postId}_user_${userId}`;\n\nif (!contactId) {\n throw new Error('No contact_id found before preparing Facebook context');\n}\n\nreturn [\n {\n json: {\n contact_id: contactId,\n fb_user_id: userId,\n fb_user_name: fb.from.name,\n fb_comment: fb.message || '',\n fb_post_id: postId,\n fb_comment_id: commentId,\n fb_thread_key: threadKey\n }\n }\n];"
},
"name": "Prepare Facebook Context",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
500,
100
],
"id": "prepare-facebook-context"
},
{
"parameters": {
"requestMethod": "GET",
"url": "https://graph.facebook.com/v25.0/{{$json.fb_post_id}}?fields=message,permalink_url,created_time,full_picture,status_type&access_token=YOUR_LONG_LIVED_PAGE_ACCESS_TOKEN",
"jsonParameters": true,
"options": {}
},
"name": "Get Facebook Post Details",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 2,
"position": [
760,
100
],
"id": "get-facebook-post-details"
},
{
"parameters": {
"jsCode": "const ctx = $('Prepare Facebook Context').first().json;\n\nreturn [\n {\n json: {\n ...ctx,\n fb_post_text: $json.message || 'No post text available',\n fb_post_url: $json.permalink_url || '',\n fb_post_created_time: $json.created_time || '',\n fb_post_picture: $json.full_picture || '',\n fb_post_type: $json.status_type || 'Unknown'\n }\n }\n];"
},
"name": "Prepare Conversation Payload",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1020,
100
],
"id": "prepare-conversation-payload"
},
{
"parameters": {
"requestMethod": "GET",
"url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/search/conversations?q={{$json.fb_thread_key}}&page=1",
"jsonParameters": true,
"options": {},
"headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
},
"name": "Search Chatwoot Conversation",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 2,
"position": [
1280,
100
],
"id": "search-chatwoot-conversation"
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "{{($json.payload.conversations || []).length}}",
"operation": "larger",
"value2": 0
}
]
}
},
"name": "Conversation Exists?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
1520,
100
],
"id": "conversation-exists"
},
{
"parameters": {
"jsCode": "const ctx = $('Prepare Conversation Payload').first().json;\nconst conversation = ($json.payload.conversations || [])[0];\n\nif (!conversation) {\n throw new Error('No existing conversation found in payload.conversations');\n}\n\nreturn [\n {\n json: {\n ...ctx,\n conversation_id: conversation.id\n }\n }\n];"
},
"name": "Use Existing Conversation",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1760,
0
],
"id": "use-existing-conversation"
},
{
"parameters": {
"requestMethod": "POST",
"url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/conversations",
"jsonParameters": true,
"options": {},
"bodyParametersJson": "{\n \"source_id\": \"{{$node['Prepare Conversation Payload'].json.fb_thread_key}}\",\n \"inbox_id\": YOUR_CHATWOOT_INBOX_ID,\n \"contact_id\": {{$node['Prepare Conversation Payload'].json.contact_id}},\n \"custom_attributes\": {\n \"fb_comment_id\": \"{{$node['Prepare Conversation Payload'].json.fb_comment_id}}\",\n \"fb_post_id\": \"{{$node['Prepare Conversation Payload'].json.fb_post_id}}\",\n \"fb_user_id\": \"{{$node['Prepare Conversation Payload'].json.fb_user_id}}\",\n \"fb_post_url\": \"{{$node['Prepare Conversation Payload'].json.fb_post_url}}\",\n \"fb_thread_key\": \"{{$node['Prepare Conversation Payload'].json.fb_thread_key}}\"\n }\n}",
"headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
},
"name": "Create Chatwoot Conversation",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 2,
"position": [
1760,
220
],
"id": "create-chatwoot-conversation"
},
{
"parameters": {
"jsCode": "const ctx = $('Prepare Conversation Payload').first().json;\n\nif (!$json.id) {\n throw new Error('No conversation id returned from Chatwoot');\n}\n\nreturn [\n {\n json: {\n ...ctx,\n conversation_id: $json.id\n }\n }\n];"
},
"name": "Use New Conversation",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2000,
220
],
"id": "use-new-conversation"
},
{
"parameters": {
"requestMethod": "POST",
"url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/conversations/{{$json.conversation_id}}/custom_attributes",
"jsonParameters": true,
"options": {},
"bodyParametersJson": "{\n \"custom_attributes\": {\n \"fb_comment_id\": \"{{$json.fb_comment_id}}\",\n \"fb_post_id\": \"{{$json.fb_post_id}}\",\n \"fb_user_id\": \"{{$json.fb_user_id}}\",\n \"fb_post_url\": \"{{$json.fb_post_url}}\",\n \"fb_thread_key\": \"{{$json.fb_thread_key}}\"\n }\n}",
"headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
},
"name": "Update Conversation Attributes",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 2,
"position": [
2240,
100
],
"id": "update-conversation-attributes"
},
{
"parameters": {
"jsCode": "let ctx;\n\nif ($('Use Existing Conversation').isExecuted) {\n ctx = $('Use Existing Conversation').first().json;\n} else if ($('Use New Conversation').isExecuted) {\n ctx = $('Use New Conversation').first().json;\n} else {\n throw new Error('No conversation context found');\n}\n\nreturn [\n {\n json: ctx\n }\n];"
},
"name": "Restore Conversation Context",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2480,
100
],
"id": "restore-conversation-context"
},
{
"parameters": {
"requestMethod": "POST",
"url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/conversations/{{$json.conversation_id}}/messages",
"jsonParameters": true,
"options": {},
"bodyParametersJson": "{\n \"content\": {{ JSON.stringify(\"## Facebook Comment\\n\\n**Customer:** \" + $json.fb_user_name + \"\\n**Facebook User ID:** \" + $json.fb_user_id + \"\\n\\n**Comment:**\\n> \" + $json.fb_comment + \"\\n\\n---\\n\\n**Post:**\\n\" + ($json.fb_post_text || \"No post text available\") + \"\\n\\n**Post Type:** \" + ($json.fb_post_type || \"Unknown\") + \"\\n**Post Time:** \" + ($json.fb_post_created_time || \"Unknown\") + \"\\n\\n[Open Original Comment](https://facebook.com/\" + $json.fb_comment_id + \")\\n\\n[Open Original Post](\" + $json.fb_post_url + \")\\n\\n---\\n\\n**Internal IDs**\\nThread Key: `\" + $json.fb_thread_key + \"`\\nPost ID: `\" + $json.fb_post_id + \"`\\nComment ID: `\" + $json.fb_comment_id + \"`\") }},\n \"message_type\": \"incoming\",\n \"content_type\": \"text\"\n}",
"headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
},
"name": "Add Comment Message",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 2,
"position": [
2720,
100
],
"id": "add-comment-message"
},
{
"parameters": {
"httpMethod": "POST",
"path": "chatwoot-facebook-reply",
"options": {}
},
"name": "Chatwoot Reply Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
-1200,
640
],
"id": "chatwoot-reply-webhook"
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "{{$json.body.message_type}}",
"value2": "outgoing"
}
]
}
},
"name": "Only Agent Replies",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
-960,
640
],
"id": "only-agent-replies"
},
{
"parameters": {
"jsCode": "const body = $json.body;\n\nconst replyText = body.content || body.message?.content || '';\n\nconst fbCommentId =\n body.conversation?.custom_attributes?.fb_comment_id ||\n body.conversation?.additional_attributes?.fb_comment_id ||\n body.custom_attributes?.fb_comment_id ||\n '';\n\nif (!replyText) {\n throw new Error('No Chatwoot agent reply content found.');\n}\n\nif (!fbCommentId) {\n throw new Error('No fb_comment_id found in Chatwoot conversation custom_attributes.');\n}\n\nreturn [\n {\n json: {\n fb_comment_id: fbCommentId,\n reply_text: replyText\n }\n }\n];"
},
"name": "Prepare Facebook Reply",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-720,
560
],
"id": "prepare-facebook-reply"
},
{
"parameters": {
"requestMethod": "POST",
"url": "https://graph.facebook.com/v25.0/{{$json.fb_comment_id}}/comments",
"jsonParameters": true,
"options": {},
"bodyParametersJson": "{\n \"message\": {{ JSON.stringify($json.reply_text) }},\n \"access_token\": \"YOUR_LONG_LIVED_PAGE_ACCESS_TOKEN\"\n}"
},
"name": "Reply to Facebook Comment",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 2,
"position": [
-480,
560
],
"id": "reply-to-facebook-comment"
}
],
"connections": {
"Meta Verification Webhook": {
"main": [
[
{
"node": "Verify Meta Token",
"type": "main",
"index": 0
}
]
]
},
"Verify Meta Token": {
"main": [
[
{
"node": "Return Meta Challenge",
"type": "main",
"index": 0
}
],
[
{
"node": "Reject Verification",
"type": "main",
"index": 0
}
]
]
},
"Facebook Comment Webhook": {
"main": [
[
{
"node": "Only Facebook Comments",
"type": "main",
"index": 0
}
]
]
},
"Only Facebook Comments": {
"main": [
[
{
"node": "Ignore Page Own Comments",
"type": "main",
"index": 0
}
]
]
},
"Ignore Page Own Comments": {
"main": [
[
{
"node": "Search Chatwoot Contact",
"type": "main",
"index": 0
}
]
]
},
"Search Chatwoot Contact": {
"main": [
[
{
"node": "Contact Exists?",
"type": "main",
"index": 0
}
]
]
},
"Contact Exists?": {
"main": [
[
{
"node": "Use Existing Contact",
"type": "main",
"index": 0
}
],
[
{
"node": "Create Chatwoot Contact",
"type": "main",
"index": 0
}
]
]
},
"Use Existing Contact": {
"main": [
[
{
"node": "Prepare Facebook Context",
"type": "main",
"index": 0
}
]
]
},
"Create Chatwoot Contact": {
"main": [
[
{
"node": "Use New Contact",
"type": "main",
"index": 0
}
]
]
},
"Use New Contact": {
"main": [
[
{
"node": "Prepare Facebook Context",
"type": "main",
"index": 0
}
]
]
},
"Prepare Facebook Context": {
"main": [
[
{
"node": "Get Facebook Post Details",
"type": "main",
"index": 0
}
]
]
},
"Get Facebook Post Details": {
"main": [
[
{
"node": "Prepare Conversation Payload",
"type": "main",
"index": 0
}
]
]
},
"Prepare Conversation Payload": {
"main": [
[
{
"node": "Search Chatwoot Conversation",
"type": "main",
"index": 0
}
]
]
},
"Search Chatwoot Conversation": {
"main": [
[
{
"node": "Conversation Exists?",
"type": "main",
"index": 0
}
]
]
},
"Conversation Exists?": {
"main": [
[
{
"node": "Use Existing Conversation",
"type": "main",
"index": 0
}
],
[
{
"node": "Create Chatwoot Conversation",
"type": "main",
"index": 0
}
]
]
},
"Use Existing Conversation": {
"main": [
[
{
"node": "Update Conversation Attributes",
"type": "main",
"index": 0
}
]
]
},
"Create Chatwoot Conversation": {
"main": [
[
{
"node": "Use New Conversation",
"type": "main",
"index": 0
}
]
]
},
"Use New Conversation": {
"main": [
[
{
"node": "Update Conversation Attributes",
"type": "main",
"index": 0
}
]
]
},
"Update Conversation Attributes": {
"main": [
[
{
"node": "Restore Conversation Context",
"type": "main",
"index": 0
}
]
]
},
"Restore Conversation Context": {
"main": [
[
{
"node": "Add Comment Message",
"type": "main",
"index": 0
}
]
]
},
"Chatwoot Reply Webhook": {
"main": [
[
{
"node": "Only Agent Replies",
"type": "main",
"index": 0
}
]
]
},
"Only Agent Replies": {
"main": [
[
{
"node": "Prepare Facebook Reply",
"type": "main",
"index": 0
}
]
]
},
"Prepare Facebook Reply": {
"main": [
[
{
"node": "Reply to Facebook Comment",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"active": false
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Facebook Comments to Chatwoot + Agent Reply to Facebook. Uses httpRequest. Webhook trigger; 27 nodes.
Source: https://gist.github.com/md-riaz/b9035f05e81dee374d2d7656babe118e — 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.
Jigsaw API key for image processing, I use this as a gatekeeper/second pair of eyes. LINK to their website https://jigsawstack.com/ SECOND A postgress DATABASE (I use Supabase) LlamaCloud for the pars
W1 - IN WhatsApp Adapter (Secure + Fast ACK). Uses postgres, redis, httpRequest. Webhook trigger; 48 nodes.
Whatsapp Multi Agent System optimized copy 2.0. Uses airtable, httpRequest, errorTrigger. Webhook trigger; 44 nodes.
Invoice Agent. Uses httpRequest, emailSend. Webhook trigger; 29 nodes.
Reputation Engine — SEO QA Agent. Uses httpRequest. Webhook trigger; 28 nodes.