Skip to content

Three numbers describe how well a comment-to-DM campaign works: match rate, delivery rate, and time to first DM. All three are defined below, along with the campaign to build, the comments to post, and the file the results are published in. No data has been collected, so no result appears on this page — the method is published first, on purpose.

Status: methodology published; data collection not started. Every measured field in this document is empty until the first run completes, at which point the results and the raw dataset are published here.

Each metric is a count divided by a count, taken over one run against one connected page, and each has a denominator that excludes trials the platform never delivered to AFP at all.

MetricDefinitionUnit
Trials startedComments posted during the run that produced an execution of the test campaigncount
Match rateTrials whose execution left the condition node through Match, divided by trials startedpercent
Delivery rateTrials whose execution recorded a sent DM, divided by trials whose execution reached the send DM nodepercent
Time to first DMSeconds from the observer posting the comment to the DM appearing in the recipient’s conversationseconds, reported as median and 90th percentile

Match rate measures the condition node, not the trigger. A trigger node holds no keyword configuration, so every comment on the post in scope starts an execution and the condition is the only place text is compared. Keyword matching rules defines the comparison each match type performs.

Delivery rate measures what AFP recorded, not what the recipient saw. A send DM node that raises an error records that error and the run stops advancing there, so the failure is visible; a message accepted by Facebook or Instagram and then filtered afterwards counts as delivered under this definition.

Time to first DM is measured on the observer’s clock at both ends — when the comment is submitted, and when the DM appears in the recipient’s conversation. Timestamps recorded inside AFP come from the platform and serve as a cross-check only.

Observer posts a commentclock startsComment reaches the connected pageTrigger accepts itexecution startsConditionkeyword listSend DM nodeRun ends with no DMDM appears in the recipient's conversationclock stops Match No Match

One campaign, four nodes, no waits. Anything else in the graph adds a variable that has nothing to do with the three metrics.

  1. Create a campaign bound to the page under test and open it on the canvas.
  2. Add a comment trigger. Set its post scope to a specific post and select a post created for the run, so ordinary traffic on other posts cannot enter the sample. Leave unique per user off — with it on, a repeat commenter is short-circuited and the trial never starts.
  3. Add a condition node with the Keyword list match type, pointing at a keyword list created for the run. Leave reverse matching off, leave the image, GIF, and link filters off, and leave wait for reply off so the run resolves in one pass.
  4. Add a send DM node with a fixed text message, connected to the condition’s Match output. Connect nothing to No Match, so a non-matching run ends at the condition and is unambiguous in the history.
  5. Save the campaign, then activate it. Activation validates the graph and is a separate action from saving.
  6. Deactivate every other campaign on that page. Each active campaign whose trigger matches starts its own execution, and two campaigns answering the same comment make delivery rate meaningless.

Environment first: one Facebook page and one Instagram business account, both connected and subscribed, under an account whose subscription is active. A comment arriving while the subscription is inactive is recorded as a subscription error, and a page whose stored access has stopped working records a re-login error. Both count as environment failures and are excluded from every rate.

  1. Fix the keyword list to a single keyword, and fix the DM text. Record both verbatim in the run notes.
  2. Assign one distinct commenter account per trial. One person gets one active run of one campaign at a time, so a second comment from the same account while the first run is still active is skipped and would silently shrink the sample.
  3. Comment from accounts other than the page itself. Comments the page posts are ignored, which rules out driving the run from the page account.
  4. For each trial, post the comment text for its bucket and record the submission time on the observer’s clock.
  5. Watch the recipient’s conversation and record the arrival time of the DM on the same clock. Record a non-arrival after a fixed cut-off, chosen before the run starts and stated with the results.
  6. Read the campaign’s execution history and record, per trial, whether the run left the condition through Match and where it stopped. The history returns the 20 most recent runs and does not refresh on its own, so keep each batch under that and read it before starting the next.
  7. Filter the activity feed to the page and the run’s time window, then export it. The export applies the feed’s filters and downloads as JSON, and it is the audit trail behind the trial-by-trial table.
  8. Repeat on the second platform without changing the campaign shape, the keyword, or the DM text.

Every trial belongs to one bucket, and the bucket fixes both the text posted and the branch it is expected to take.

BucketWhat is postedExpected branch
Exact keywordThe keyword aloneMatch
Keyword in a sentenceA sentence containing the keyword as a substringMatch
Keyword in upper caseThe keyword typed in capital lettersMatch
Near missA word that shares a prefix with the keyword without containing itNo Match
Unrelated textA comment on the post that contains no keywordNo Match
Media onlyA sticker or image with no textNo Match

A media-only comment reaches the condition as a placeholder text rather than as an empty string, which is why it belongs in the sample: it is the one bucket where what the condition compares is not what the commenter typed.

No results. Data collection has not started, and nothing on this page has been measured.

The definitions, the campaign shape, the buckets, and the cut-off are fixed in public before any number exists, so the eventual figures can be checked against a protocol nobody could have tuned after seeing the data.

One JSON file per run, published on this page alongside the summary table, with one object per trial. The activity export taken in step 7 is published with it unchanged, so every trial can be traced back to the row AFP recorded.

FieldWhat it holds
trial_idSequence number within the run
platformfacebook or instagram
bucketOne of the six bucket names above
comment_textThe exact text posted
comment_posted_atObserver clock, when the comment was submitted
execution_startedWhether an execution was created for this comment
branch_takenmatch, no_match, or none
dm_recordedWhether the execution recorded a sent DM
dm_observed_atObserver clock, when the DM appeared in the conversation
time_to_first_dm_secondsDifference between the two observer timestamps
outcomedelivered, no_match, no_execution, environment_failure, or timeout
notesAnything unusual about the trial, in plain text

Measured fields are null until the run fills them in. One trial from the published skeleton looks like this:

[
{
"trial_id": 1,
"platform": "facebook",
"bucket": "exact_keyword",
"comment_text": "price",
"comment_posted_at": null,
"execution_started": null,
"branch_taken": null,
"dm_recorded": null,
"dm_observed_at": null,
"time_to_first_dm_seconds": null,
"outcome": null,
"notes": ""
}
]
  • Delivery is not AFP’s alone. AFP hands the message to Facebook or Instagram; what happens after that is outside anything measured here, and time to first DM includes the platform’s own delivery time.
  • One account, one audience, one window. A run covers one Facebook page and one Instagram business account at one time of day. It says nothing about pages with different traffic, different follower counts, or a different region.
  • Observer clocks are manual. Both ends of the timing measurement are recorded by a person watching two surfaces, so the resolution is coarse and human reaction time is inside the number.
  • The sample is synthetic. Comments written to fill buckets are not comments real followers write, and the near-miss bucket in particular is chosen to sit close to the matching boundary.
  • Case handling is unconfirmed. The upper-case bucket is measured, but the expected branch for it is unverified until engineering confirms how the comparison treats letter case.
  • No competitor is measured. These metrics describe AFP only. The comparison pages state plainly that no competitor performance number has been measured.
  • Rates are recorded, not guaranteed. Nothing here is a service level. A published figure describes one run on one day.