{
  "id": "DnElB0XzSfbT1ura",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Smart Lead Score Drop Alert & Recovery Workflow",
  "tags": [
    {
      "id": "4Of2LE0HSt4qmmUG",
      "name": "Ansh",
      "createdAt": "2026-04-20T10:32:01.726Z",
      "updatedAt": "2026-04-20T10:32:01.726Z"
    }
  ],
  "nodes": [
    {
      "id": "afd25691-b5f9-4dc8-87df-ff232bac81a4",
      "name": "Sticky Note \u2014 Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1024,
        1680
      ],
      "parameters": {
        "width": 564,
        "height": 752,
        "content": "## Smart Lead Score Drop Alert & Recovery Workflow\nThis workflow automatically watches for leads in HubSpot whose score has dropped below a set threshold. When it finds at-risk leads, it alerts the right sales rep on Slack, creates a follow-up task, sends the contact a re-engagement email, and logs everything \u2014 with deduplication so your team never gets spammed.\n\n### How it works\n\n\t\u2022\tRuns every hour and fetches low-score contacts from HubSpot.\n\t\u2022\tChecks a Google Sheet to skip contacts already alerted in the last 24 hours.\n\t\u2022\tLooks up the contact owner in HubSpot to route the alert to the right sales rep.\n\t\u2022\tDetermines urgency \u2014 critical (under 20) or standard warning (under 50).\n\t\u2022\tSends a personalised Slack DM to the contact owner and posts to the sales channel.\n\t\u2022\tCreates a follow-up task in HubSpot on the contact record.\n\t\u2022\tSends an automatic re-engagement email to the contact via Gmail.\n\t\u2022\tLogs the full alert to Google Sheets and handles any errors gracefully.\n\n### Setup Steps\n\n\t1.\tConnect HubSpot, Slack, Gmail, and Google Sheets credentials in n8n.\n\t2.\tCreate a Google Sheet named 'Lead Score Alerts' with columns: Timestamp, Contact ID, Contact Name, Email, Score, Urgency, Owner Email, Lead Status.\n\t3.\tCreate a second sheet tab named 'Alert Dedup Log' with columns: contact_id, last_alerted.\n\t4.\tUpdate the Slack channel names and Gmail sender address in the relevant nodes.\n\t5.\tTurn on the workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "8156f9d9-7ffe-49fd-976c-77814f5034c2",
      "name": "Sticky Note \u2014 Step 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1600,
        1680
      ],
      "parameters": {
        "color": 7,
        "width": 1360,
        "height": 752,
        "content": "## Step 1: Fetch & Deduplicate At-Risk Leads\nEvery hour this workflow wakes up and pulls contacts from HubSpot who have a low lead score. It then checks a log sheet to see if any of those contacts were already alerted recently. This stops your team from being bombarded with the same alert over and over."
      },
      "typeVersion": 1
    },
    {
      "id": "68e15a92-3b13-4424-99d7-0dfb0117ad2f",
      "name": "Sticky Note \u2014 Step 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2976,
        1680
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 752,
        "content": "## Step 2: Score Check, Owner Lookup & Urgency Routing\nFor each new at-risk contact, the workflow checks how serious the score drop is and finds out who owns that lead in HubSpot. It then routes the alert differently depending on whether the situation is critical or just a warning."
      },
      "typeVersion": 1
    },
    {
      "id": "5858cfb7-4542-470c-872d-a0f606f43f4f",
      "name": "Sticky Note \u2014 Step 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3632,
        1680
      ],
      "parameters": {
        "color": 7,
        "width": 1312,
        "height": 752,
        "content": "## Step 3: Alert, Task, Re-Engagement & Logging\nOnce urgency is decided, the workflow sends a Slack alert to the right sales rep, creates a follow-up task in HubSpot, and sends the contact a re-engagement email. Every action is logged to Google Sheets so managers can track trends over time."
      },
      "typeVersion": 1
    },
    {
      "id": "2bb2120c-ada2-4038-a0de-8fd19734ec60",
      "name": "Sticky Note \u2014 Step 4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4960,
        1680
      ],
      "parameters": {
        "color": 7,
        "width": 848,
        "height": 752,
        "content": "## Step 4: Error Handling & Admin Notification\nIf anything goes wrong at any point in the workflow, this section catches the error. It immediately sends a Slack message to the admin so the issue can be investigated quickly. This ensures no silent failures go unnoticed in production."
      },
      "typeVersion": 1
    },
    {
      "id": "d6702b1f-62c5-4b1d-b25b-3b69112346dc",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        1632,
        2032
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ca7212a5-e21c-4bfe-adfc-ec7afe03760f",
      "name": "HubSpot \u2014 Get Low Score Contacts",
      "type": "n8n-nodes-base.hubspot",
      "position": [
        1856,
        2032
      ],
      "parameters": {
        "operation": "getAll",
        "authentication": "oAuth2",
        "additionalFields": {}
      },
      "typeVersion": 2
    },
    {
      "id": "90725459-f7d6-4123-96bc-3f4a1654152a",
      "name": "Google Sheets \u2014 Read Dedup Log",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2096,
        2032
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Alert Dedup Log"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_YOUR_SHEET_ID"
        },
        "authentication": "serviceAccount"
      },
      "typeVersion": 4.5
    },
    {
      "id": "306df45e-4367-4fbf-9fdb-c20b6a48fc6a",
      "name": "Code \u2014 Deduplicate & Enrich",
      "type": "n8n-nodes-base.code",
      "position": [
        2336,
        2032
      ],
      "parameters": {
        "jsCode": "// Build a dedup map from the sheet rows\nconst allItems = $input.all();\n\n// Separate the HubSpot contacts (passed via $('HubSpot \u2014 Get Low Score Contacts').all())\n// and the dedup sheet rows which come through sequentially.\n// We merge them using the static data pattern: contacts come first, sheet rows second.\n// In practice this node is wired after the sheet read, so we use $node to access both.\n\nconst contacts = $('HubSpot \u2014 Get Low Score Contacts').all();\nconst dedupRows = $('Google Sheets \u2014 Read Dedup Log').all();\n\nconst now = new Date();\nconst twentyFourHoursAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);\n\n// Build a set of recently alerted contact IDs\nconst recentlyAlerted = new Set();\nfor (const row of dedupRows) {\n  const lastAlerted = new Date(row.json.last_alerted);\n  if (lastAlerted > twentyFourHoursAgo) {\n    recentlyAlerted.add(String(row.json.contact_id));\n  }\n}\n\n// Filter out already-alerted contacts and build enriched output\nconst results = [];\nfor (const item of contacts) {\n  const props = item.json.properties || item.json;\n  const contactId = String(item.json.id || item.json.vid || '');\n  const score = parseInt(props.hubspotscore || 0);\n  const firstname = props.firstname || 'Unknown';\n  const lastname = props.lastname || '';\n  const email = props.email || '';\n  const leadStatus = props.hs_lead_status || 'Unknown';\n  const ownerId = props.hubspot_owner_id || '';\n\n  if (score < 50 && !recentlyAlerted.has(contactId)) {\n    results.push({\n      json: {\n        contactId,\n        fullName: `${firstname} ${lastname}`.trim(),\n        email,\n        score,\n        leadStatus,\n        ownerId,\n        urgency: score < 20 ? 'CRITICAL' : 'WARNING',\n        timestamp: now.toISOString()\n      }\n    });\n  }\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "ae5148c7-d196-4bcf-8e52-bfbb83266c46",
      "name": "IF \u2014 Any Contacts Left?",
      "type": "n8n-nodes-base.if",
      "position": [
        2576,
        2032
      ],
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{ $json.score }}",
              "operation": "smallerEqual"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c617e2d7-57ae-4347-84c3-6bd7e6bca612",
      "name": "HubSpot \u2014 Get Contact Owner",
      "type": "n8n-nodes-base.hubspot",
      "position": [
        3024,
        2048
      ],
      "parameters": {
        "resource": "owner",
        "authentication": "oAuth2"
      },
      "typeVersion": 2
    },
    {
      "id": "e0d10699-e6c2-4cfb-b492-d6cfb1da07e1",
      "name": "Code \u2014 Merge Owner & Build Alert",
      "type": "n8n-nodes-base.code",
      "position": [
        3216,
        2144
      ],
      "parameters": {
        "jsCode": "// Merge owner details back onto the contact item\nconst contactData = $('Code \u2014 Deduplicate & Enrich').item.json;\nconst ownerData = $input.item.json;\n\nconst ownerEmail = ownerData.email || '';\nconst ownerFirstName = ownerData.firstName || 'Sales Rep';\nconst ownerSlackHandle = ownerEmail.split('@')[0]; // fallback Slack handle from email prefix\n\nconst urgency = contactData.urgency;\nconst score = contactData.score;\n\nreturn [{\n  json: {\n    ...contactData,\n    ownerEmail,\n    ownerFirstName,\n    ownerSlackHandle,\n    slackChannel: urgency === 'CRITICAL' ? 'sales-urgent' : 'sales-alerts',\n    alertColor: urgency === 'CRITICAL' ? '#FF0000' : '#FFA500',\n    alertEmoji: urgency === 'CRITICAL' ? '\ud83d\udea8' : '\u26a0\ufe0f',\n    alertMessage: urgency === 'CRITICAL'\n      ? `\ud83d\udea8 *CRITICAL score drop* \u2014 *${contactData.fullName}* (${contactData.email}) scored *${score}*. Assign to: ${ownerFirstName}. Immediate action needed.`\n      : `\u26a0\ufe0f *Lead score warning* \u2014 *${contactData.fullName}* (${contactData.email}) scored *${score}*. Owner: ${ownerFirstName}. Follow-up recommended.`\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "07d893cf-f7e3-4ac1-af81-4ccc720eb3e4",
      "name": "IF \u2014 Critical or Warning?",
      "type": "n8n-nodes-base.if",
      "position": [
        3440,
        2144
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.urgency }}",
              "value2": "CRITICAL",
              "operation": "equals"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "89e09617-7a50-4728-8b50-eca1fc618d6d",
      "name": "Slack \u2014 Critical Alert to Channel",
      "type": "n8n-nodes-base.slack",
      "position": [
        3680,
        2048
      ],
      "parameters": {
        "text": "={{ $json.alertMessage }}",
        "otherOptions": {
          "mrkdwn": true
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 2.2
    },
    {
      "id": "144087e7-621f-4abe-af47-049d06735ad6",
      "name": "Slack \u2014 Warning Alert to Channel",
      "type": "n8n-nodes-base.slack",
      "position": [
        3680,
        2256
      ],
      "parameters": {
        "text": "={{ $json.alertMessage }}",
        "otherOptions": {
          "mrkdwn": true
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 2.2
    },
    {
      "id": "33dd5d87-6601-4939-9693-328a15e90b4d",
      "name": "Slack \u2014 DM to Contact Owner",
      "type": "n8n-nodes-base.slack",
      "position": [
        3936,
        2144
      ],
      "parameters": {
        "text": "=Hey {{ $json.ownerFirstName }}, one of your leads just dropped to a low score.\n\n*Contact:* {{ $json.fullName }}\n*Email:* {{ $json.email }}\n*Score:* {{ $json.score }}\n*Urgency:* {{ $json.urgency }}\n\nPlease follow up as soon as possible.",
        "otherOptions": {
          "mrkdwn": true
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 2.2
    },
    {
      "id": "74e7c382-97e5-4392-a833-1e00ad1e9294",
      "name": "HubSpot \u2014 Create Follow-Up Task",
      "type": "n8n-nodes-base.hubspot",
      "position": [
        4144,
        2144
      ],
      "parameters": {
        "resource": "task",
        "authentication": "oAuth2"
      },
      "typeVersion": 2
    },
    {
      "id": "3ebac387-9f6d-43d8-acc8-1b6c14826e64",
      "name": "Gmail \u2014 Re-Engagement Email to Contact",
      "type": "n8n-nodes-base.gmail",
      "position": [
        4336,
        2144
      ],
      "parameters": {
        "sendTo": "={{ $json.email }}",
        "message": "=<p>Hi {{ $json.fullName.split(' ')[0] }},</p><p>We noticed you haven't been as active recently and wanted to check in. We'd love to help you get back on track and make sure you're getting the most value from us.</p><p>Would you be open to a quick 15-minute call this week? Just reply to this email and we'll sort a time that works for you.</p><p>Looking forward to hearing from you.</p><p>Best,<br>{{ $json.ownerFirstName }}<br>Your {{ $json.ownerFirstName }} at [Your Company]</p>",
        "options": {
          "replyTo": "={{ $json.ownerEmail }}"
        },
        "subject": "=We miss you, {{ $json.fullName.split(' ')[0] }} \u2014 let's reconnect"
      },
      "typeVersion": 2.1
    },
    {
      "id": "3077651a-02fc-461b-a88a-626ac8187a06",
      "name": "Google Sheets \u2014 Log Alert",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4528,
        2144
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Lead Score Alerts"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_YOUR_SHEET_ID"
        },
        "authentication": "serviceAccount"
      },
      "typeVersion": 4.5
    },
    {
      "id": "e297511b-b47f-4bc6-91a2-d864516abaed",
      "name": "Google Sheets \u2014 Update Dedup Log",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4736,
        2144
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Alert Dedup Log"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_YOUR_SHEET_ID"
        },
        "authentication": "serviceAccount"
      },
      "typeVersion": 4.5
    },
    {
      "id": "bd33dcd1-5ab2-4b84-8fd8-009982e9a1a2",
      "name": "Slack \u2014 Error Alert to Admin",
      "type": "n8n-nodes-base.slack",
      "position": [
        5024,
        1792
      ],
      "parameters": {
        "text": "=\ud83d\udd34 *Workflow Error \u2014 Lead Score Drop Alert*\n\n*Error:* {{ $json.message || 'Unknown error' }}\n*Node:* {{ $runIndex }}\n*Time:* {{ $now.toISOString() }}\n\nPlease check the n8n execution log immediately.",
        "otherOptions": {
          "mrkdwn": true
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 2.2
    },
    {
      "id": "0da48f18-5c44-467c-9de7-2d583105f94a",
      "name": "Code \u2014 No New Contacts (Exit)",
      "type": "n8n-nodes-base.code",
      "position": [
        2784,
        1888
      ],
      "parameters": {
        "jsCode": "// No new contacts to process \u2014 exit cleanly\nreturn [{ json: { status: 'skipped', reason: 'All contacts already alerted within 24 hours or no low-score contacts found.', timestamp: new Date().toISOString() } }];"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "445c6309-1b7c-460f-b994-f0f32fa8a8fe",
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "HubSpot \u2014 Get Low Score Contacts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF \u2014 Any Contacts Left?": {
      "main": [
        [
          {
            "node": "Code \u2014 No New Contacts (Exit)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "HubSpot \u2014 Get Contact Owner",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2014 Log Alert": {
      "main": [
        [
          {
            "node": "Google Sheets \u2014 Update Dedup Log",
            "type": "main",
            "index": 0
          },
          {
            "node": "Slack \u2014 Error Alert to Admin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF \u2014 Critical or Warning?": {
      "main": [
        [
          {
            "node": "Slack \u2014 Critical Alert to Channel",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Slack \u2014 Warning Alert to Channel",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code \u2014 Deduplicate & Enrich": {
      "main": [
        [
          {
            "node": "IF \u2014 Any Contacts Left?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HubSpot \u2014 Get Contact Owner": {
      "main": [
        [
          {
            "node": "Code \u2014 Merge Owner & Build Alert",
            "type": "main",
            "index": 0
          },
          {
            "node": "Slack \u2014 Error Alert to Admin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack \u2014 DM to Contact Owner": {
      "main": [
        [
          {
            "node": "HubSpot \u2014 Create Follow-Up Task",
            "type": "main",
            "index": 0
          },
          {
            "node": "Slack \u2014 Error Alert to Admin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets \u2014 Read Dedup Log": {
      "main": [
        [
          {
            "node": "Code \u2014 Deduplicate & Enrich",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HubSpot \u2014 Create Follow-Up Task": {
      "main": [
        [
          {
            "node": "Gmail \u2014 Re-Engagement Email to Contact",
            "type": "main",
            "index": 0
          },
          {
            "node": "Slack \u2014 Error Alert to Admin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code \u2014 Merge Owner & Build Alert": {
      "main": [
        [
          {
            "node": "IF \u2014 Critical or Warning?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HubSpot \u2014 Get Low Score Contacts": {
      "main": [
        [
          {
            "node": "Google Sheets \u2014 Read Dedup Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack \u2014 Warning Alert to Channel": {
      "main": [
        [
          {
            "node": "Slack \u2014 DM to Contact Owner",
            "type": "main",
            "index": 0
          },
          {
            "node": "Slack \u2014 Error Alert to Admin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack \u2014 Critical Alert to Channel": {
      "main": [
        [
          {
            "node": "Slack \u2014 DM to Contact Owner",
            "type": "main",
            "index": 0
          },
          {
            "node": "Slack \u2014 Error Alert to Admin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail \u2014 Re-Engagement Email to Contact": {
      "main": [
        [
          {
            "node": "Google Sheets \u2014 Log Alert",
            "type": "main",
            "index": 0
          },
          {
            "node": "Slack \u2014 Error Alert to Admin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}