AutomationFlowsData & Sheets › Predict Customer Churn Daily Using Ml or LLM Models and Notify via Slack/email

Predict Customer Churn Daily Using Ml or LLM Models and Notify via Slack/email

ByOneclick AI Squad @oneclick-ai on n8n.io

This n8n workflow runs daily to analyze active customer behavior, engineers relevant features from usage and transaction data, applies a machine learning or AI-based model to predict churn probability, classifies risk levels, triggers retention actions for at-risk customers,…

Cron / scheduled trigger★★★★☆ complexity22 nodesHTTP RequestPostgresEmail Send
Data & Sheets Trigger: Cron / scheduled Nodes: 22 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #13726 — we link there as the canonical source.

This workflow follows the Emailsend → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "9pmjBc7dqrEagOoX",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "AI Customer Churn Predictor",
  "tags": [],
  "nodes": [
    {
      "id": "1f854286-b67a-42f9-9711-0056c93f9a0d",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -32,
        -384
      ],
      "parameters": {
        "width": 900,
        "height": 1504,
        "content": "## AI Customer Churn Predictor\n\nAnalyzes user behavior data and predicts churn probability using machine learning algorithms.\n\n## How it works\n\n1. **Trigger** \u2014 Runs daily at 2 AM to analyze active customers\n2. **Collect** \u2014 Fetches customer profiles, activity logs, and transaction history from database\n3. **Engineer** \u2014 Extracts features: login frequency, spend patterns, support tickets, engagement metrics\n4. **Predict** \u2014 Uses ML model to calculate churn probability (0-100%)\n5. **Score** \u2014 Classifies as HIGH RISK / MEDIUM RISK / LOW RISK\n6. **Remediate** \u2014 Creates retention campaigns for at-risk customers\n7. **Store** \u2014 Saves predictions to analytics database\n8. **Notify** \u2014 Sends alerts and dashboards via Email & Slack\n\n## Setup steps\n\n1. **Database** \u2014 Connect your customer database (PostgreSQL/MySQL)\n2. **ML Model** \u2014 Configure ML API endpoint or use Python ML node\n3. **Analytics DB** \u2014 Set up table for churn predictions\n4. **Slack/Email** \u2014 Add webhook URLs and SMTP credentials\n5. **Retention API** \u2014 Configure CRM/marketing platform for campaigns\n6. **Test** \u2014 Run manually first, then schedule daily execution\n\n**AI Customer Churn Predictor**\n\nThis n8n workflow runs daily to analyze active customer behavior, engineers relevant features from usage and transaction data, applies a machine learning or AI-based model to predict churn probability, classifies risk levels, triggers retention actions for at-risk customers, stores predictions for tracking, and notifies relevant teams.\n\n### Key Insights\n- Prediction accuracy heavily depends on feature quality \u2014 ensure login frequency, spend trends, support interactions, and engagement metrics are consistently captured and up-to-date.\n- Start with simple rule-based scoring or AI prompting (e.g., OpenAI/Claude) before integrating full ML models for easier testing and faster value.\n- High-risk thresholds (e.g., >70%) should be tuned based on your actual churn data to avoid alert fatigue or missed opportunities.\n\n### Usage Guide\n- Import the workflow into n8n and configure credentials for your customer database (PostgreSQL/MySQL), ML API (if external), analytics DB, Slack webhook, SMTP/email, and CRM/retention platform.\n- Define feature extraction queries and thresholds carefully in the relevant nodes \u2014 test with a small customer subset first.\n- If using AI/LLM for prediction, refine the prompt to include clear examples of churn signals.\n- Run manually via the **Execute workflow** button with sample data to validate data flow, scoring logic, and notifications.\n- Once confident, activate the daily schedule.\n\n### Prerequisites\n- Customer database with readable tables for users, activity logs, transactions, and support interactions\n- ML integration option: either an external ML API endpoint, Python code node with scikit-learn/simple model, or LLM node (OpenAI, Claude, etc.) for probabilistic scoring\n- Separate analytics database (or same DB) with a table ready for churn predictions (customer_id, date, churn_prob, risk_level, etc.)\n- SMTP credentials or email service for alerts\n- Slack webhook URL (optional but recommended for team notifications)\n- CRM or marketing automation API access (e.g., HubSpot, ActiveCampaign, Klaviyo) for creating retention campaigns/tasks\n\n### Customization Options\n- Adjust the daily trigger time or make it hourly for near real-time monitoring of high-value accounts.\n- Change risk classification thresholds or add more tiers in the scoring logic node.\n- Enhance the prediction step: switch from LLM-based to a trained ML model (via Hugging Face, custom endpoint, or Code node).\n- Personalize retention actions: use AI to generate custom email content/offers based on the customer's behavior profile.\n- Add filtering (e.g., only high-value customers > certain MRR) to focus retention efforts.\n- Extend notifications: integrate with Microsoft Teams, Discord, or create tickets in Zendesk/Jira for follow-up.\n- Build feedback loop: after actual churn occurs, update a training dataset or adjust weights/rules in future runs.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "2ae5a72b-8d07-4274-8d1d-233863fb9a08",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        112
      ],
      "parameters": {
        "color": 3,
        "width": 500,
        "height": 768,
        "content": "## 1. Trigger & Collect Data\n\nDaily schedule to fetch customer profiles and behavioral data"
      },
      "typeVersion": 1
    },
    {
      "id": "43bb8c82-df36-49f3-89fe-70d908cd5e4a",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1472,
        256
      ],
      "parameters": {
        "color": 5,
        "width": 388,
        "height": 448,
        "content": "## 2. Feature Engineering\n\nExtract and calculate behavioral features for ML model"
      },
      "typeVersion": 1
    },
    {
      "id": "45eec6c4-bb3c-40ae-91fd-f3523ced9e7b",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1920,
        320
      ],
      "parameters": {
        "color": 4,
        "width": 596,
        "height": 408,
        "content": "## 3. ML Prediction\n\nRun churn probability predictions and score customers"
      },
      "typeVersion": 1
    },
    {
      "id": "a0bd3b99-1e56-4d62-9abb-b60829950996",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2592,
        192
      ],
      "parameters": {
        "color": 5,
        "width": 550,
        "height": 612,
        "content": "## 4. Classify & Remediate\n\nRoute customers by risk level and create retention campaigns"
      },
      "typeVersion": 1
    },
    {
      "id": "197eba11-4fc5-477a-9ec7-73b512f5351c",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3232,
        208
      ],
      "parameters": {
        "color": 3,
        "width": 550,
        "height": 580,
        "content": "## 5. Report & Notify\n\nStore results and deliver churn analytics to stakeholders"
      },
      "typeVersion": 1
    },
    {
      "id": "e6ec0958-1d51-45be-a2d3-e9e2edf6b9da",
      "name": "Daily churn analysis at 2 AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        1056,
        496
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 2 * * *"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "4c3ff3c6-e6a4-4a16-8a9d-ce732dbccdc3",
      "name": "Fetch active customer profiles",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1280,
        304
      ],
      "parameters": {
        "url": "https://api.example.com/customers/active",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "ca121dcf-1812-463d-8388-10266013e886",
      "name": "Fetch customer activity logs (30 days)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1280,
        496
      ],
      "parameters": {
        "url": "https://api.example.com/logs/activity?days=30",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "ed96d0b9-b6e3-408d-b955-2c3cf2080712",
      "name": "Fetch transaction history (90 days)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1280,
        688
      ],
      "parameters": {
        "url": "https://api.example.com/transactions?days=90",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "5ac08f4f-5321-40ad-81a1-f027fd635970",
      "name": "Merge customer and activity data",
      "type": "n8n-nodes-base.merge",
      "position": [
        1504,
        496
      ],
      "parameters": {
        "mode": "combine",
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "39030266-1388-4a8f-8b10-4bb70898b93e",
      "name": "Engineer behavioral features",
      "type": "n8n-nodes-base.code",
      "position": [
        1728,
        496
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Feature engineering for churn prediction\nconst customer = $input.item.json;\n\n// --- Login Frequency ---\nconst loginDays = customer.activity_logs?.filter(log => log.type === 'login').length || 0;\nconst daysActive = customer.days_since_signup || 1;\nconst loginFrequency = Math.round((loginDays / 30) * 100) / 100; // logins per month\nconst loginTrend = (customer.login_last_7_days || 0) - (customer.login_previous_7_days || 0);\n\n// --- Spend Patterns ---\nconst totalSpend = customer.transactions?.reduce((sum, t) => sum + (t.amount || 0), 0) || 0;\nconst avgTransactionValue = customer.transactions?.length > 0 ? totalSpend / customer.transactions.length : 0;\nconst spendTrend = ((customer.spend_last_30 || 0) - (customer.spend_previous_30 || 0)) / (customer.spend_previous_30 || 1);\nconst daysLastPurchase = customer.days_since_last_purchase || 999;\n\n// --- Engagement Metrics ---\nconst supportTickets = customer.support_tickets || 0;\nconst featureUsage = customer.features_used || 0;\nconst emailEngagement = customer.email_open_rate || 0; // percentage\nconst accountAge = customer.days_since_signup || 1;\n\n// --- Subscription Details ---\nconst planValue = customer.plan_value || 0;\nconst isFreeTier = customer.plan_type === 'free';\nconst daysUntilRenewal = customer.days_until_renewal || 365;\nconst hasCardOnFile = customer.has_payment_method || false;\n\n// --- Feature Adoption ---\nconst adoptionScore = (featureUsage / (customer.available_features || 1)) * 100;\nconst apiCalls = customer.api_usage || 0;\nconst storageUsage = customer.storage_used_percent || 0;\n\n// --- Anomaly Flags ---\nconst suspiciousLogin = loginTrend < -5; // drop in logins\nconst noPurchaseInDays = daysLastPurchase > 60;\nconst lowEngagement = loginFrequency < 2; // less than 2 logins/month\nconst highSupportVolume = supportTickets > 5;\nconst negativeSpendTrend = spendTrend < -0.3; // 30% drop in spend\n\n// --- Compile feature vector ---\nconst features = {\n  customer_id: customer.id,\n  email: customer.email,\n  signup_date: customer.signup_date,\n  plan_type: customer.plan_type,\n  \n  // Core features\n  login_frequency: loginFrequency,\n  login_trend: loginTrend,\n  days_last_purchase: daysLastPurchase,\n  total_spend: totalSpend,\n  avg_transaction_value: avgTransactionValue,\n  spend_trend: spendTrend,\n  account_age_days: accountAge,\n  \n  // Engagement\n  support_tickets: supportTickets,\n  feature_usage_count: featureUsage,\n  adoption_score: adoptionScore,\n  email_engagement: emailEngagement,\n  api_calls: apiCalls,\n  storage_usage_percent: storageUsage,\n  \n  // Subscription\n  plan_value: planValue,\n  is_free_tier: isFreeTier,\n  days_until_renewal: daysUntilRenewal,\n  has_card_on_file: hasCardOnFile,\n  \n  // Anomalies\n  flag_suspicious_login: suspiciousLogin,\n  flag_no_purchase_60days: noPurchaseInDays,\n  flag_low_engagement: lowEngagement,\n  flag_high_support_volume: highSupportVolume,\n  flag_negative_spend_trend: negativeSpendTrend,\n  \n  // Calculated risk indicators\n  anomaly_count: [suspiciousLogin, noPurchaseInDays, lowEngagement, highSupportVolume, negativeSpendTrend].filter(Boolean).length\n};\n\nreturn {\n  json: features\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "a6e2a4e3-05e5-426f-b6e6-8502ea446f3d",
      "name": "Call ML churn prediction model",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1952,
        496
      ],
      "parameters": {
        "url": "https://ml-api.example.com/predict/churn",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "features",
              "value": "={{ {login_frequency: $json.login_frequency, login_trend: $json.login_trend, days_last_purchase: $json.days_last_purchase, total_spend: $json.total_spend, spend_trend: $json.spend_trend, support_tickets: $json.support_tickets, adoption_score: $json.adoption_score, anomaly_count: $json.anomaly_count} }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "241db3b1-befb-4b8e-9758-f84ae5d600c8",
      "name": "Score and classify churn risk",
      "type": "n8n-nodes-base.code",
      "position": [
        2176,
        496
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Score churn risk and classify into risk tiers\nconst data = $input.item.json;\nconst mlPrediction = data.churn_probability || 0; // 0-1 scale\n\n// Convert to 0-100 scale\nconst churnScore = Math.round(mlPrediction * 100);\n\n// Classification logic\nlet riskLevel = 'LOW_RISK';\nlet actionRequired = false;\nlet campaignType = 'none';\nlet priority = 'low';\n\nif (churnScore >= 70) {\n  riskLevel = 'HIGH_RISK';\n  actionRequired = true;\n  campaignType = 'aggressive_retention';\n  priority = 'critical';\n} else if (churnScore >= 50) {\n  riskLevel = 'MEDIUM_RISK';\n  actionRequired = true;\n  campaignType = 'engagement_boost';\n  priority = 'high';\n} else if (churnScore >= 30) {\n  riskLevel = 'EARLY_RISK';\n  actionRequired = false;\n  campaignType = 'preventive';\n  priority = 'medium';\n}\n\n// Risk factors summary\nconst riskFactors = [];\nif (data.flag_no_purchase_60days) riskFactors.push('No purchase in 60+ days');\nif (data.flag_low_engagement) riskFactors.push('Low login frequency');\nif (data.flag_negative_spend_trend) riskFactors.push('Declining spend');\nif (data.flag_high_support_volume) riskFactors.push('High support tickets');\nif (data.flag_suspicious_login) riskFactors.push('Unusual login activity');\n\n// Retention strategy\nlet recommendedAction = '';\nif (churnScore >= 70) {\n  recommendedAction = 'Immediate outreach: Offer discount, upgrade incentive, or VIP support';\n} else if (churnScore >= 50) {\n  recommendedAction = 'Engagement campaign: Personalized tutorials, feature highlights';\n} else if (churnScore >= 30) {\n  recommendedAction = 'Monitor closely: Nurture with educational content and updates';\n}\n\nconst timestamp = new Date().toISOString();\nconst predictionDate = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\n\nreturn {\n  json: {\n    // Customer & Prediction Identity\n    customer_id: data.customer_id,\n    email: data.email,\n    plan_type: data.plan_type,\n    \n    // Churn Score & Classification\n    churn_probability_score: churnScore,\n    churn_probability_percentage: churnScore + '%',\n    risk_level: riskLevel,\n    risk_level_numeric: riskLevel === 'HIGH_RISK' ? 3 : riskLevel === 'MEDIUM_RISK' ? 2 : riskLevel === 'EARLY_RISK' ? 1 : 0,\n    \n    // Key Metrics\n    login_frequency: data.login_frequency,\n    days_since_last_purchase: data.days_last_purchase,\n    total_lifetime_value: data.total_spend,\n    spend_trend_percent: Math.round(data.spend_trend * 100),\n    support_tickets_90days: data.support_tickets,\n    feature_adoption_score: Math.round(data.adoption_score),\n    account_age_days: data.account_age_days,\n    \n    // Risk Indicators\n    risk_factors: riskFactors,\n    risk_factor_count: riskFactors.length,\n    anomaly_flags_count: data.anomaly_count,\n    \n    // Action & Campaign\n    action_required: actionRequired,\n    campaign_type: campaignType,\n    priority: priority,\n    recommended_action: recommendedAction,\n    \n    // Timestamp\n    prediction_date: predictionDate,\n    prediction_timestamp: timestamp,\n    \n    // Original features for reference\n    features: data\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "e37bc7ba-bd03-41d3-9be4-0744bbb5b2d7",
      "name": "Route by risk level",
      "type": "n8n-nodes-base.switch",
      "position": [
        2400,
        480
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "High Risk",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.risk_level }}",
                    "rightValue": "HIGH_RISK"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Medium Risk",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.risk_level }}",
                    "rightValue": "MEDIUM_RISK"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Low Risk",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.risk_level }}",
                    "rightValue": "EARLY_RISK"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "c276d68c-d114-4894-a2c1-7b7a2f620762",
      "name": "Create retention campaign task",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2624,
        400
      ],
      "parameters": {
        "url": "https://api.example.com/campaigns/create",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "customer_id",
              "value": "={{ $json.customer_id }}"
            },
            {
              "name": "campaign_type",
              "value": "={{ $json.campaign_type }}"
            },
            {
              "name": "churn_score",
              "value": "={{ $json.churn_probability_score }}"
            },
            {
              "name": "risk_level",
              "value": "={{ $json.risk_level }}"
            },
            {
              "name": "recommended_action",
              "value": "={{ $json.recommended_action }}"
            },
            {
              "name": "priority",
              "value": "={{ $json.priority }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ca4e1fe7-be3f-4551-88f2-321fee4b8318",
      "name": "Store churn predictions in database",
      "type": "n8n-nodes-base.postgres",
      "position": [
        2624,
        592
      ],
      "parameters": {
        "table": "churn_predictions",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "77b5a3e0-50ac-4a7a-90fd-5df6a4245a73",
      "name": "Generate churn analytics report",
      "type": "n8n-nodes-base.code",
      "position": [
        2848,
        496
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Generate HTML report for churn predictions\nconst data = $input.item.json;\n\nconst statusColor = data.risk_level === 'HIGH_RISK' ? '#ef4444' \n  : data.risk_level === 'MEDIUM_RISK' ? '#f59e0b' \n  : '#22c55e';\n\nconst statusIcon = data.risk_level === 'HIGH_RISK' ? '\ud83d\udea8' \n  : data.risk_level === 'MEDIUM_RISK' ? '\u26a0\ufe0f' \n  : '\u2705';\n\nconst reportHtml = `\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Churn Prediction Report - ${data.customer_id}</title>\n  <style>\n    body { font-family: Arial, sans-serif; color: #1e293b; margin: 0; padding: 24px; background: #f8fafc; }\n    .header { background: #0f172a; color: white; padding: 24px; border-radius: 8px; margin-bottom: 24px; }\n    .header h1 { margin: 0 0 8px 0; font-size: 22px; }\n    .header p { margin: 0; opacity: 0.7; font-size: 13px; }\n    .status-badge { display: inline-block; padding: 8px 16px; border-radius: 20px; font-weight: bold; font-size: 14px; background: ${statusColor}; color: white; margin-top: 12px; }\n    .cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 24px; }\n    .card { background: white; border-radius: 8px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n    .card .value { font-size: 28px; font-weight: bold; color: ${statusColor}; }\n    .card .label { font-size: 12px; color: #64748b; margin-top: 4px; }\n    .section { background: white; border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n    .section h2 { margin: 0 0 16px 0; font-size: 16px; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px; }\n    table { width: 100%; border-collapse: collapse; font-size: 13px; }\n    th { background: #f1f5f9; text-align: left; padding: 8px 12px; }\n    td { padding: 8px 12px; border-bottom: 1px solid #e2e8f0; }\n    .action-box { background: ${statusColor}15; border-left: 4px solid ${statusColor}; padding: 12px; margin-top: 12px; border-radius: 4px; }\n    .footer { text-align: center; font-size: 11px; color: #94a3b8; margin-top: 24px; }\n  </style>\n</head>\n<body>\n  <div class=\"header\">\n    <h1>${statusIcon} Customer Churn Risk Assessment</h1>\n    <p>Customer: ${data.email} | Plan: ${data.plan_type} | Generated: ${data.prediction_date}</p>\n    <div class=\"status-badge\">${data.risk_level.replace(/_/g, ' ')}</div>\n  </div>\n\n  <div class=\"cards\">\n    <div class=\"card\"><div class=\"value\">${data.churn_probability_score}%</div><div class=\"label\">Churn Risk Score</div></div>\n    <div class=\"card\"><div class=\"value\">\\$${Math.round(data.total_lifetime_value)}</div><div class=\"label\">Lifetime Value</div></div>\n    <div class=\"card\"><div class=\"value\">${data.login_frequency.toFixed(1)}</div><div class=\"label\">Logins/Month</div></div>\n    <div class=\"card\"><div class=\"value\">${data.adoption_score}%</div><div class=\"label\">Feature Adoption</div></div>\n  </div>\n\n  <div class=\"section\">\n    <h2>\ud83d\udcca Key Metrics</h2>\n    <table><tbody>\n      <tr><td><strong>Days Since Last Purchase</strong></td><td>${data.days_since_last_purchase}</td></tr>\n      <tr><td><strong>Spend Trend (90 days)</strong></td><td>${data.spend_trend_percent > 0 ? '+' : ''}${data.spend_trend_percent}%</td></tr>\n      <tr><td><strong>Support Tickets (90 days)</strong></td><td>${data.support_tickets_90days}</td></tr>\n      <tr><td><strong>Account Age</strong></td><td>${data.account_age_days} days</td></tr>\n    </tbody></table>\n  </div>\n\n  <div class=\"section\">\n    <h2>\u26a0\ufe0f Risk Factors (${data.risk_factor_count})</h2>\n    <ul>${data.risk_factors.map(f => '<li>' + f + '</li>').join('')}</ul>\n  </div>\n\n  <div class=\"section\">\n    <h2>\ud83c\udfaf Recommended Action</h2>\n    <div class=\"action-box\">\n      <strong>${data.recommended_action}</strong>\n      <br><br>\n      <em>Campaign Type: ${data.campaign_type.replace(/_/g, ' ').toUpperCase()}</em>\n    </div>\n  </div>\n\n  <div class=\"footer\">AI Customer Churn Predictor | ${data.prediction_timestamp}</div>\n</body>\n</html>`;\n\nconst notificationMessage = `${statusIcon} *CHURN RISK ALERT \u2014 ${data.email}*\\n\\n` +\n  `*Risk Level:* ${data.risk_level.replace(/_/g, ' ')}\\n` +\n  `*Churn Score:* ${data.churn_probability_score}%\\n` +\n  `*Lifetime Value:* \\$${Math.round(data.total_lifetime_value)}\\n\\n` +\n  `*Key Metrics:*\\n` +\n  `\u2022 Logins/Month: ${data.login_frequency.toFixed(1)}\\n` +\n  `\u2022 Days Since Purchase: ${data.days_since_last_purchase}\\n` +\n  `\u2022 Spend Trend: ${data.spend_trend_percent > 0 ? '+' : ''}${data.spend_trend_percent}%\\n` +\n  `\u2022 Feature Adoption: ${data.adoption_score}%\\n\\n` +\n  `*Risk Factors:* ${data.risk_factors.join(', ')}\\n` +\n  `*Action:* ${data.recommended_action}`;\n\nreturn {\n  json: {\n    ...data,\n    reportHtml,\n    notificationMessage,\n    notificationTitle: `${statusIcon} [${data.customer_id}] ${data.risk_level.replace(/_/g, ' ')} - Churn Score: ${data.churn_probability_score}%`,\n    shouldNotify: data.action_required,\n    shouldNotifyAll: true\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "749cee1c-71ed-4c46-acf5-2bffb16fd094",
      "name": "Filter at-risk customers",
      "type": "n8n-nodes-base.filter",
      "position": [
        3072,
        496
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "notify-condition",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.action_required }}"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "859e2c70-dded-45ee-a8a0-118a16762657",
      "name": "Post churn alert to Slack",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3296,
        400
      ],
      "parameters": {
        "url": "YOUR_SLACK_WEBHOOK_URL",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"text\": \"{{ $json.notificationTitle }}\",\n  \"blocks\": [\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"{{ $json.notificationMessage }}\"\n      }\n    }\n  ]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "c871536b-fb9f-4b73-ba8e-9666959da6ab",
      "name": "Email report to customer success team",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        3296,
        592
      ],
      "parameters": {
        "html": "={{ $json.reportHtml }}",
        "options": {},
        "subject": "={{ $json.notificationTitle }}",
        "toEmail": "user@example.com",
        "fromEmail": "noreply@example.com"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "f6b94a2d-c388-4596-9438-f8b593307b22",
      "name": "Log analysis completion",
      "type": "n8n-nodes-base.code",
      "position": [
        3520,
        496
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Log churn analysis completion\nconst timestamp = new Date().toISOString();\nconst data = $input.item.json;\n\nconsole.log(`\u2705 CHURN ANALYSIS: Customer ${data.customer_id} | Risk: ${data.risk_level} | Score: ${data.churn_probability_score}% | Action: ${data.campaign_type} | Time: ${timestamp}`);\n\n// Aggregate statistics\nconst stats = $getWorkflowStaticData('global').stats || {\n  totalAnalyzed: 0,\n  highRiskCount: 0,\n  mediumRiskCount: 0,\n  lowRiskCount: 0,\n  avgChurnScore: 0,\n  lastUpdated: null\n};\n\nif (data.risk_level === 'HIGH_RISK') stats.highRiskCount++;\nelse if (data.risk_level === 'MEDIUM_RISK') stats.mediumRiskCount++;\nelse stats.lowRiskCount++;\n\nstats.totalAnalyzed++;\nstats.lastUpdated = timestamp;\n\n$getWorkflowStaticData('global').stats = stats;\n\nreturn {\n  json: {\n    success: true,\n    customer_id: data.customer_id,\n    risk_level: data.risk_level,\n    churn_score: data.churn_probability_score,\n    timestamp,\n    cumulativeStats: stats\n  }\n};"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "d4a74901-f1bc-46d0-ae0a-88864d51c3df",
  "connections": {
    "Route by risk level": {
      "main": [
        [
          {
            "node": "Create retention campaign task",
            "type": "main",
            "index": 0
          },
          {
            "node": "Store churn predictions in database",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create retention campaign task",
            "type": "main",
            "index": 0
          },
          {
            "node": "Store churn predictions in database",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Store churn predictions in database",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter at-risk customers": {
      "main": [
        [
          {
            "node": "Post churn alert to Slack",
            "type": "main",
            "index": 0
          },
          {
            "node": "Email report to customer success team",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post churn alert to Slack": {
      "main": [
        [
          {
            "node": "Log analysis completion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily churn analysis at 2 AM": {
      "main": [
        [
          {
            "node": "Fetch active customer profiles",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch customer activity logs (30 days)",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch transaction history (90 days)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Engineer behavioral features": {
      "main": [
        [
          {
            "node": "Call ML churn prediction model",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Score and classify churn risk": {
      "main": [
        [
          {
            "node": "Route by risk level",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call ML churn prediction model": {
      "main": [
        [
          {
            "node": "Score and classify churn risk",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create retention campaign task": {
      "main": [
        [
          {
            "node": "Generate churn analytics report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch active customer profiles": {
      "main": [
        [
          {
            "node": "Merge customer and activity data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate churn analytics report": {
      "main": [
        [
          {
            "node": "Filter at-risk customers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge customer and activity data": {
      "main": [
        [
          {
            "node": "Engineer behavioral features",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch transaction history (90 days)": {
      "main": [
        [
          {
            "node": "Merge customer and activity data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Store churn predictions in database": {
      "main": [
        [
          {
            "node": "Generate churn analytics report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email report to customer success team": {
      "main": [
        [
          {
            "node": "Log analysis completion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch customer activity logs (30 days)": {
      "main": [
        [
          {
            "node": "Merge customer and activity data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This n8n workflow runs daily to analyze active customer behavior, engineers relevant features from usage and transaction data, applies a machine learning or AI-based model to predict churn probability, classifies risk levels, triggers retention actions for at-risk customers,…

Source: https://n8n.io/workflows/13726/ — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

Disparador 1.8. Uses itemLists, postgres, emailSend, httpRequest. Scheduled trigger; 85 nodes.

Item Lists, Postgres, Email Send +1
Data & Sheets

This n8n workflow automates continuous compliance monitoring across IT, OT, and cloud environments by aggregating security controls, validating policies (ISO 27001, NIST, GDPR, SOC2), detecting anomal

HTTP Request, Postgres, Email Send
Data & Sheets

Automates real-time market monitoring, technical analysis, AI-powered signal generation for cryptocurrencies (and stocks), filters high-confidence trades, and delivers actionable alerts via multiple c

HTTP Request, Postgres, Email Send
Data & Sheets

Scheduled processes retrieve customer feedback from multiple channels. The system performs sentiment analysis to classify tone, then uses OpenAI models to extract themes, topics, and urgency indicator

HTTP Request, Lm Chat Azure Open Ai, Sentiment Analysis +5
Data & Sheets

Recordatorio de Citas - 24 horas antes. Uses postgres, emailSend, httpRequest. Scheduled trigger; 5 nodes.

Postgres, Email Send, HTTP Request