- Add 100 blog posts covering AI, development, and tech topics - Add .env.example for environment configuration - Add accessibility and lighthouse audit scripts - Remove obsolete SEO reports and temporary files - Remove dev-dist build artifacts and backup files - Remove unused portrait images (moved/consolidated elsewhere) - Update contact form and component improvements Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
785 lines
23 KiB
Markdown
785 lines
23 KiB
Markdown
# 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/)
|