Comment Automations

Create comment-to-DM automation

Changed on

Create a keyword-triggered automation. On Instagram and Facebook, when someone comments a matching keyword (or, with trigger: story_reply, replies to your Instagram story with one), they automatically receive a DM.

Platforms:

  • instagram, facebook: the full DM automation (private reply, buttons, product card, audience rules, follow gate) plus the optional public reply.
  • tiktok, threads, linkedin, youtube: public reply only. These platforms have no private reply to a comment, so the automation answers a matching comment with commentReply and nothing else. commentReply is required and the DM fields (dmMessage, dmMessageVariations, buttons, template, quickReplies, alsoMatchInDms, audience, followGate, dmDelaySeconds, commentReplyDelaySeconds) are rejected with a 400 naming the field. TikTok comments arrive by webhook (TikTok business accounts only); the others are read by the comment poll, so a reply follows the comment by up to the poll interval (10 minutes on posts from the last 24 hours, longer on older posts). repeatPolicy applies there too: with the default once, a person gets one public reply per automation, and their later comments get none.
  • X accounts are refused with a 400 (platform_not_supported): X comment polling is off, so an X automation could never fire.

To continue into a specific workflow after the recipient taps a button, use {"type":"postback","title":"Send it","payload":"zernio:workflow:<workflowId>"}. The target must be active and belong to the same account and profile. This also works for product-card buttons. The tap starts that workflow directly, without matching its keyword or first-message condition. A tap on a workflow that is waiting on wait_for_reply in that conversation answers that wait and resumes the run. A tap on a different active workflow starts it and exits the other live runs. Stale or invalid targets still do nothing. The initial comment DM alone does not start the workflow: the recipient must tap.

Triggers (trigger):

  • comment (default): fires on keyword comments on a post or reel.
  • story_reply: fires when someone replies to your Instagram story with a keyword, and answers them with a DM. Set platformPostId to a story media id to scope to one story, or omit it to match replies to any story.
  • live_comment (Instagram only): fires on keyword comments made during one of your Instagram live broadcasts and answers them with a private reply. comment automations never fire on live comments, and live_comment ones never fire on post comments. Meta only accepts the private reply while the broadcast is live.
  • story_mention (Instagram only): fires when someone mentions your account in their story, and answers them with a DM. A mention carries no text and Meta does not identify the story, so keywords must be empty and platformPostId omitted.

Comments on Instagram and Facebook arrive by webhook. Every 10 minutes Zernio also reads the latest comments and replies back (the bound post, or the 5 newest posts for an account-wide automation, up to 20 Graph reads per account per run; a post not fully read is picked up again on the next run) and runs any comment the webhook did not deliver, so a dropped webhook still fires. A comment is answered at most once whichever path sees it first.

Targeting (comment trigger):

  • Per-post: set platformPostId to scope to one specific post (only one active per-post automation is allowed per post).
  • Account-wide ("any post"): omit platformPostId (and postId). The automation evaluates every comment on every post on the account. You can stack unlimited account-wide automations, each with its own keyword set, and they all run independently. Per-post automations take priority on their post.

Audience (audience, Instagram only): restrict the automation to followers or non-followers, and/or to accounts above a follower count. Instagram only reveals the follow relationship for people who have messaged the account, so audience.whenUnknown decides what happens for everyone else - including verify, which sends a one-tap confirmation DM (followGate) and then delivers the real DM automatically. People we already know follow you skip the tap entirely. Set audience.tapToUnlock: true instead to send that button DM to every commenter and deliver the real DM on the tap with no follow check.

Set alsoMatchInDms: true on a comment automation to also answer people who send a keyword as a direct message instead of commenting it. One automation then covers both doors, and each door is deduplicated separately (someone who already got the DM from their comment still gets it if they later DM the keyword). Requires at least one keyword.

Links in the DM's buttons can be click-tracked (linkTracking, on by default) and clickers optionally tagged (clickTag) for segmentation. Stats returned include delivered, read, and link clicks.

Personalisation: {{first_name}}, {{name}} and {{username}} in dmMessage, commentReply, their variations and button titles resolve from the commenter. {{first_name}} is the first word of the display name and {{name}} the display name; when the platform gives no display name both fall back to the platform username (unless it is all digits). {{username}} is the platform username. A value still unknown resolves to an empty string and the space before it is dropped.

Behaviour: repeatPolicy decides whether a person can get the DM again, dedupeSameTextHours stops two automations sending the same text to one person, publicReplyPolicy decides whether the public reply waits for the DM, and actions likes or hides the matched comment.

post/v1/comment-automations

Request

  • Base URL: https://zernio.com/api
  • URL: https://zernio.com/api/v1/comment-automations
  • Auth: HTTP bearer

Request body

profileIdstring required
accountIdstring required

Instagram, Facebook, TikTok, Threads, LinkedIn or YouTube account ID. On the last four the automation only posts the public reply. X accounts are refused (400, code platform_not_supported) while X comment polling is off.

trigger'comment' | 'live_comment' | 'story_reply' | 'story_mention'

What fires the automation. 'comment' (keyword comment on a post), 'live_comment' (keyword comment on an Instagram live broadcast), 'story_reply' (keyword reply to an Instagram story) or 'story_mention' (a story mentioning the Instagram account). For 'story_reply', platformPostId is the story media id (omit for any story). Every trigger but 'comment' is Instagram only; reply-only platforms accept 'comment' only.

