# Customer Success Automation

**Meta-Description:** Customer Success automatisieren. Health Scores, Lifecycle Emails, Churn Prediction und Proactive Outreach für SaaS.

**Keywords:** Customer Success, Health Score, Churn Prediction, Lifecycle Marketing, Customer Retention, Automation, NPS

---

## Einführung

**Customer Success** ist der Schlüssel zu Retention und Expansion. Mit **Automation** können Health Scores berechnet, Risiko-Kunden identifiziert und proaktive Maßnahmen ergriffen werden – skalierbar für tausende Kunden.

---

## Customer Success Overview

```
┌─────────────────────────────────────────────────────────────┐
│              CUSTOMER SUCCESS AUTOMATION                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Customer Health Score:                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Score Components (0-100):                          │   │
│  │  ├── Product Usage (40%)                            │   │
│  │  │   ├── Login frequency                           │   │
│  │  │   ├── Feature adoption                          │   │
│  │  │   └── Active users/seats                        │   │
│  │  ├── Engagement (30%)                               │   │
│  │  │   ├── Support tickets                           │   │
│  │  │   ├── NPS score                                 │   │
│  │  │   └── Training completion                       │   │
│  │  └── Business Value (30%)                           │   │
│  │      ├── ROI achieved                              │   │
│  │      ├── Expansion potential                       │   │
│  │      └── Contract value                            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Lifecycle Stages:                                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Onboarding → Adoption → Growth → Renewal          │   │
│  │      │          │          │         │              │   │
│  │      ↓          ↓          ↓         ↓              │   │
│  │   Welcome    Training   Upsell   Review            │   │
│  │   Emails     Content    Offers   Campaign          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Risk Triggers:                                             │
│  ├── Login decrease > 50%                                  │
│  ├── Support tickets spike                                 │
│  ├── Key user departure                                    │
│  ├── Contract renewal in 60 days                          │
│  └── Low NPS score (< 7)                                   │
│                                                             │
│  Automated Actions:                                         │
│  ├── Email sequences                                       │
│  ├── In-app messages                                       │
│  ├── CSM alerts                                            │
│  ├── Scheduled calls                                       │
│  └── Personalized offers                                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

---

## Health Score Calculation

```typescript
// lib/customer-success/health-score.ts
import { db } from '@/lib/db';
import { subDays, differenceInDays } from 'date-fns';

interface HealthScoreWeights {
  usage: number;
  engagement: number;
  business: number;
}

interface HealthScoreComponents {
  usage: {
    loginScore: number;
    featureAdoptionScore: number;
    activeUsersScore: number;
  };
  engagement: {
    supportScore: number;
    npsScore: number;
    trainingScore: number;
  };
  business: {
    contractValueScore: number;
    expansionScore: number;
    tenureScore: number;
  };
}

interface HealthScore {
  score: number;
  trend: 'up' | 'down' | 'stable';
  riskLevel: 'healthy' | 'attention' | 'at-risk' | 'critical';
  components: HealthScoreComponents;
  lastUpdated: Date;
}

const DEFAULT_WEIGHTS: HealthScoreWeights = {
  usage: 0.4,
  engagement: 0.3,
  business: 0.3
};

