---
title: "Trigger events"
description: "The four Facebook and Instagram events that can start a campaign, what each one carries into the graph, and which events AFP ignores."
canonical: https://docs.afp.monster/reference/trigger-events
updated: 2026-08-19
pageType: reference
---

Four platform events start a campaign: a comment on a Facebook page post, a comment on an Instagram post, a Facebook Messenger message, and an Instagram direct message. Each event is matched against the active campaigns bound to the connected page it arrived for, and every campaign whose current graph version holds the matching trigger node starts one execution. Button clicks and the page's own comments never start a campaign.

## Summary

| Event | Trigger node | Campaign platform | Starts an execution |
|---|---|---|---|
| Comment on a Facebook page post | `trigger_comment` | Facebook | Yes, once per matching active campaign on that page |
| Comment on an Instagram post | `trigger_comment` | Instagram | Yes, once per matching active campaign on that page |
| Facebook Messenger message | `trigger_dm` | Facebook | Yes, when the message carries text and nothing is running for that person |
| Instagram direct message | `trigger_dm` | Instagram | Yes, when the message carries text and nothing is running for that person |
| Button click inside a DM | none | both | No — it resumes an execution waiting for a reply |
| Reply on a comment thread an execution waits on | none | both | No — it resumes that execution, with no further campaign matching |

## Event routing

```d2 title="Which arriving comments and DMs are ignored, which resume a waiting run, and which start an execution"
direction: down
arrives: "Comment or DM arrives\nfor a connected page"
skippable: "Sent by the page itself,\nan echo of a sent DM,\na removed or hidden comment,\nor a DM with no text?" {shape: diamond}
ignored: Ignored
awaiting: "Is a run for this person\non this page waiting for a reply?" {shape: diamond}
resumes: "That run resumes and takes\nthe text as the reply.\nNo campaign matching happens"
campaign: "Active campaign on the page whose\ncurrent graph version holds\nthe matching trigger node?" {shape: diamond}
starts: "One execution starts\nper matching campaign"
arrives -> skippable
skippable -> ignored: Yes
skippable -> awaiting: No
awaiting -> resumes: Yes
awaiting -> campaign: No
campaign -> ignored: No
campaign -> starts: Yes
```

## Comment on a Facebook page post

- **Trigger node:** `trigger_comment`
- **Campaign platform:** Facebook
- **Carries:** the comment, its post, the comment text, the commenter's name, any attached photo or video, and the parent comment on a reply

A comment on a post of a connected Facebook page is matched against every active campaign bound to that page. A campaign whose trigger has `post_scope` set to `specific` only matches comments on the post named in `post_id`; a trigger scoped to `all` matches comments on any post of the page.

Post scope is the only thing a comment trigger filters on. A trigger node holds no keyword configuration, so text filtering happens further down the graph, at the first `condition` node the execution reaches.

A comment with no text — a sticker, or an attachment posted without a caption — arrives with the placeholder text `{{sticker}}`, so a condition node always has something deterministic to match against.

## Comment on an Instagram post

- **Trigger node:** `trigger_comment`
- **Campaign platform:** Instagram
- **Carries:** the comment, its media, the comment text, the commenter's username, and the parent comment on a reply

Instagram comments follow the same path as Facebook comments and use the same trigger node. The campaign has to be bound to the Instagram business account the comment arrived for; a campaign's platform is derived from the page it targets, so binding it to an Instagram account is what makes it eligible for Instagram events.

A comment that resumes a waiting execution on the Instagram path arrives with the placeholder text `{{media}}` when it carries media instead of text.

## Facebook Messenger message

- **Trigger node:** `trigger_dm`
- **Campaign platform:** Facebook
- **Carries:** the sender and the message text

An incoming Messenger message is first checked against the executions already running for that person on that page. A running execution takes the message as a reply. With no execution running, AFP looks for active campaigns on the page whose current graph starts with `trigger_dm` and starts one execution per match.

The `trigger_dm` node has no post scope and no text filter, so any DM carrying text starts every active `trigger_dm` campaign on the page. Which of them go on to send anything is decided by their condition nodes.

## Instagram direct message

- **Trigger node:** `trigger_dm`
- **Campaign platform:** Instagram
- **Carries:** the sender and the message text

