Overview
Lead Gen is a multi-step DM automation builder that allows users to create flows triggered by comments on posts or replies to stories. It supports lead collection (email, phone, name), delays, tags, button templates, and a followers-only gate. It works for:
- Single post automation - triggered by comments on a specific post
- Single story automation - triggered by replies to a specific story
- Global post automation - triggered by comments on ALL posts
- Global story automation - triggered by replies to ALL stories
1. Entry Points
1.1 Manage Post Page (Single Post/Story)
When a user opens a specific post or story to manage, the "Lead Gen" card appears alongside "Send Link or Images".
- Card title: "Lead Gen"
- Card description: "Build a multi-step DM automation with lead collection (email, phone, name), delays, tags, and button templates - all triggered by comments on this post."
- Toggle (Switch): Shows enabled/disabled based on whether
flow_idsfrom theautomate-postAPI response contains a key starting withcomment-flow- - Click action: Opens the Lead Gen flow editor (LinearFlowView)
Visibility rules:
- Shown for posts, stories, and global automations
- Hidden for collab posts where user doesn't have view permission
- Hidden when
igDetailhas an error (unless it's a scheduled post, FB, or global)
1.2 Global Automation Page
On the global automation list page, Lead Gen entries appear alongside regular trigger word automations.
- Display: Purple "Lead Gen" tag + trigger word tags + "Edit" button
- Data source: Extracted from
quick_gloabl_flow.triger_wordsin thequick-global-automate-postsAPI response - Edit URL:
/manage-post/{postId}?post_type={posts|stories}&platform_type={insta|fb}&is_global=true&lead_gen=true
2. API Endpoints
2.1 Get Post Automation Config
GET /automate-post?post_id={postId}
Response includes:
{
"data": { ... },
"ig_post_data": { ... },
"flow_ids": {
"comment-flow-{postId}": {
"automate_all": "false",
"trigger_words": ["keyword1", "keyword2"]
}
},
"code": 200
}
- If
flow_idscontains a key starting withcomment-flow-, Lead Gen is enabled for this post - NOT called when URL has
lead_gen=true(global lead gen edit)
2.2 Get Global Automation Config
GET /quick-global-automate-posts
GET /quick-global-automate-posts?is_story=true
Response includes:
{
"data": {
"triger_words": {
"*allwordautomation*": "uuid-id",
"keyword": "uuid-id"
}
},
"quick_gloabl_flow": {
"type": "comment_reply",
"triger_words": {
"trigger-word-name": ["comment-flow-{globalId}"]
}
},
"code": 200
}
- Entries in
quick_gloabl_flow.triger_wordswhere the flow ID array contains acomment-flow-prefixed ID are Lead Gen automations
2.3 Save Draft (Firebase)
Firestore: automations/{userId}/draft_automations/{flowId}
flowIdformat:comment-flow-{postId}- Stores the full flow payload +
cleanAutomationData(the LinearFlowView format) live: true/falseindicates publish status
2.4 Publish Flow
POST /flow_editor?flow_id=comment-flow-{postId}
Request body:
{
"name": "Flow Name",
"live": true,
"comment_automation": true,
"quick_dm": true,
"cleanAutomationData": { ... },
"nodes": [ ... ],
"edges": [ ... ]
}
2.5 Get Published Flow (for discard)
GET /flow_editor?flow_id=comment-flow-{postId}
2.6 Delete/Unpublish Flow
DELETE /flow_editor?flow_id=comment-flow-{postId}
2.7 Get Lead Gen Contacts
GET /flow_editor_response?flow_id=comment-flow-{postId}
Response:
{
"data": [
{
"created_at": "2026-04-05 17:13:14.206741",
"flow_completed": true,
"flow_id": "comment-flow-{postId}",
"message_count": "4",
"parent_id": "recipientId-senderId-flowId",
"question_response": [
{
"question": "email please",
"user_response": "user@example.com",
"skip": false,
"id": "q-1",
"sender_id": "4160762890722152",
"updated_at": "2026-04-05 17:13:34.472381"
}
],
"sender_detail": {
"id": "4160762890722152",
"username": "user_handle"
},
"sender_id": "4160762890722152",
"tags": [
{ "name": "tag-name", "id": "tagDocId" }
],
"contact_info": {
"flow_end": true,
"human_takeover": false,
"processing_by_ai": false
}
}
]
}
2.8 Save to Library (Firebase)
Firestore: saved_leadgen_automations/{autoDocId}
Document:
{
"user_id": "userId",
"name": "Flow Name",
"config": { ... },
"type": "lead_gen",
"flow_id": "comment-flow-{postId}",
"createdAt": serverTimestamp
}
3. Data Model - LinearFlowView Format (cleanAutomationData)
This is the simplified format stored in cleanAutomationData and used by the LinearFlowView editor.
{
"id": "comment-flow-{postId}",
"name": "Flow Name",
"live": false,
"isGlobal": false,
"trigger": {
"type": "comment_reply | story_reply",
"keywords": ["link", "info"],
"automate_all": false,
"match_exact_word": false,
"selected_posts": ["postId1"],
"all_posts": "true | false",
"all_stories": "true | false",
"comment_response": ["Thanks! Check DM", "Sent ✅"]
},
"welcome_message": {
"title": "Thanks for commenting! Click below to get your content.",
"description": "",
"button": "Send me the link"
},
"steps": [ ... ],
"confirmation": { "text": "" }
}
3.1 Trigger Types
Comment Reply (comment_reply):
keywords: array of trigger wordsautomate_all: boolean - automate all commentsmatch_exact_word: booleanselected_posts: array of post IDs (empty for global)all_posts:"true"for global,"false"for specific postcomment_response: array of reply comment texts (one random reply per comment)
Story Reply (story_reply):
keywords: array of trigger wordsautomate_all: boolean - automate all repliesmatch_exact_word: booleanselected_posts: array of story IDs (empty for global)all_stories:"true"for global,"false"for specific story- No
comment_response(stories don't have comments)
3.2 Welcome Message (Comment mode only, NOT for stories)
{
"title": "Thanks for commenting! Click below to get your content.",
"description": "",
"button": "Send me the link"
}
- Rendered as a button template card in DM
- User taps the button → proceeds to next step
- Default title: "Thanks for commenting! Click below to get your content."
- Default button: "Send me the link"
4. Step Types
4.1 Message (type: "message")
{
"id": "step-123",
"type": "message",
"messageType": "text | button | image",
"text": "Here is your link: https://example.com",
"image_url": "https://...",
"templates": [
{
"id": "tpl-123",
"title": "Card Title",
"description": "Card description",
"thumb_url": "https://...",
"buttons": [
{ "title": "Visit", "url": "https://...", "type": "web_url" }
]
}
]
}
- Text: plain text message, supports link preview (first URL extracted via regex, preview fetched from
https://curly-surf-0de5.sanjayhotaction.workers.dev/?url={encodedUrl}) - Button: card template with title, description, image, up to 3 buttons with URLs
- Image: image message with
image_url
4.2 Question (type: "question")
{
"id": "step-123",
"type": "question",
"questionType": "email | phone | name | custom_input",
"question": "What's your email?",
"skip_option": { "enable": false },
"retry_attempt": { "count": 3 },
"wrong_input": { "message": "" },
"variable": ""
}
- Bot sends the question, waits for user response
questionTypedetermines validation:emailvalidates email format,phonevalidates phone,nameaccepts any text,custom_inputaccepts any textskip_option.enable: if true, user can skip this questionretry_attempt.count: number of retries on invalid input
4.3 Delay (type: "delay")
{
"id": "step-123",
"type": "delay",
"duration": 3,
"durationType": "s | m | h"
}
- Pauses the flow for the specified duration
s= seconds,m= minutes,h= hours
4.4 Tag Contact (type: "tag")
{
"id": "step-123",
"type": "tag",
"tags": ["tagId1", "tagId2"],
"tagsData": [
{ "label": "VIP", "value": "tagId1", "name": "VIP" }
]
}
- Tags the contact with specified tags
- Tags are fetched from
Firestore: users/{userId}/tags
4.5 Followers Only Gate (type: "followers_only")
{
"id": "step-123",
"type": "followers_only",
"message_reply": "true | false",
"message": {
"title": "Follow for exclusive content",
"description": "",
"open_profile_text": "Open Profile",
"button": "I started following you"
},
"follow_up_duration": 30,
"follow_up_duration_type": "m"
}
Behavior:
- Checks if the user follows the account
- If following: proceeds to next step via
{nodeId}-follow-flowconnection - If NOT following and
message_reply= "true": sends a button template with:- Title + description
- "Open Profile" button - opens the account profile
- "I started following you" button - re-checks if user followed
- If NOT following and
message_reply= "false": routes to a separate flow (not used in LinearFlowView) - Follow-up: if enabled (
follow_up_duration > 0), after the specified time, moves to next step via{nodeId}-followupconnection even if user didn't follow
Edge connections (important for payload):
{nodeId}-follow-flow-right→ connects to next step (user IS following){nodeId}-followup-right→ connects to next step (follow-up timer expired, only iffollow_up_duration > 0)- Regular edges use
{nodeId}-rightas sourceHandle
5. Flow Editor Payload (nodes/edges format)
The LinearFlowView format is converted to the flow editor payload for the backend. This is the nodes and edges format.
5.1 Node Types
| LinearFlowView type | Node type | Notes |
|---|---|---|
| trigger | triggerComp | Always node-1, contains auto_reply config |
| message | messageReply | Contains messages array |
| question | questionNode | Contains messages array with question config |
| delay | messageReply | Message with type: "delay" |
| tag | tagContact | Contains tags and tagsData |
| followers_only | followersOnly | Contains followers_only, message, follow_up_duration |
5.2 Trigger Node Data Structure
{
"id": "node-1",
"type": "triggerComp",
"data": {
"auto_reply": {
"dm_reply": {
"enabled": false,
"automate_all": "false",
"triger_words": []
},
"story_reply": {
"enabled": true,
"automate_all": "true | false",
"triger_words": ["keyword"],
"all_stories": "true | false",
"selected_posts": [],
"match_exact_word": false
},
"comment_reply": {
"enabled": true,
"automate_all": "true | false",
"triger_words": ["keyword"],
"all_posts": "true | false",
"selected_posts": ["postId"],
"comment_response": ["reply text"],
"match_exact_word": false
},
"welcome_message": {
"title": "...",
"description": "",
"button": "Send me the link"
}
}
}
}
- Only ONE of
story_reply.enabledorcomment_reply.enabledistrue dm_replyis always disabled for Lead Gen
5.3 Edge Structure
{
"id": "e-node-1-step-1",
"source": "node-1",
"target": "step-1",
"sourceHandle": "node-1-right",
"targetHandle": "step-1-left",
"type": "custom-edge",
"markerEnd": { "type": "arrowclosed" },
"data": {}
}
Special edge handles for followers_only:
- Source from followers_only to next step:
sourceHandle: "{nodeId}-follow-flow-right" - Follow-up edge (only if
follow_up_duration > 0):sourceHandle: "{nodeId}-followup-right"
6. UI Screens & Components
6.1 Trigger Configuration (Entry Point card)
For Comment mode (posts):
- Post preview (image, caption, likes, comments) - or "🌐 All Posts - Global Automation" banner for global
- Step 1: Trigger Keywords - Custom Keywords / All Comments toggle, keyword input, match exact word checkbox
- Step 2: Reply to Comment (optional) - comment reply input, displayed as tags
- Step 3: Welcome Message - button template card editor (title + button text, no description, no image)
For Story mode:
- Story preview (image, caption, username) - or "🌐 All Stories - Global Automation" banner for global
- Step 1: Trigger Keywords - Custom Keywords / All Replies toggle, keyword input, match exact word checkbox
- No welcome message
- No reply to comment
6.2 Step Editor Cards
Each step is rendered as a card in the flow timeline with:
- Step type icon and label (e.g., "MESSAGE", "QUESTION", "FOLLOWERS ONLY")
- Inline editing (click to edit text, buttons, etc.)
- Move up/down buttons
- Delete button
- "Add Step" button between steps
6.3 Chat Preview (Phone Mockup)
Comment mode - two tabs:
- 💬 Comment tab: Instagram post image full-screen with bottom sheet overlay showing trigger comments and reply comments
- ✉️ DMs tab: DM conversation preview with context line "You replied to lead for commenting on your post", welcome message card, and all steps
Story mode - no tabs, DM view only:
- Context line: "Lead replied to your story"
- Story thumbnail image + trigger keyword with typing animation (stacked vertically)
- Steps rendered below
Tab switching:
- Editing trigger keywords or reply comments → switches to Comment tab
- Editing welcome message or steps → switches to DMs tab
- Story mode always shows DM view
6.4 Followers Only Gate Card
Displays:
- "Followers Only Gate" header with icon
- "If not following:" label
- Button template card with:
- Title (editable)
- Description (editable)
- "Open Profile" button (editable text)
- "I started following you" button (editable text)
- "🔄 'I started following you' → re-checks if user followed" info line
- "Move to next step if not followed" toggle with time delay (number + sec/min/hour)
- "✅ Move to next step" indicator inside the follow-up section
6.5 Lead Gen Contacts Table
Displayed in the manage post page's second tab (replaces "All Comments" when Lead Gen is enabled).
Table columns:
- Contact: avatar, name, @username, Instagram icon link (
https://instagram.com/{username}) - Tags: colored tag pills
- Date:
created_atformatted to local time - Status: "Completed" (green) or "In Progress" (orange)
Expandable rows: question responses with question text and user's answer (or "Skipped" tag)
CSV Download: exports Username, Name, Instagram URL, all question responses as dynamic columns, Tags, Status, Date
7. Link Preview
For text messages containing URLs, a link preview is shown.
Extraction: First https:// or http:// URL extracted via regex from message text.
Preview API:
GET https://curly-surf-0de5.sanjayhotaction.workers.dev/?url={encodedUrl}
Response:
{
"title": "Page Title",
"description": "Page description",
"image": "https://og-image-url.jpg"
}
Display: Card with image, title, description, domain - rendered ABOVE the text message.
8. Publish Flow
8.1 Save to Draft
- Saves to Firebase:
automations/{userId}/draft_automations/comment-flow-{postId} - Includes both the flow editor payload (nodes/edges) and
cleanAutomationData(LinearFlowView format)
8.2 Publish & Activate
- Save draft first
- POST to
/flow_editor?flow_id=comment-flow-{postId}withlive: true - Update Firebase draft with
live: true - Save to library:
saved_leadgen_automationscollection - Show success message, reload page after 1.5s
8.3 Discard Draft
- GET
/flow_editor?flow_id=comment-flow-{postId}to fetch live version - Overwrite Firebase draft with live version
- Reload the editor
9. Flow ID Convention
| Context | Flow ID format | Example |
|---|---|---|
| Single post | comment-flow-{igPostId} | comment-flow-18131564404539322 |
| Single story | comment-flow-{igStoryId} | comment-flow-18131564404539322 |
| Global post | comment-flow-{globalUUID} | comment-flow-2336b1c4-61a7-4d27-b2f3-78caa76da97b |
| Global story | comment-flow-{globalUUID} | comment-flow-2336b1c4-61a7-4d27-b2f3-78caa76da97b |
10. URL Parameters
| Parameter | Values | Description |
|---|---|---|
post_type | posts, stories, live, next-post | Type of content being automated |
platform_type | insta, fb | Platform |
is_global | true | Global automation (all posts/stories) |
lead_gen | true | Lead Gen edit mode - skips automate-post API call, sets default empty data |
flow_editor | true/false | Legacy flow editor flag |
11. Detection Logic
Is Lead Gen enabled for a post?
const hasLeadGen = Object.keys(flowIds).some(k => k.startsWith('comment-flow-'));
Is it a Lead Gen entry in global automation list?
const commentFlowId = (flowIds || []).find(fid => fid.startsWith('comment-flow-'));
Should we show Lead Gen contacts instead of regular comments?
const showLeadGenContacts = Object.keys(flowIds).some(k => k.startsWith('comment-flow-'));
12. Known Issues / Missing Items
No
global_automationflag in publish payload -convertToFlowPayloaddoesn't includeglobal_automation: truefor global automations. The regular publish adds this. Backend may need it.Lead Gen disable doesn't unpublish the flow - The Switch toggle on the Lead Gen card calls
showConfirm('Auto Reply')which disables the regular automation. It should callDELETE /flow_editor?flow_id=comment-flow-{postId}to unpublish the lead gen flow.Library saves duplicate on every publish -
addDoccreates a new document each time. Should usesetDocwith the flow ID as document ID, or check for existing entry first.one_time_onlynot exposed - The flow editor trigger has aone_time_onlyoption (reply once per day vs first time only). Not exposed in the Lead Gen editor UI.post_typenot in flow payload - The regular publish addspost_type: "story"for stories. The Lead Gen publish doesn't include this.No Shopify product step - The flow editor supports Shopify product nodes but the LinearFlowView doesn't have this step type.
AI Reply node - The flow editor has an AI Reply node. Not available in LinearFlowView.