platformPostIdstring

Platform media/post ID (or story media id when trigger=story_reply). Omit for an account-wide (any-post / any-story) automation.

postIdstring

Zernio post ID (24 hexadecimal characters); platform IDs return 400. Optional and never required. Use it INSTEAD of platformPostId to bind a per-post automation to a not-yet-published Zernio post: the automation stays pending and arms itself when that post publishes. For a post already live on the platform, pass platformPostId alone and omit this.

postTitlestring

Post content snippet for display

namestring required

Automation label

keywordsstring[]

Trigger keywords (empty = any comment triggers)

matchMode'exact' | 'contains' | 'word'

How a keyword is compared with the comment. 'contains' (default) matches anywhere, even inside another word (keyword 'app' fires on 'happy'). 'word' matches the keyword only as a standalone word. 'exact' requires the whole comment to be exactly the keyword.

excludeKeywordsstring[]

Comments containing one of these never trigger the automation, even when a trigger keyword also matches. Compared using the same matchMode.

typoToleranceboolean

Only with matchMode=word: also fire on close misspellings of a keyword (one edit for 4-7 character keywords, two from 8 up). Keywords shorter than 4 characters are never fuzzy-matched.

dmMessagestring

DM text sent to the commenter. Required on Instagram and Facebook (400 missing_required_field when absent). Rejected on TikTok, Threads, LinkedIn and YouTube, which have no private reply (400 invalid_field_value). Max 640 chars when buttons are set, otherwise ~1000.

commentReplystring

Public reply to the comment. Optional on Instagram and Facebook; required on TikTok, Threads, LinkedIn and YouTube, where it is the automation's only action.

dmMessageVariationsstring[]

Optional alternate DM texts for random rotation. When set, each triggered comment sends one picked at random from [dmMessage, ...dmMessageVariations], so repeat commenters get slightly different DMs (helps avoid identical-message patterns). Up to 5. Buttons are attached to whichever text is picked, not varied.

commentReplyVariationsstring[]

Optional alternate public replies, rotated at random alongside commentReply (picked independently of the DM). Up to 5.

linkTrackingboolean

Wrap link buttons in the DM in a tracked redirect so clicks are counted (Link Clicks / CTR). Pass false to send links exactly as written. Defaults to on.

clickTagstring

Optional tag applied to a contact when they click a tracked link (requires linkTracking). Lets you segment clickers for broadcasts/sequences.

dmDelaySecondsinteger

Seconds to wait after the trigger before sending the DM. Omit or send 0 to reply immediately (the default). Max 86400 (24h). The trigger is still matched and deduplicated the moment the comment arrives, so a delay only moves when the response is sent.

commentReplyDelaySecondsinteger

Seconds to wait before posting the public comment reply. Omit or send 0 to post it right after the DM (the default). The reply never goes out before the DM, so a value below dmDelaySeconds is raised to it. Ignored when trigger=story_reply, which has no public reply.

alsoMatchInDmsboolean

Also fire these keywords on a plain inbound DM, so the automation answers people who message the keyword instead of commenting it. Requires at least one keyword (an empty keyword list means 'match anything', which would answer every inbound message) and is rejected on story_reply automations, which already trigger on DMs. Dedup is per door: a contact who already received the DM from their comment can still receive it from a DM.

dedupeSameTextHoursinteger nullable

Skip the DM when this recipient already received identical DM text (after personalisation) from this account, from any automation, within this many hours. The skip is logged with status skipped.

publicReplyPolicy'after_dm' | 'always'

'after_dm' posts commentReply only after a successful DM. 'always' posts it whatever the audience rule, dedupe or DM outcome: the moment a comment matches, or after commentReplyDelaySeconds when set (raised to dmDelaySeconds, so it never precedes the DM attempt).

isActiveboolean

Create the automation paused with false.

Response

Automation created

successboolean

Changes

    • warning

      removed the optional property // from the response with the status

    • warning

      removed the optional property // from the response with the status

    • warning

      removed the optional property // from the response with the status

    • warning

      added the new facebook enum value to the / response property for the response status

    • warning

      added the new instagram enum value to the / response property for the response status

    • warning

      added the new linkedin enum value to the / response property for the response status

    • warning

      added the new live_comment enum value to the / response property for the response status

    • warning

      added the new story_mention enum value to the / response property for the response status

    • warning

      added the new threads enum value to the / response property for the response status

    • warning

      added the new tiktok enum value to the / response property for the response status

    • warning

      added the new youtube enum value to the / response property for the response status

    • info

      added the new optional request property

    • info

      added the new optional request property

    • info

      added the new optional request property

    • info

      added the new optional request property

    • info

      added the new optional request property

    • info

      added the new optional request property

    • info

      added the new optional request property

    • info

      the request property became optional

    • info

      added the new live_comment enum value to the request property

    • info

      added the new story_mention enum value to the request property

    • info

      added the media type application/json for the response with the status

    • info

      added the optional property / to the response with the status

    • info

      added the optional property / to the response with the status

    • info

      added the optional property / to the response with the status

    • info

      added the optional property / to the response with the status

    • info

      added the optional property / to the response with the status

    • info

      added the optional property / to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • info

      added the optional property // to the response with the status

    • warning

      added the new account enum value to the / response property for the response status

    • warning

      added the new account enum value to the / response property for the response status