Instagram DMs resolve to a connected page either directly, for an Instagram business account connected on its own, or through the Facebook page the account is linked to. An event for an Instagram account that is not connected to AFP is dropped.

## What an event carries into the graph

| Value | Comment events | DM events | What uses it |
|---|---|---|---|
| The person who sent it | yes | yes | The recipient of every `send_dm` in the run, and the contact `add_tag` and `remove_tag` apply to |
| Message text | the comment text | the message text | `condition` matching, including keyword lists |
| Sender name | yes | yes | Personalising the text of a `send_dm`, `reply_comment`, or `send_comment` |
| The triggering comment | yes | no | `reply_comment`, `hide_comment`, and `delete_comment`, which act on that comment |
| The post the comment is on | yes | no | The trigger's `post_scope` check |
| An attached photo or video | yes | no | The media filters on a `condition`, such as `filter_images` |
| The connected page and its platform | yes | yes | Deciding where the run's actions are published |

A reply that resumes a waiting execution carries text but no attachment. A `condition` whose image filter is on therefore does not match a plain text reply, and a "wait for an image" branch routes text replies down the **No Match** output.

A DM event carries no comment and no post, which is why comment actions cannot be added to a campaign whose trigger is `trigger_dm`.

## Events that do not start a campaign

| Event | What happens |
|---|---|
| A comment removed or hidden on the platform | Ignored. Only new comments are processed. |
| Page activity that is not a comment | Ignored. |
| A comment the page posted itself, including one a campaign posted | Ignored, so a `reply_comment` or `send_comment` cannot re-trigger its own campaign. |
| An echo of a DM the page sent | Ignored, so a `send_dm` cannot resume its own run. |
| A DM with no text — image, sticker, or attachment only | Ignored. It neither starts an execution nor resumes a waiting one. |
| A button click in a DM | Resumes a waiting execution with the button's label as the reply text; with nothing running for that person, nothing happens. |
| A second matching event from the same person while their execution of that campaign runs | Skipped. One person cannot have two runs of the same campaign in flight at once. |
| An event for a page that is not connected to AFP | Dropped. |
| An event for a page whose owner has no active subscription | No campaign runs. The comment is recorded as a subscription error in the activity feed. |
| An event for a page whose access token no longer works | No campaign runs. The comment is recorded as a re-login error until the page's access is renewed. |
| An event on an inactive campaign, or one matching a trigger in an older saved version of the graph | Not matched. Only an active campaign's current version starts executions. |
| An event on an active campaign that has no saved graph, or whose graph has no trigger node | Not matched. Activation alone does not make a campaign eligible. |

## Page subscription

Events reach AFP only for a connected page whose event subscription is registered with the platform and verified. Until that handshake succeeds, comments and DMs on the page produce nothing, however the campaign is built.

Creating the first campaign on a page subscribes that page, so there is no separate subscription step to perform. Changing the page a campaign targets subscribes the new page too, and deleting the last campaign on a page removes the subscription again.

The subscription covers comment activity on the page's posts, incoming messages, and button clicks inside those messages — all four trigger events come through it.

Deactivating a campaign does not remove the subscription. Events keep arriving for the page and match nothing while every campaign on it is inactive, which is why re-activating a campaign starts working immediately.

## Notes

- Every matching campaign on the page starts its own execution. Two active campaigns with overlapping keywords both run for the same comment.
- Matching happens against the graph version saved at the moment the event arrives, and the execution stays pinned to that version for its whole life.
- A trigger's `unique_per_user` setting narrows which repeat events from the same person start a campaign. [Node types](/reference/node-types) covers what it restricts.
- A comment posted as a reply inside a thread an execution is waiting on resumes that execution and stops there — the comment is not offered to any other campaign on the page.

## Related

- [Execution states](/reference/execution-states) — what happens to the execution an event starts, and how it ends.
- [Node types](/reference/node-types) — the full configuration of `trigger_comment`, `trigger_dm`, and every other node.
- [Keyword matching rules](/reference/keyword-matching) — how the text an event carries is compared once the execution reaches a condition.
- [Test and debug campaigns](/guides/test-and-debug-campaigns) — how to tell which of these events reached your campaign.