export async function calculateHealthScore(
  customerId: string,
  weights: HealthScoreWeights = DEFAULT_WEIGHTS
): Promise<HealthScore> {
  const now = new Date();
  const thirtyDaysAgo = subDays(now, 30);

  // Get customer data
  const customer = await db.customer.findUnique({
    where: { id: customerId },
    include: {
      subscription: true,
      users: true,
      supportTickets: {
        where: { createdAt: { gte: thirtyDaysAgo } }
      },
      npsResponses: {
        orderBy: { createdAt: 'desc' },
        take: 1
      }
    }
  });

  if (!customer) {
    throw new Error('Customer not found');
  }

  // Calculate usage scores
  const loginScore = await calculateLoginScore(customerId, thirtyDaysAgo);
  const featureAdoptionScore = await calculateFeatureAdoptionScore(customerId);
  const activeUsersScore = calculateActiveUsersScore(customer);

  const usageScore = (loginScore + featureAdoptionScore + activeUsersScore) / 3;

  // Calculate engagement scores
  const supportScore = calculateSupportScore(customer.supportTickets);
  const npsScore = calculateNPSHealthScore(customer.npsResponses[0]?.score);
  const trainingScore = await calculateTrainingScore(customerId);

  const engagementScore = (supportScore + npsScore + trainingScore) / 3;

  // Calculate business scores
  const contractValueScore = calculateContractValueScore(customer.subscription);
  const expansionScore = await calculateExpansionScore(customerId);
  const tenureScore = calculateTenureScore(customer.createdAt);

  const businessScore = (contractValueScore + expansionScore + tenureScore) / 3;

  // Weighted total
  const totalScore = Math.round(
    usageScore * weights.usage +
    engagementScore * weights.engagement +
    businessScore * weights.business
  );

  // Calculate trend
  const previousScore = await getPreviousHealthScore(customerId);
  const trend = getTrend(totalScore, previousScore);

  // Determine risk level
  const riskLevel = getRiskLevel(totalScore);

  const healthScore: HealthScore = {
    score: totalScore,
    trend,
    riskLevel,
    components: {
      usage: { loginScore, featureAdoptionScore, activeUsersScore },
      engagement: { supportScore, npsScore, trainingScore },
      business: { contractValueScore, expansionScore, tenureScore }
    },
    lastUpdated: now
  };

  // Store for history
  await db.healthScoreHistory.create({
    data: {
      customerId,
      score: totalScore,
      components: healthScore.components,
      calculatedAt: now
    }
  });

  return healthScore;
}

async function calculateLoginScore(
  customerId: string,
  since: Date
): Promise<number> {
  const logins = await db.userActivity.count({
    where: {
      user: { customerId },
      activityType: 'login',
      createdAt: { gte: since }
    }
  });

  // Expected: at least 20 logins per month for healthy usage
  return Math.min(100, (logins / 20) * 100);
}

async function calculateFeatureAdoptionScore(
  customerId: string
): Promise<number> {
  const totalFeatures = await db.feature.count({
    where: { isCore: true }
  });

  const usedFeatures = await db.featureUsage.groupBy({
    by: ['featureId'],
    where: {
      user: { customerId }
    }
  });

  return Math.round((usedFeatures.length / totalFeatures) * 100);
}

function calculateActiveUsersScore(customer: any): number {
  const totalSeats = customer.subscription?.seats || 1;
  const activeUsers = customer.users.filter((u: any) =>
    u.lastActiveAt && differenceInDays(new Date(), u.lastActiveAt) < 7
  ).length;

  return Math.round((activeUsers / totalSeats) * 100);
}

function calculateSupportScore(tickets: any[]): number {
  if (tickets.length === 0) return 100;

  // Fewer tickets = higher score, but some engagement is good
  const ticketCount = tickets.length;
  if (ticketCount <= 2) return 100;
  if (ticketCount <= 5) return 80;
  if (ticketCount <= 10) return 60;
  return 40;
}

function calculateNPSHealthScore(npsScore?: number): number {
  if (npsScore === undefined) return 50; // Neutral if no data
  if (npsScore >= 9) return 100;
  if (npsScore >= 7) return 75;
  if (npsScore >= 5) return 50;
  return 25;
}

function getRiskLevel(score: number): HealthScore['riskLevel'] {
  if (score >= 80) return 'healthy';
  if (score >= 60) return 'attention';
  if (score >= 40) return 'at-risk';
  return 'critical';
}

function getTrend(current: number, previous?: number): HealthScore['trend'] {
  if (!previous) return 'stable';
  const diff = current - previous;
  if (diff > 5) return 'up';
  if (diff < -5) return 'down';
  return 'stable';
}
```

---

## Lifecycle Email Automation

```typescript
// lib/customer-success/lifecycle.ts
import { db } from '@/lib/db';
import { addDays, differenceInDays } from 'date-fns';

interface LifecycleStage {
  id: string;
  name: string;
  triggers: TriggerCondition[];
  actions: Action[];
}

interface TriggerCondition {
  type: 'days_since_signup' | 'event' | 'health_score' | 'subscription';
  value: any;
}

interface Action {
  type: 'email' | 'in_app' | 'slack_notify' | 'task';
  template: string;
  delay?: number;
}

