---
title: "Route comments to a DM"
description: "DM everyone who comments a keyword on your post, and reply publicly first, using four nodes on the campaign canvas — trigger, condition, reply, and DM."
canonical: https://docs.afp.monster/guides/route-comments-to-dm
updated: 2026-08-19
pageType: guide
---

Four nodes do it. A `trigger_comment` node listens to a connected page, a `condition` node matches the comment text against a keyword list, a `reply_comment` node answers publicly under the comment, and a `send_dm` node sends the private message. Connect them in that order, save the graph, and switch the campaign on — the next comment that matches gets both replies.

![A four-node campaign: a comment trigger, a condition on a keyword list, a public comment reply on the match output, and a send DM node after it](../../../assets/screenshots/guides/route-comments-to-dm/four-node-graph.webp)

## What you need first

- A campaign on a connected page, open in the canvas. See [Build a campaign on the canvas](/guides/build-a-campaign).
- A keyword list holding the words you want to catch. See [Match comments with keyword lists](/guides/keyword-lists).

## How do I DM everyone who comments a keyword on my post?

```d2 title="The four-node comment-to-DM campaign: trigger, keyword condition, public reply, private message"
direction: down
trigger: "trigger_comment\nall posts or one post"
cond: "condition\nkeyword list" {shape: diamond}
reply: "reply_comment\npublic answer"
dm: "send_dm\nprivate message"
halt: stop
trigger -> cond
cond -> reply: Match
reply -> dm
cond -> halt: No Match
```

1. Add a `trigger_comment` node. Choose whether it watches every post on the page or one specific post; a specific post needs the post itself selected in the settings panel.
2. Connect the trigger to a `condition` node. A trigger connects only to a condition, so this step is not optional.
3. In the condition, set the match type to **Keyword list** and pick your list. Comments containing one of its words leave the **Match** output; everything else leaves **No Match**.
4. From the **Match** output, add a `reply_comment` node and write the public reply.
5. Connect `reply_comment` to `send_dm` and write the private message. A DM can be text, an image, a card, or text with buttons.
6. From the **No Match** output, add a `stop` node — or leave it unconnected, which ends the execution just as well but is harder to read on the canvas.
7. Click **Save campaign**, then switch the campaign on and confirm.

Both the public reply and the DM can address the commenter by name through a template variable. 

:::note
Nodes run in the order you connect them, so the public reply is posted before the DM is sent. Putting `send_dm` first works too — it changes which one the commenter sees first.
:::

## Why reply publicly as well as sending a DM?

The two replies reach different audiences. A `reply_comment` node posts under the comment, where everyone reading the post sees it. A `send_dm` node reaches one person: the commenter.

The public reply also gives the DM somewhere to come from. AFP delivers the first DM of an execution as a private reply to the comment that triggered it, and addresses the person directly for every message after that.

A campaign never triggers itself with its own output. Comments the page posts — including replies a `reply_comment` node just published — do not start a new execution.

Whether the pair converts better than a DM alone is a claim about results, not behaviour. 

## What is the 24-hour messaging window?

Facebook and Instagram limit when a page may message a person, and that limit is described as a 24-hour window. AFP works within it by addressing the first DM of an execution through the triggering comment rather than through the person, and by switching to the person for the messages that follow.



A DM the platform refuses is recorded as an error on that execution, and the execution does not advance past the `send_dm` node. Nodes after it never run, which is why a campaign whose DM fails often looks like "the public reply worked and nothing else did".

## Should I hide the comment after replying?

Add a `hide_comment` node after `reply_comment` when the comment is something you do not want left on the post — a price question you answer privately, or a repeated spam phrase. On Facebook the same node can block the comment's author; that option is unavailable on Instagram.

Hiding is a poor choice in three cases:

- **The public reply is the point.** Hiding takes the comment out of the public thread, so the exchange you posted for other readers is no longer part of the conversation they see. 
- **The campaign is triggered by DMs.** Comment actions are unavailable when the trigger is `trigger_dm`, so the canvas refuses the connection: a DM-triggered execution has no comment to act on.
- **You wanted the comment gone for good.** That is `delete_comment`, and it forecloses the rest of the pattern: the canvas refuses `reply_comment` or `hide_comment` anywhere after it, because the comment no longer exists.

:::caution
A comment action with no comment to work on is skipped, and the execution moves to the next node without being marked as failed. A comment action the platform rejects is recorded as an error instead, and the execution stops at that node — so a hide that did not happen is worth reading in the execution history rather than assuming.
:::

## What if I want a different set of comments?

Four settings change what the pattern catches, and none of them need another node.

| Goal | Setting | Effect |
|---|---|---|
| Answer each person once | The trigger's once-per-person setting | A person who comments again does not start another execution |
| Watch one post instead of the whole page | The trigger's post scope, set to a specific post | Comments on every other post are ignored |
| Catch every comment, whatever it says | The condition's match type, set to any message | The condition stops branching: its **No Match** output disappears, and a connection already leaving that output is dropped |
| Match everything except your keywords | The condition's reverse-keyword setting | Comments containing none of the list's words leave **Match** |
| Skip comments carrying an image, a GIF, or a link | The condition's image, GIF, and link filters | Those comments are routed to **No Match** rather than answered |

## Why is my campaign not sending the DM?

| Symptom | Cause | Fix |
|---|---|---|
| No comment produces anything | The campaign is switched off, or the graph with the trigger was never saved | Save the graph, then switch the campaign on — only the trigger in the current saved version starts executions |
| The public reply appears, the DM never does | The DM was refused and the error was recorded on the execution, which stopped at that node | Open the execution and read the node it stopped on. See [Test and debug a campaign](/guides/test-and-debug-campaigns) |
| Every comment matches, including ones without your keywords | The condition points at a keyword list that was deleted, or at an empty one — both fall through to a match | Point the condition at a list that exists and has words in it |
| A person comments twice and only the first comment is answered | One person cannot have two executions of the same campaign running at once; a matching comment that arrives during one is skipped | Nothing to fix — or shorten the graph so executions finish sooner |
| Comments on your other posts are ignored | The trigger is scoped to one specific post | Switch the trigger to every post, or point it at the post you are testing on |
| Your own test comment does nothing | Comments the page posts as itself never trigger a campaign | Comment from a personal profile instead of as the page |
| One comment produces two DMs | Two active campaigns on the same page both match it, and each starts its own execution | Deactivate the campaign you are not using, or narrow one keyword list |
| A `send_comment` node posts nothing | `send_comment` needs the post it should comment on, and does nothing without it | Select the post in that node's settings panel, or use `reply_comment` to answer under the triggering comment |

## Related

- [Build a campaign on the canvas](/guides/build-a-campaign) — creating, saving, and activating the campaign this pattern lives in.
- [Match comments with keyword lists](/guides/keyword-lists) — building and reusing the list the condition matches against.
- [Node types](/reference/node-types) — every field on `trigger_comment`, `condition`, `reply_comment`, and `send_dm`.
- [Test and debug a campaign](/guides/test-and-debug-campaigns) — run this pattern without posting anything, and read what each execution did.
- [Comment moderation](/guides/comment-moderation) — hiding, deleting, and blocking beyond one campaign.
