{
  "id": "wk6WjT2zWgwUiTlK",
  "name": "LinkedIn Auto-Reply Workflow with Smart Resource Delivery",
  "tags": [],
  "nodes": [
    {
      "id": "5df2657c-0cc3-4cf8-8451-01a7a2aaa073",
      "name": "Every 5 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "notes": "Runs every 5 minutes to check for new LinkedIn comments",
      "position": [
        -128,
        848
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 1.2
    },
    {
      "id": "c15f846b-5b11-4e74-ab8f-09c2884ca023",
      "name": "Fetch Recent Posts",
      "type": "n8n-nodes-base.linkedIn",
      "notes": "Gets your 10 most recent LinkedIn posts",
      "position": [
        96,
        848
      ],
      "parameters": {
        "operation": "getAll",
        "authentication": "oAuth2"
      },
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "5a0de7f6-4adb-403d-9968-3929f0a7c089",
      "name": "Fetch Post Comments",
      "type": "n8n-nodes-base.linkedIn",
      "notes": "Retrieves all comments from each post (up to 20 per post)",
      "position": [
        320,
        848
      ],
      "parameters": {
        "resource": "comment",
        "authentication": "oAuth2"
      },
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "90fd1e95-4801-4c06-ad00-7c11eac13099",
      "name": "Remove Own Comments",
      "type": "n8n-nodes-base.filter",
      "notes": "Filters out your own comments to prevent self-messaging",
      "position": [
        544,
        848
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "3c4d5e6f-7g8h-9i0j-1k2l-m3n4o5p6q7r8",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.author.id }}",
              "rightValue": "={{ $('Fetch Recent Posts').item.json.author.id }}"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "adeb662f-0e35-450e-8212-9afa27386fca",
      "name": "Combine Comment and Post",
      "type": "n8n-nodes-base.merge",
      "notes": "Merges comment data with original post context",
      "position": [
        768,
        848
      ],
      "parameters": {
        "mode": "combine",
        "options": {}
      },
      "notesInFlow": true,
      "typeVersion": 3
    },
    {
      "id": "1eb2db53-0361-4847-8f89-2499aa679ad9",
      "name": "Track Processed Comments",
      "type": "n8n-nodes-base.code",
      "notes": "Prevents duplicate messages using workflow static data",
      "position": [
        992,
        848
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Check if we've already sent a DM to this commenter on this post\nconst commentId = $input.item.json.id;\nconst authorId = $input.item.json.author.id;\nconst postId = $input.item.json.postId || 'unknown';\n\n// Create a unique key for this comment\nconst uniqueKey = `${postId}_${authorId}_${commentId}`;\n\n// Use workflow static data to store processed comments\nconst processedComments = $getWorkflowStaticData('global').processedComments || {};\n\nif (processedComments[uniqueKey]) {\n  // Already processed this comment\n  return { json: { skip: true, reason: 'Already processed' } };\n}\n\n// Mark as processed\nprocessedComments[uniqueKey] = {\n  timestamp: new Date().toISOString(),\n  processed: true\n};\n\n// Clean up old entries (older than 30 days)\nconst thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);\nfor (const key in processedComments) {\n  const entryTime = new Date(processedComments[key].timestamp).getTime();\n  if (entryTime < thirtyDaysAgo) {\n    delete processedComments[key];\n  }\n}\n\n// Save back to static data\n$getWorkflowStaticData('global').processedComments = processedComments;\n\nreturn { \n  json: { \n    skip: false, \n    ...($input.item.json),\n    uniqueKey \n  } \n};"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "44a95a29-09f7-4b89-8b53-405ca6e501f0",
      "name": "Rate Limit Delay",
      "type": "n8n-nodes-base.wait",
      "notes": "Adds delay to avoid LinkedIn rate limits",
      "position": [
        1200,
        848
      ],
      "parameters": {
        "amount": 2
      },
      "notesInFlow": true,
      "typeVersion": 1.1
    },
    {
      "id": "c0b81984-43fb-4d57-b981-a93d12ba1648",
      "name": "Only New Comments",
      "type": "n8n-nodes-base.filter",
      "notes": "Filters to unprocessed comments only",
      "position": [
        1424,
        848
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "7g8h9i0j-1k2l-3m4n-5o6p-q7r8s9t0u1v2",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.skip }}",
              "rightValue": "false"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "a9acec03-c9c4-4d22-bc8d-68c9a1a9fa0d",
      "name": "Match Resource to Comment",
      "type": "n8n-nodes-base.code",
      "notes": "Analyzes comment content and selects most relevant resource",
      "position": [
        1648,
        848
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Analyze comment to determine relevant resource\nconst commentText = ($input.item.json.text || '').toLowerCase();\nconst postText = ($input.item.json.postText || '').toLowerCase();\n\n// Keywords for different resource categories\nconst resourceMap = {\n  'ebook': {\n    keywords: ['learn', 'guide', 'tutorial', 'how to', 'beginner', 'start', 'ebook', 'book', 'read'],\n    resource: {\n      title: '\ud83d\udcda Free eBook: Complete Guide to LinkedIn Marketing',\n      url: 'https://yourwebsite.com/linkedin-marketing-ebook',\n      description: 'A comprehensive guide covering everything from profile optimization to content strategy.'\n    }\n  },\n  'webinar': {\n    keywords: ['watch', 'video', 'webinar', 'training', 'course', 'learn more', 'session'],\n    resource: {\n      title: '\ud83c\udfa5 Free Webinar: Advanced LinkedIn Strategies',\n      url: 'https://yourwebsite.com/webinar-registration',\n      description: 'Join our live webinar to learn advanced tactics from industry experts.'\n    }\n  },\n  'template': {\n    keywords: ['template', 'example', 'sample', 'format', 'structure', 'framework'],\n    resource: {\n      title: '\ud83d\udccb Free Templates: LinkedIn Content Calendar',\n      url: 'https://yourwebsite.com/content-templates',\n      description: 'Download our proven templates to plan and organize your LinkedIn content.'\n    }\n  },\n  'tool': {\n    keywords: ['tool', 'software', 'app', 'automate', 'automation', 'schedule', 'analytics'],\n    resource: {\n      title: '\ud83d\udee0\ufe0f Free Tool: LinkedIn Analytics Dashboard',\n      url: 'https://yourwebsite.com/analytics-tool',\n      description: 'Track your LinkedIn performance with our free analytics dashboard.'\n    }\n  },\n  'checklist': {\n    keywords: ['checklist', 'steps', 'process', 'list', 'tips', 'best practices'],\n    resource: {\n      title: '\u2705 Free Checklist: LinkedIn Profile Optimization',\n      url: 'https://yourwebsite.com/profile-checklist',\n      description: 'A step-by-step checklist to optimize your LinkedIn profile for maximum visibility.'\n    }\n  }\n};\n\n// Determine which resource to send\nlet selectedResource = null;\nlet maxMatches = 0;\n\nfor (const [category, data] of Object.entries(resourceMap)) {\n  let matches = 0;\n  for (const keyword of data.keywords) {\n    if (commentText.includes(keyword) || postText.includes(keyword)) {\n      matches++;\n    }\n  }\n  \n  if (matches > maxMatches) {\n    maxMatches = matches;\n    selectedResource = data.resource;\n  }\n}\n\n// Default resource if no specific match\nif (!selectedResource) {\n  selectedResource = {\n    title: '\ud83c\udf81 Free Resource Pack: LinkedIn Success Bundle',\n    url: 'https://yourwebsite.com/linkedin-bundle',\n    description: 'Get access to our complete resource pack including guides, templates, and tools.'\n  };\n}\n\nreturn {\n  json: {\n    ...($input.item.json),\n    selectedResource,\n    commenterName: $input.item.json.author?.firstName || 'there'\n  }\n};"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "fd16c4dd-d8e4-404e-8471-db0442b4f0f9",
      "name": "Build Personalized Message",
      "type": "n8n-nodes-base.code",
      "notes": "Generates personalized DM with commenter's name and resource",
      "position": [
        1872,
        848
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Create personalized message\nconst commenterName = $input.item.json.commenterName;\nconst resource = $input.item.json.selectedResource;\n\nconst message = `Hi ${commenterName}! \ud83d\udc4b\n\nThank you so much for engaging with my post! I really appreciate your comment.\n\nI thought you might find this helpful:\n\n${resource.title}\n${resource.description}\n\n\ud83d\udd17 Access it here: ${resource.url}\n\nFeel free to reach out if you have any questions. Happy to help! \ud83d\ude80\n\nBest regards`;\n\nreturn {\n  json: {\n    ...($input.item.json),\n    messageToSend: message\n  }\n};"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "836850e7-067a-4863-8949-63686fde80b8",
      "name": "Send DM via LinkedIn",
      "type": "n8n-nodes-base.linkedIn",
      "notes": "Delivers the direct message to the commenter",
      "position": [
        2160,
        848
      ],
      "parameters": {
        "resource": "message",
        "authentication": "oAuth2"
      },
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "aabec416-e03f-43a6-a3a6-d258280ee933",
      "name": "Log Delivery Status",
      "type": "n8n-nodes-base.code",
      "notes": "Records successful message delivery for tracking",
      "position": [
        2384,
        848
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Log successful send\nconst timestamp = new Date().toISOString();\nconst commenterName = $input.item.json.commenterName;\nconst resourceTitle = $input.item.json.selectedResource.title;\n\nconsole.log(`\u2705 SUCCESS: Sent resource \"${resourceTitle}\" to ${commenterName} at ${timestamp}`);\n\nreturn {\n  json: {\n    success: true,\n    timestamp,\n    commenterName,\n    resourceSent: resourceTitle,\n    commentId: $input.item.json.id\n  }\n};"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "94582886-f0ba-41ac-8682-b701e3df87d5",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -928,
        464
      ],
      "parameters": {
        "width": 636,
        "height": 776,
        "content": "## Auto-reply to LinkedIn comments with personalized resources\n\nThis workflow monitors your LinkedIn posts for new comments and automatically sends personalized direct messages with relevant resources to commenters.\n\n## How it works\n\n1. **Monitor posts**: Every 5 minutes, the workflow fetches your 10 most recent LinkedIn posts\n2. **Collect comments**: Retrieves all comments from each post (up to 20 per post)\n3. **Filter engagement**: Removes your own comments and tracks previously contacted users\n4. **Smart matching**: Analyzes comment text using keyword matching to determine the most relevant resource (eBook, webinar, template, tool, or checklist)\n5. **Personalize message**: Creates a custom DM with the commenter's name and selected resource\n6. **Send and track**: Delivers the message via LinkedIn and logs the interaction\n\n## Setup steps\n\n1. **Connect LinkedIn**: Add your LinkedIn OAuth2 credentials to these nodes:\n   - Fetch Recent Posts\n   - Fetch Post Comments\n   - Send DM via LinkedIn\n\n2. **Update resource URLs**: Open the \"Match Resource to Comment\" node and replace all `https://yourwebsite.com/...` URLs with your actual resource links\n\n3. **Customize message** (optional): Edit the \"Build Personalized Message\" node to adjust the DM template and tone\n\n4. **Test first**: Click \"Execute Workflow\" to test before activating. Check the execution log to verify it works correctly\n\n5. **Activate**: Once tested, toggle the workflow to \"Active\" to run automatically every 5 minutes\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1c508416-773c-4c8f-9922-f3f7daa46745",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -176,
        688
      ],
      "parameters": {
        "color": 6,
        "width": 640,
        "height": 336,
        "content": "## \ud83d\udce5 Data Collection"
      },
      "typeVersion": 1
    },
    {
      "id": "e86e64a1-c3d7-4467-b08e-dbc92a62878e",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        688
      ],
      "parameters": {
        "color": 4,
        "width": 1088,
        "height": 320,
        "content": "## \ud83d\udd0d Smart Filtering"
      },
      "typeVersion": 1
    },
    {
      "id": "7d8d06dc-cd7a-4845-82d7-e1d26205f0f3",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1600,
        688
      ],
      "parameters": {
        "color": 6,
        "width": 464,
        "height": 336,
        "content": "## \ud83e\udde0 Resource Matching"
      },
      "typeVersion": 1
    },
    {
      "id": "5befb33e-7494-42a1-b4a4-ffdda316bed2",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2096,
        688
      ],
      "parameters": {
        "color": 4,
        "width": 464,
        "height": 368,
        "content": "## \ud83d\udce8 Message Delivery"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "bd52e147-07f1-4ca4-a13d-6845f7e71abd",
  "connections": {
    "Every 5 Minutes": {
      "main": [
        [
          {
            "node": "Fetch Recent Posts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rate Limit Delay": {
      "main": [
        [
          {
            "node": "Only New Comments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Only New Comments": {
      "main": [
        [
          {
            "node": "Match Resource to Comment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Recent Posts": {
      "main": [
        [
          {
            "node": "Fetch Post Comments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Post Comments": {
      "main": [
        [
          {
            "node": "Remove Own Comments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Own Comments": {
      "main": [
        [
          {
            "node": "Combine Comment and Post",
            "type": "main",
            "index": 0
          },
          {
            "node": "Combine Comment and Post",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Send DM via LinkedIn": {
      "main": [
        [
          {
            "node": "Log Delivery Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine Comment and Post": {
      "main": [
        [
          {
            "node": "Track Processed Comments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Track Processed Comments": {
      "main": [
        [
          {
            "node": "Rate Limit Delay",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Match Resource to Comment": {
      "main": [
        [
          {
            "node": "Build Personalized Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Personalized Message": {
      "main": [
        [
          {
            "node": "Send DM via LinkedIn",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}