const lifecycleStages: LifecycleStage[] = [
  {
    id: 'onboarding',
    name: 'Onboarding',
    triggers: [{ type: 'days_since_signup', value: { min: 0, max: 14 } }],
    actions: [
      { type: 'email', template: 'welcome', delay: 0 },
      { type: 'email', template: 'getting-started', delay: 1 },
      { type: 'email', template: 'first-project', delay: 3 },
      { type: 'email', template: 'invite-team', delay: 7 },
      { type: 'email', template: 'onboarding-check-in', delay: 14 }
    ]
  },
  {
    id: 'adoption',
    name: 'Adoption',
    triggers: [
      { type: 'days_since_signup', value: { min: 14, max: 60 } },
      { type: 'event', value: 'onboarding_completed' }
    ],
    actions: [
      { type: 'email', template: 'feature-spotlight-1', delay: 0 },
      { type: 'email', template: 'success-story', delay: 7 },
      { type: 'email', template: 'feature-spotlight-2', delay: 14 },
      { type: 'email', template: 'tips-tricks', delay: 21 }
    ]
  },
  {
    id: 'growth',
    name: 'Growth',
    triggers: [
      { type: 'days_since_signup', value: { min: 60 } },
      { type: 'health_score', value: { min: 70 } }
    ],
    actions: [
      { type: 'email', template: 'upgrade-benefits', delay: 0 },
      { type: 'email', template: 'case-study', delay: 14 },
      { type: 'in_app', template: 'upgrade-prompt', delay: 7 }
    ]
  },
  {
    id: 'renewal',
    name: 'Renewal',
    triggers: [
      { type: 'subscription', value: 'renewal_in_60_days' }
    ],
    actions: [
      { type: 'email', template: 'renewal-reminder-60', delay: 0 },
      { type: 'task', template: 'csm-outreach', delay: 0 },
      { type: 'email', template: 'renewal-reminder-30', delay: 30 },
      { type: 'email', template: 'renewal-reminder-7', delay: 53 }
    ]
  },
  {
    id: 'at-risk',
    name: 'At Risk',
    triggers: [
      { type: 'health_score', value: { max: 40 } }
    ],
    actions: [
      { type: 'slack_notify', template: 'at-risk-alert', delay: 0 },
      { type: 'email', template: 'we-miss-you', delay: 1 },
      { type: 'task', template: 'csm-intervention', delay: 0 },
      { type: 'email', template: 'how-can-we-help', delay: 3 }
    ]
  }
];

// Process lifecycle for all customers
export async function processLifecycleAutomation(): Promise<void> {
  const customers = await db.customer.findMany({
    include: {
      subscription: true,
      healthScore: true,
      lifecycleState: true
    }
  });

  for (const customer of customers) {
    await processCustomerLifecycle(customer);
  }
}

async function processCustomerLifecycle(customer: any): Promise<void> {
  // Determine current stage
  const currentStage = determineLifecycleStage(customer);

  if (!currentStage) return;

  // Check if stage changed
  const previousStage = customer.lifecycleState?.stageId;

  if (currentStage.id !== previousStage) {
    // Update stage
    await db.customerLifecycleState.upsert({
      where: { customerId: customer.id },
      create: {
        customerId: customer.id,
        stageId: currentStage.id,
        enteredAt: new Date()
      },
      update: {
        stageId: currentStage.id,
        enteredAt: new Date()
      }
    });

    // Execute stage entry actions
    for (const action of currentStage.actions) {
      await scheduleAction(customer.id, action);
    }
  }
}

function determineLifecycleStage(customer: any): LifecycleStage | null {
  const daysSinceSignup = differenceInDays(new Date(), customer.createdAt);
  const healthScore = customer.healthScore?.score || 50;
  const renewalDays = customer.subscription?.currentPeriodEnd
    ? differenceInDays(customer.subscription.currentPeriodEnd, new Date())
    : null;

  // Check stages in priority order
  if (healthScore < 40) {
    return lifecycleStages.find(s => s.id === 'at-risk')!;
  }

  if (renewalDays !== null && renewalDays <= 60) {
    return lifecycleStages.find(s => s.id === 'renewal')!;
  }

  if (daysSinceSignup < 14) {
    return lifecycleStages.find(s => s.id === 'onboarding')!;
  }

  if (daysSinceSignup < 60) {
    return lifecycleStages.find(s => s.id === 'adoption')!;
  }

  return lifecycleStages.find(s => s.id === 'growth')!;
}

