Describe the problem/error/question
After publishing my n8n workflow, when a user sends a message, it creates a duplicate loop, causing the AI to continuously send messages repeatedly.
What I want to achieve is:
I need to apply 3 types of filtering:
If the user requests an image, AI Agent 1 should send a single response with the image.
If the message contains specific keywords (like “pic” or similar), AI Agent 1 should handle it and respond once.
If none of the above conditions match, then AI Agent 3 should handle the response.
Please share your workflow
Share the output returned by the last node
Information on your n8n setup
- n8n version:
- Database (default: SQLite):
- n8n EXECUTIONS_PROCESS setting (default: own, main):
- Running n8n via (Docker, npm, n8n cloud, desktop app):n8n cloud
- Operating system:
Hi @Abidul_Haque_Shohel , Welcome !
The duplicate loop happens because your AI agent sends a reply via “Send a text message”, which triggers the same webhook again, creating an infinite cycle. Your is_echo filter is on the right track but has an issue.
The fix:
-
Your is_echo check is comparing to a string "true" instead of a boolean. In your If node, you have is_echo is not equal to true but true is in the expression field (fx), meaning it’s being treated as a string. Facebook Messenger sends is_echo as a boolean true, not the string "true". Switch that condition to use the boolean comparison, or better yet, flip the logic: check that is_echo does not exist rather than checking its value.
-
Add a sender check as a safety net. Even with is_echo, add a condition that compares the sender ID against your page ID. Something like: {{ $json.body.entry[0].messaging[0].sender.id }} is not equal to YOUR_PAGE_ID. This guarantees the bot never processes its own messages.
-
Your routing logic can be simplified. Right now you have If → If1 → If2 cascading into three separate AI agents with separate memory and models. Instead, use a single Switch node with three outputs: one for image attachments, one for image-related keywords, and a default for everything else. This avoids the nested If chain and makes the flow cleaner.
-
Make sure “Respond to Webhook” fires immediately. It looks like it does from your screenshot, but confirm it returns 200 to Facebook before any AI processing starts. Facebook will retry the webhook if it doesn’t get a 200 within 5 seconds, which also causes duplicates.
Let me know if this works 
2 Likes
@houda_ben
The loop issue is solved, but there’s still a problem with image handling.
When a user sends an image, it goes to the first IF node and immediately returns false. Because of that, it never properly reaches or triggers the second IF node.
However, the expected behavior is:
If an image is detected in the second IF node, it should trigger the response from the specific AI agent assigned to handle image-related requests.
The problem is in the first IF node’s logic. Looking back at your screenshots:
Your first IF checks: message.text exists. When a user sends an image, Facebook Messenger sends an attachments array but no message.text field. So the first IF correctly says “text doesn’t exist” and routes to false. The image message never makes it past that gate.
The fix: change the first IF node’s condition from AND to OR:
This way both text messages and image messages pass through to the routing logic below.
Then your IF1 node (checking attachments[0].type equals “image”) will actually receive the image messages and route them to the right AI agent.
2 Likes
@houda_ben solved. Thank you
1 Like
@houda_ben
My Facebook AI agent is missing some messages. For certain messages, the AI does not reply, but when the same user sends another message later, the AI replies.
In my current flow:
-
After the Webhook, I have IF Node 1:
{{ !!$json.body.entry[0].messaging[0].message && !$json.body.entry[0].messaging[0].message?.is_echo }}
If this is true, it goes to IF Node 2.
-
In IF Node 2, I check:
{{ $json.body.entry[0].messaging[0].message.attachments?.[0]?.type || '' }}
If it is equal to "image" or "audio", then it goes to AI Agent 2 for a response.
If false, it goes to IF Node 3.
-
In IF Node 3, I check:
{{ ($json.body.entry[0].messaging[0].message.text || '')
.toLowerCase()
.match(/image|pic|chobi|ছবি/) ? true : false }}
If true, it goes to AI Agent 2.
If false, it goes to AI Agent 3.