async function scheduleAction(
  customerId: string,
  action: Action
): Promise<void> {
  const scheduledFor = action.delay
    ? addDays(new Date(), action.delay)
    : new Date();

  await db.scheduledAction.create({
    data: {
      customerId,
      actionType: action.type,
      template: action.template,
      scheduledFor,
      status: 'pending'
    }
  });
}
```

---

## Churn Prediction

```typescript
// lib/customer-success/churn-prediction.ts
import { db } from '@/lib/db';

interface ChurnPrediction {
  customerId: string;
  churnProbability: number;
  riskFactors: RiskFactor[];
  recommendedActions: string[];
}

interface RiskFactor {
  factor: string;
  impact: 'high' | 'medium' | 'low';
  currentValue: number;
  threshold: number;
}

export async function predictChurn(customerId: string): Promise<ChurnPrediction> {
  const riskFactors: RiskFactor[] = [];
  let churnScore = 0;

  // Factor 1: Login frequency decline
  const loginDecline = await calculateLoginDecline(customerId);
  if (loginDecline > 50) {
    riskFactors.push({
      factor: 'Login frequency decreased',
      impact: 'high',
      currentValue: loginDecline,
      threshold: 50
    });
    churnScore += 25;
  }

  // Factor 2: Feature usage decline
  const featureDecline = await calculateFeatureUsageDecline(customerId);
  if (featureDecline > 30) {
    riskFactors.push({
      factor: 'Feature usage decreased',
      impact: 'medium',
      currentValue: featureDecline,
      threshold: 30
    });
    churnScore += 15;
  }

  // Factor 3: Support sentiment
  const supportSentiment = await analyzeSupportSentiment(customerId);
  if (supportSentiment < 0.3) {
    riskFactors.push({
      factor: 'Negative support interactions',
      impact: 'high',
      currentValue: supportSentiment,
      threshold: 0.3
    });
    churnScore += 20;
  }

  // Factor 4: NPS score
  const npsScore = await getLatestNPS(customerId);
  if (npsScore !== null && npsScore < 7) {
    riskFactors.push({
      factor: 'Low NPS score',
      impact: npsScore < 5 ? 'high' : 'medium',
      currentValue: npsScore,
      threshold: 7
    });
    churnScore += npsScore < 5 ? 25 : 15;
  }

  // Factor 5: Key user departure
  const keyUserLeft = await checkKeyUserDeparture(customerId);
  if (keyUserLeft) {
    riskFactors.push({
      factor: 'Key user left organization',
      impact: 'high',
      currentValue: 1,
      threshold: 0
    });
    churnScore += 20;
  }

  // Factor 6: Contract value change
  const contractDecreased = await checkContractDecrease(customerId);
  if (contractDecreased) {
    riskFactors.push({
      factor: 'Contract value decreased',
      impact: 'medium',
      currentValue: 1,
      threshold: 0
    });
    churnScore += 15;
  }

  const churnProbability = Math.min(100, churnScore);

  // Generate recommended actions
  const recommendedActions = generateRecommendations(riskFactors);

  return {
    customerId,
    churnProbability,
    riskFactors,
    recommendedActions
  };
}

function generateRecommendations(riskFactors: RiskFactor[]): string[] {
  const recommendations: string[] = [];

  const factorTypes = riskFactors.map(f => f.factor);

  if (factorTypes.includes('Login frequency decreased')) {
    recommendations.push('Schedule re-engagement call');
    recommendations.push('Send personalized win-back email');
  }

  if (factorTypes.includes('Feature usage decreased')) {
    recommendations.push('Offer feature training session');
    recommendations.push('Share relevant use case examples');
  }

  if (factorTypes.includes('Negative support interactions')) {
    recommendations.push('Escalate to senior support');
    recommendations.push('CSM personal outreach');
  }

  if (factorTypes.includes('Low NPS score')) {
    recommendations.push('Schedule NPS follow-up call');
    recommendations.push('Address specific feedback');
  }

  if (factorTypes.includes('Key user left organization')) {
    recommendations.push('Identify and onboard new champion');
    recommendations.push('Executive sponsor outreach');
  }

  return recommendations;
}

// Batch process all customers
export async function runChurnPredictions(): Promise<void> {
  const customers = await db.customer.findMany({
    where: { subscription: { status: 'active' } }
  });

  for (const customer of customers) {
    const prediction = await predictChurn(customer.id);

    // Store prediction
    await db.churnPrediction.upsert({
      where: { customerId: customer.id },
      create: {
        customerId: customer.id,
        probability: prediction.churnProbability,
        riskFactors: prediction.riskFactors,
        predictedAt: new Date()
      },
      update: {
        probability: prediction.churnProbability,
        riskFactors: prediction.riskFactors,
        predictedAt: new Date()
      }
    });

    // Alert if high risk
    if (prediction.churnProbability > 70) {
      await createChurnAlert(customer.id, prediction);
    }
  }
}
```

---

## NPS Survey Automation

```tsx
// components/NPS/NPSSurvey.tsx
'use client';

import { useState } from 'react';

interface NPSSurveyProps {
  onSubmit: (score: number, feedback?: string) => void;
  onDismiss: () => void;
}

export function NPSSurvey({ onSubmit, onDismiss }: NPSSurveyProps) {
  const [score, setScore] = useState<number | null>(null);
  const [feedback, setFeedback] = useState('');
  const [step, setStep] = useState<'score' | 'feedback'>('score');

  const handleScoreSelect = (value: number) => {
    setScore(value);
    setStep('feedback');
  };

  const handleSubmit = () => {
    if (score !== null) {
      onSubmit(score, feedback || undefined);
    }
  };

  return (
    <div className="fixed bottom-4 right-4 w-96 bg-white rounded-lg shadow-xl p-6">
      <button
        onClick={onDismiss}
        className="absolute top-2 right-2 text-gray-400"
      >
        ×
      </button>

      {step === 'score' ? (
        <>
          <h3 className="text-lg font-semibold mb-4">
            How likely are you to recommend us?
          </h3>

          <div className="flex gap-1 mb-4">
            {Array.from({ length: 11 }, (_, i) => (
              <button
                key={i}
                onClick={() => handleScoreSelect(i)}
                className={`w-8 h-8 rounded text-sm font-medium transition ${
                  i <= 6 ? 'hover:bg-red-100' :
                  i <= 8 ? 'hover:bg-yellow-100' : 'hover:bg-green-100'
                } ${score === i ? 'ring-2 ring-blue-500' : 'bg-gray-100'}`}
              >
                {i}
              </button>
            ))}
          </div>

          <div className="flex justify-between text-xs text-gray-500">
            <span>Not at all likely</span>
            <span>Extremely likely</span>
          </div>
        </>
      ) : (
        <>
          <h3 className="text-lg font-semibold mb-2">
            {score! >= 9 ? "That's great! What do you love most?" :
             score! >= 7 ? "Thanks! How can we improve?" :
             "We're sorry to hear that. What went wrong?"}
          </h3>

          <textarea
            value={feedback}
            onChange={(e) => setFeedback(e.target.value)}
            placeholder="Your feedback helps us improve..."
            className="w-full p-3 border rounded-lg mb-4"
            rows={3}
          />

          <div className="flex gap-2">
            <button
              onClick={() => setStep('score')}
              className="px-4 py-2 text-gray-600"
            >
              Back
            </button>
            <button
              onClick={handleSubmit}
              className="flex-1 px-4 py-2 bg-blue-600 text-white rounded-lg"
            >
              Submit
            </button>
          </div>
        </>
      )}
    </div>
  );
}
```

---

## Best Practices

| Area | Recommendation |
|------|----------------|
| **Health Score** | Update daily, weight factors appropriately |
| **Lifecycle** | Personalize based on segment and behavior |
| **Churn** | Act on predictions within 48 hours |
| **NPS** | Survey at key moments, not randomly |
| **Automation** | Always allow human override |

---

## Fazit

Customer Success Automation ermöglicht:

1. **Health Scores**: Frühzeitige Risiko-Erkennung
2. **Lifecycle Emails**: Skalierbare Kommunikation
3. **Churn Prediction**: Proaktive Intervention
4. **NPS**: Kontinuierliches Feedback

Automatisierung skaliert Customer Success ohne Qualitätsverlust.

---

## Bildprompts

1. "Customer health score dashboard, gauge visualization with risk levels"
2. "Lifecycle email automation flow, triggered sequences"
3. "Churn prediction model, risk factors highlighted"

---

## Quellen

- [Gainsight Customer Success](https://www.gainsight.com/customer-success/)
- [ChurnZero Best Practices](https://churnzero.com/resources/)
- [Customer Success Metrics](https://www.custify.com/blog/customer-success-metrics/)
- [NPS Best Practices](https://www.netpromoter.com/know/)
