n8n Automation

n8n Customer Onboarding Automation: Building End-to-End Onboarding Workflows

DeviDevs Team
15 min read
#n8n#customer onboarding#automation#CRM#user experience

n8n Customer Onboarding Automation: Building End-to-End Onboarding Workflows

Effective customer onboarding drives retention and satisfaction. This guide shows how to build comprehensive onboarding automation with n8n for seamless customer experiences.

Onboarding Workflow Architecture

New Customer Trigger Handler

// n8n Function Node - New Customer Processor
const webhookData = $input.first().json;
 
// Validate incoming customer data
const requiredFields = ['email', 'name', 'plan'];
const missingFields = requiredFields.filter(f => !webhookData[f]);
 
if (missingFields.length > 0) {
  throw new Error(`Missing required fields: ${missingFields.join(', ')}`);
}
 
// Normalize and enrich customer data
const customer = {
  id: webhookData.customer_id || `cust_${Date.now()}`,
  email: webhookData.email.toLowerCase().trim(),
  firstName: extractFirstName(webhookData.name),
  lastName: extractLastName(webhookData.name),
  fullName: webhookData.name,
  company: webhookData.company || null,
  plan: webhookData.plan,
  planTier: determinePlanTier(webhookData.plan),
  source: webhookData.source || 'website',
  signupDate: new Date().toISOString(),
  timezone: webhookData.timezone || 'UTC',
  locale: webhookData.locale || 'en',
  metadata: {
    utm_source: webhookData.utm_source,
    utm_medium: webhookData.utm_medium,
    utm_campaign: webhookData.utm_campaign,
    referrer: webhookData.referrer
  }
};
 
// Determine onboarding path
const onboardingPath = determineOnboardingPath(customer);
 
function extractFirstName(fullName) {
  return fullName.split(' ')[0];
}
 
function extractLastName(fullName) {
  const parts = fullName.split(' ');
  return parts.length > 1 ? parts.slice(1).join(' ') : '';
}
 
function determinePlanTier(plan) {
  const tiers = {
    'starter': 'basic',
    'professional': 'standard',
    'business': 'premium',
    'enterprise': 'enterprise'
  };
  return tiers[plan.toLowerCase()] || 'basic';
}
 
function determineOnboardingPath(customer) {
  // Enterprise customers get white-glove onboarding
  if (customer.planTier === 'enterprise') {
    return {
      type: 'enterprise',
      steps: ['sales_handoff', 'kickoff_call', 'custom_setup', 'training', 'go_live'],
      assignedCSM: true,
      duration: '30_days'
    };
  }
 
  // Premium gets guided onboarding
  if (customer.planTier === 'premium') {
    return {
      type: 'guided',
      steps: ['welcome', 'setup_wizard', 'demo_call', 'training_videos', 'check_in'],
      assignedCSM: false,
      duration: '14_days'
    };
  }
 
  // Standard self-service onboarding
  return {
    type: 'self_service',
    steps: ['welcome', 'setup_wizard', 'email_sequence', 'in_app_guides'],
    assignedCSM: false,
    duration: '7_days'
  };
}
 
return {
  json: {
    customer,
    onboarding: {
      path: onboardingPath,
      startedAt: new Date().toISOString(),
      currentStep: 0,
      completedSteps: [],
      status: 'started'
    }
  }
};

User Provisioning Workflow

// n8n Function Node - Account Provisioning
const { customer, onboarding } = $input.first().json;
 
// Generate secure credentials
const provisioning = {
  customerId: customer.id,
  accountId: `acc_${generateSecureId()}`,
  apiKey: `sk_live_${generateSecureId(32)}`,
  webhookSecret: `whsec_${generateSecureId(24)}`,
  tempPassword: generateTempPassword(),
  passwordResetToken: generateSecureId(48),
  tokenExpiry: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString() // 24 hours
};
 
// Determine initial setup based on plan
const initialSetup = {
  features: getFeaturesByPlan(customer.plan),
  limits: getLimitsByPlan(customer.plan),
  defaults: getDefaultSettings(customer.planTier),
  integrations: []
};
 
// Create provisioning tasks
const tasks = [
  {
    type: 'create_account',
    data: {
      accountId: provisioning.accountId,
      email: customer.email,
      name: customer.fullName,
      plan: customer.plan
    }
  },
  {
    type: 'create_api_credentials',
    data: {
      accountId: provisioning.accountId,
      apiKey: provisioning.apiKey,
      webhookSecret: provisioning.webhookSecret
    }
  },
  {
    type: 'setup_initial_config',
    data: initialSetup
  },
  {
    type: 'create_sample_data',
    data: {
      accountId: provisioning.accountId,
      templates: getSampleTemplates(customer.planTier)
    }
  }
];
 
function generateSecureId(length = 16) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  let result = '';
  for (let i = 0; i < length; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return result;
}
 
function generateTempPassword() {
  const upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  const lower = 'abcdefghijklmnopqrstuvwxyz';
  const numbers = '0123456789';
  const special = '!@#$%^&*';
 
  let password = '';
  password += upper.charAt(Math.floor(Math.random() * upper.length));
  password += lower.charAt(Math.floor(Math.random() * lower.length));
  password += numbers.charAt(Math.floor(Math.random() * numbers.length));
  password += special.charAt(Math.floor(Math.random() * special.length));
 
  const allChars = upper + lower + numbers + special;
  for (let i = 0; i < 8; i++) {
    password += allChars.charAt(Math.floor(Math.random() * allChars.length));
  }
 
  return password.split('').sort(() => Math.random() - 0.5).join('');
}
 
function getFeaturesByPlan(plan) {
  const features = {
    starter: ['basic_dashboard', 'email_support', 'api_access'],
    professional: ['advanced_analytics', 'priority_support', 'api_access', 'integrations'],
    business: ['custom_reports', 'dedicated_support', 'advanced_api', 'sso', 'audit_logs'],
    enterprise: ['all_features', 'custom_development', 'sla', 'dedicated_infrastructure']
  };
  return features[plan.toLowerCase()] || features.starter;
}
 
function getLimitsByPlan(plan) {
  const limits = {
    starter: { users: 5, storage_gb: 10, api_calls_monthly: 10000 },
    professional: { users: 25, storage_gb: 100, api_calls_monthly: 100000 },
    business: { users: 100, storage_gb: 500, api_calls_monthly: 500000 },
    enterprise: { users: -1, storage_gb: -1, api_calls_monthly: -1 } // Unlimited
  };
  return limits[plan.toLowerCase()] || limits.starter;
}
 
function getDefaultSettings(tier) {
  return {
    notifications: { email: true, in_app: true, slack: tier !== 'basic' },
    security: { mfa_required: tier === 'enterprise', session_timeout: 3600 },
    privacy: { analytics_enabled: true, crash_reports: true }
  };
}
 
function getSampleTemplates(tier) {
  const templates = ['getting_started', 'basic_workflow'];
  if (tier !== 'basic') {
    templates.push('advanced_automation', 'reporting_template');
  }
  if (tier === 'enterprise') {
    templates.push('enterprise_integration', 'compliance_workflow');
  }
  return templates;
}
 
return {
  json: {
    customer,
    onboarding,
    provisioning,
    tasks
  }
};

Welcome Email Sequence

// n8n Function Node - Email Sequence Builder
const { customer, onboarding, provisioning } = $input.first().json;
 
// Build personalized email sequence
const emailSequence = [];
 
// Day 0 - Welcome Email
emailSequence.push({
  day: 0,
  hours: 0,
  template: 'welcome',
  subject: `Welcome to ${process.env.COMPANY_NAME}, ${customer.firstName}!`,
  personalization: {
    firstName: customer.firstName,
    plan: customer.plan,
    loginUrl: `${process.env.APP_URL}/login`,
    passwordResetUrl: `${process.env.APP_URL}/reset-password?token=${provisioning.passwordResetToken}`,
    supportEmail: process.env.SUPPORT_EMAIL
  },
  tags: ['onboarding', 'day_0', 'welcome']
});
 
// Day 1 - Getting Started Guide
emailSequence.push({
  day: 1,
  hours: 10, // Send at 10 AM in customer's timezone
  template: 'getting_started',
  subject: `Get started with ${process.env.COMPANY_NAME} in 5 minutes`,
  personalization: {
    firstName: customer.firstName,
    quickStartUrl: `${process.env.APP_URL}/quickstart`,
    videoTutorialUrl: `${process.env.DOCS_URL}/tutorials/getting-started`,
    features: getTopFeatures(customer.plan)
  },
  tags: ['onboarding', 'day_1', 'education'],
  condition: {
    type: 'not_completed',
    milestone: 'first_login'
  }
});
 
// Day 3 - Feature Spotlight
emailSequence.push({
  day: 3,
  hours: 14,
  template: 'feature_spotlight',
  subject: `Did you know? ${getFeatureSpotlight(customer.plan).title}`,
  personalization: {
    firstName: customer.firstName,
    feature: getFeatureSpotlight(customer.plan),
    cta_url: `${process.env.APP_URL}/features/${getFeatureSpotlight(customer.plan).slug}`
  },
  tags: ['onboarding', 'day_3', 'feature'],
  condition: {
    type: 'not_used',
    feature: getFeatureSpotlight(customer.plan).slug
  }
});
 
// Day 5 - Integration Suggestions
if (customer.planTier !== 'basic') {
  emailSequence.push({
    day: 5,
    hours: 10,
    template: 'integrations',
    subject: `Connect ${process.env.COMPANY_NAME} to your favorite tools`,
    personalization: {
      firstName: customer.firstName,
      suggestedIntegrations: getSuggestedIntegrations(customer),
      integrationsUrl: `${process.env.APP_URL}/integrations`
    },
    tags: ['onboarding', 'day_5', 'integrations']
  });
}
 
// Day 7 - Check-in
emailSequence.push({
  day: 7,
  hours: 10,
  template: 'check_in',
  subject: `How's it going, ${customer.firstName}?`,
  personalization: {
    firstName: customer.firstName,
    usageStats: '{{usage_stats}}', // Placeholder for dynamic data
    feedbackUrl: `${process.env.APP_URL}/feedback`,
    bookCallUrl: onboarding.path.type !== 'self_service' ?
      `${process.env.CALENDLY_URL}/onboarding-call` : null
  },
  tags: ['onboarding', 'day_7', 'engagement']
});
 
// Day 14 - Success Tips (for guided onboarding)
if (onboarding.path.type !== 'self_service') {
  emailSequence.push({
    day: 14,
    hours: 10,
    template: 'success_tips',
    subject: `Pro tips for ${customer.plan} users`,
    personalization: {
      firstName: customer.firstName,
      tips: getProTips(customer.planTier),
      communityUrl: `${process.env.COMMUNITY_URL}`,
      webinarUrl: `${process.env.APP_URL}/webinars`
    },
    tags: ['onboarding', 'day_14', 'education']
  });
}
 
function getTopFeatures(plan) {
  const features = {
    starter: [
      { name: 'Dashboard', description: 'View all your data at a glance' },
      { name: 'Reports', description: 'Generate basic reports' }
    ],
    professional: [
      { name: 'Advanced Analytics', description: 'Deep dive into your metrics' },
      { name: 'Integrations', description: 'Connect your favorite tools' }
    ],
    business: [
      { name: 'Custom Reports', description: 'Build reports your way' },
      { name: 'Team Collaboration', description: 'Work together seamlessly' }
    ],
    enterprise: [
      { name: 'SSO', description: 'Secure single sign-on' },
      { name: 'Audit Logs', description: 'Complete activity tracking' }
    ]
  };
  return features[plan.toLowerCase()] || features.starter;
}
 
function getFeatureSpotlight(plan) {
  const spotlights = {
    starter: { title: 'Automated Reminders', slug: 'reminders', description: 'Never miss important tasks' },
    professional: { title: 'Workflow Automation', slug: 'workflows', description: 'Automate repetitive tasks' },
    business: { title: 'Custom Dashboards', slug: 'dashboards', description: 'Build your perfect view' },
    enterprise: { title: 'API Access', slug: 'api', description: 'Build custom integrations' }
  };
  return spotlights[plan.toLowerCase()] || spotlights.starter;
}
 
function getSuggestedIntegrations(customer) {
  // Would be based on customer industry/use case
  return [
    { name: 'Slack', icon: 'slack', description: 'Get notifications in Slack' },
    { name: 'Google Calendar', icon: 'google-calendar', description: 'Sync your schedule' },
    { name: 'Zapier', icon: 'zapier', description: 'Connect 3000+ apps' }
  ];
}
 
function getProTips(tier) {
  return [
    'Use keyboard shortcuts to navigate faster',
    'Set up weekly email digests for team updates',
    'Create templates for common tasks'
  ];
}
 
// Calculate send times
const scheduledEmails = emailSequence.map(email => {
  const sendDate = new Date(customer.signupDate);
  sendDate.setDate(sendDate.getDate() + email.day);
  sendDate.setHours(email.hours, 0, 0, 0);
 
  return {
    ...email,
    scheduledAt: sendDate.toISOString(),
    recipientEmail: customer.email,
    recipientName: customer.fullName,
    customerId: customer.id
  };
});
 
return {
  json: {
    customer,
    onboarding,
    emailSequence: scheduledEmails
  }
};

Progress Tracking

// n8n Function Node - Onboarding Progress Tracker
const customer = $input.first().json.customer;
const currentProgress = $('Get Current Progress').first()?.json || {};
 
// Define onboarding milestones
const milestones = {
  self_service: [
    { id: 'account_created', name: 'Account Created', weight: 10 },
    { id: 'first_login', name: 'First Login', weight: 15 },
    { id: 'profile_completed', name: 'Profile Completed', weight: 10 },
    { id: 'first_project', name: 'Created First Project', weight: 20 },
    { id: 'invited_team', name: 'Invited Team Member', weight: 15 },
    { id: 'used_core_feature', name: 'Used Core Feature', weight: 20 },
    { id: 'completed_tutorial', name: 'Completed Tutorial', weight: 10 }
  ],
  guided: [
    { id: 'account_created', name: 'Account Created', weight: 5 },
    { id: 'first_login', name: 'First Login', weight: 10 },
    { id: 'profile_completed', name: 'Profile Completed', weight: 5 },
    { id: 'demo_completed', name: 'Demo Call Completed', weight: 15 },
    { id: 'first_project', name: 'Created First Project', weight: 15 },
    { id: 'integration_setup', name: 'Set Up Integration', weight: 15 },
    { id: 'invited_team', name: 'Invited Team', weight: 15 },
    { id: 'training_completed', name: 'Completed Training', weight: 20 }
  ],
  enterprise: [
    { id: 'kickoff_completed', name: 'Kickoff Call Completed', weight: 10 },
    { id: 'requirements_gathered', name: 'Requirements Gathered', weight: 10 },
    { id: 'environment_setup', name: 'Environment Set Up', weight: 15 },
    { id: 'sso_configured', name: 'SSO Configured', weight: 10 },
    { id: 'data_migration', name: 'Data Migration Complete', weight: 15 },
    { id: 'team_training', name: 'Team Training Complete', weight: 15 },
    { id: 'pilot_launched', name: 'Pilot Launched', weight: 10 },
    { id: 'go_live', name: 'Go Live Complete', weight: 15 }
  ]
};
 
// Get relevant milestones for customer
const customerMilestones = milestones[currentProgress.onboardingType] || milestones.self_service;
 
// Calculate progress
const completedMilestones = currentProgress.completedMilestones || [];
const completedWeight = customerMilestones
  .filter(m => completedMilestones.includes(m.id))
  .reduce((sum, m) => sum + m.weight, 0);
 
const progressPercentage = Math.round(completedWeight);
 
// Determine current step
const pendingMilestones = customerMilestones.filter(m => !completedMilestones.includes(m.id));
const nextMilestone = pendingMilestones[0];
 
// Calculate health score
const healthScore = calculateHealthScore(customer, currentProgress);
 
// Determine if intervention needed
const intervention = checkForIntervention(customer, currentProgress, healthScore);
 
function calculateHealthScore(customer, progress) {
  let score = 100;
 
  // Days since signup
  const daysSinceSignup = Math.floor(
    (Date.now() - new Date(customer.signupDate).getTime()) / (1000 * 60 * 60 * 24)
  );
 
  // Penalize slow progress
  const expectedProgress = Math.min(daysSinceSignup * 10, 70); // Expect ~70% by day 7
  const actualProgress = progressPercentage;
 
  if (actualProgress < expectedProgress) {
    score -= (expectedProgress - actualProgress);
  }
 
  // Penalize no recent activity
  const lastActivity = progress.lastActivityAt ?
    Math.floor((Date.now() - new Date(progress.lastActivityAt).getTime()) / (1000 * 60 * 60 * 24)) : daysSinceSignup;
 
  if (lastActivity > 3) {
    score -= (lastActivity - 3) * 5;
  }
 
  // Boost for key actions
  if (completedMilestones.includes('invited_team')) score += 10;
  if (completedMilestones.includes('integration_setup')) score += 10;
 
  return Math.max(0, Math.min(100, score));
}
 
function checkForIntervention(customer, progress, healthScore) {
  const interventions = [];
 
  // Low health score
  if (healthScore < 50) {
    interventions.push({
      type: 'low_health',
      action: 'personal_outreach',
      priority: 'high',
      message: 'Customer may need assistance'
    });
  }
 
  // No login after 48 hours
  if (!progress.completedMilestones?.includes('first_login')) {
    const hoursSinceSignup = (Date.now() - new Date(customer.signupDate).getTime()) / (1000 * 60 * 60);
    if (hoursSinceSignup > 48) {
      interventions.push({
        type: 'no_login',
        action: 'reminder_email',
        priority: 'medium',
        message: 'Customer has not logged in'
      });
    }
  }
 
  // Stalled at specific milestone
  if (progress.stalledAt) {
    interventions.push({
      type: 'stalled_progress',
      action: 'help_content',
      priority: 'medium',
      milestone: progress.stalledAt,
      message: `Customer stuck at ${progress.stalledAt}`
    });
  }
 
  return interventions;
}
 
// Build progress report
const progressReport = {
  customerId: customer.id,
  email: customer.email,
  plan: customer.plan,
  onboardingType: currentProgress.onboardingType || 'self_service',
  startedAt: customer.signupDate,
  lastActivityAt: currentProgress.lastActivityAt,
  progress: {
    percentage: progressPercentage,
    completedMilestones: completedMilestones,
    pendingMilestones: pendingMilestones.map(m => m.id),
    nextMilestone: nextMilestone,
    totalMilestones: customerMilestones.length
  },
  healthScore: healthScore,
  interventionsNeeded: intervention,
  status: progressPercentage >= 100 ? 'completed' :
          progressPercentage >= 50 ? 'on_track' :
          healthScore < 50 ? 'at_risk' : 'in_progress',
  generatedAt: new Date().toISOString()
};
 
return { json: progressReport };

Personalized In-App Guides

// n8n Function Node - In-App Guide Builder
const customer = $input.first().json;
const userBehavior = $('Get User Behavior').first()?.json || {};
 
// Define guide templates
const guideTemplates = {
  welcome_tour: {
    id: 'welcome_tour',
    name: 'Welcome Tour',
    type: 'product_tour',
    steps: [
      {
        target: '#dashboard',
        title: 'Your Dashboard',
        content: 'This is where you\'ll see all your important metrics at a glance.',
        position: 'bottom'
      },
      {
        target: '#create-button',
        title: 'Create Your First Project',
        content: 'Click here to start your first project. We\'ll guide you through the process.',
        position: 'right'
      },
      {
        target: '#settings-menu',
        title: 'Customize Your Experience',
        content: 'Access settings to personalize your workspace.',
        position: 'left'
      }
    ],
    trigger: 'first_login',
    dismissible: true
  },
 
  feature_discovery: {
    id: 'feature_discovery',
    name: 'Feature Discovery',
    type: 'tooltip_sequence',
    steps: [
      {
        target: '#analytics-tab',
        title: 'Analytics',
        content: 'Deep dive into your data with advanced analytics.',
        position: 'bottom',
        condition: { plan_tier: ['standard', 'premium', 'enterprise'] }
      },
      {
        target: '#automations',
        title: 'Automations',
        content: 'Set up automated workflows to save time.',
        position: 'right'
      }
    ],
    trigger: 'milestone_completed',
    milestone: 'first_project'
  },
 
  empty_state_prompt: {
    id: 'empty_state_prompt',
    name: 'Getting Started Prompt',
    type: 'modal',
    content: {
      title: 'Let\'s Get Started!',
      body: 'Create your first project to unlock the full potential of our platform.',
      cta_text: 'Create Project',
      cta_action: 'open_create_modal',
      secondary_text: 'Watch Tutorial',
      secondary_action: 'open_tutorial'
    },
    trigger: 'empty_state',
    entity: 'projects'
  },
 
  integration_prompt: {
    id: 'integration_prompt',
    name: 'Integration Suggestion',
    type: 'banner',
    content: {
      title: 'Connect Your Tools',
      body: 'Integrate with your favorite apps to streamline your workflow.',
      cta_text: 'View Integrations',
      cta_action: 'navigate_integrations'
    },
    trigger: 'time_in_app',
    threshold_minutes: 30,
    condition: { integrations_count: 0 }
  },
 
  upgrade_prompt: {
    id: 'upgrade_prompt',
    name: 'Upgrade Prompt',
    type: 'modal',
    content: {
      title: 'Unlock More Features',
      body: 'You\'re using {{usage_percentage}}% of your plan limits. Upgrade to unlock more.',
      features: ['Unlimited projects', 'Advanced analytics', 'Priority support'],
      cta_text: 'View Plans',
      cta_action: 'navigate_pricing'
    },
    trigger: 'usage_threshold',
    threshold: 80
  }
};
 
// Determine which guides to show based on user state
function selectGuidesForUser(customer, behavior) {
  const selectedGuides = [];
  const now = new Date();
  const signupDate = new Date(customer.signupDate);
  const daysSinceSignup = Math.floor((now - signupDate) / (1000 * 60 * 60 * 24));
 
  // First login - show welcome tour
  if (behavior.loginCount <= 1 && !behavior.completedGuides?.includes('welcome_tour')) {
    selectedGuides.push({
      ...guideTemplates.welcome_tour,
      priority: 1,
      reason: 'First login'
    });
  }
 
  // After first project - show feature discovery
  if (behavior.projectsCreated >= 1 && !behavior.completedGuides?.includes('feature_discovery')) {
    const guide = guideTemplates.feature_discovery;
    // Filter steps based on plan
    guide.steps = guide.steps.filter(step => {
      if (!step.condition) return true;
      if (step.condition.plan_tier) {
        return step.condition.plan_tier.includes(customer.planTier);
      }
      return true;
    });
    selectedGuides.push({
      ...guide,
      priority: 2,
      reason: 'First project completed'
    });
  }
 
  // Empty state - prompt to create
  if (behavior.projectsCreated === 0 && daysSinceSignup >= 1) {
    selectedGuides.push({
      ...guideTemplates.empty_state_prompt,
      priority: 1,
      reason: 'No projects after 24 hours'
    });
  }
 
  // Integration prompt after spending time in app
  if (behavior.totalMinutesInApp >= 30 &&
      behavior.integrationsCount === 0 &&
      !behavior.dismissedGuides?.includes('integration_prompt')) {
    selectedGuides.push({
      ...guideTemplates.integration_prompt,
      priority: 3,
      reason: 'No integrations after 30 minutes'
    });
  }
 
  // Upgrade prompt at usage threshold
  if (behavior.usagePercentage >= 80 && customer.planTier !== 'enterprise') {
    const guide = { ...guideTemplates.upgrade_prompt };
    guide.content.body = guide.content.body.replace('{{usage_percentage}}', behavior.usagePercentage);
    selectedGuides.push({
      ...guide,
      priority: 2,
      reason: 'High usage'
    });
  }
 
  return selectedGuides.sort((a, b) => a.priority - b.priority);
}
 
// Personalize guide content
function personalizeGuide(guide, customer) {
  const personalized = JSON.parse(JSON.stringify(guide));
 
  // Replace placeholders
  const replacements = {
    '{{firstName}}': customer.firstName,
    '{{company}}': customer.company || 'your team',
    '{{plan}}': customer.plan
  };
 
  const contentStr = JSON.stringify(personalized);
  let personalizedContent = contentStr;
  for (const [placeholder, value] of Object.entries(replacements)) {
    personalizedContent = personalizedContent.replace(new RegExp(placeholder, 'g'), value);
  }
 
  return JSON.parse(personalizedContent);
}
 
const selectedGuides = selectGuidesForUser(customer, userBehavior);
const personalizedGuides = selectedGuides.map(guide => personalizeGuide(guide, customer));
 
return {
  json: {
    customerId: customer.id,
    guides: personalizedGuides,
    behavior: userBehavior,
    generatedAt: new Date().toISOString()
  }
};

Completion and Handoff

// n8n Function Node - Onboarding Completion Handler
const progressReport = $input.first().json;
 
// Check if onboarding is complete
const isComplete = progressReport.progress.percentage >= 100;
const isTimedOut = checkOnboardingTimeout(progressReport);
 
// Determine next steps
function determineNextSteps(report) {
  if (isComplete) {
    return {
      action: 'complete_onboarding',
      tasks: [
        { type: 'send_completion_email', template: 'onboarding_complete' },
        { type: 'update_customer_stage', stage: 'active' },
        { type: 'trigger_nps_survey', delay_days: 7 },
        { type: 'schedule_success_call', condition: 'premium_or_higher' }
      ]
    };
  }
 
  if (isTimedOut) {
    return {
      action: 'escalate_stalled',
      tasks: [
        { type: 'notify_csm', priority: 'high' },
        { type: 'send_reengagement_email', template: 'stuck_onboarding' },
        { type: 'create_support_ticket', reason: 'Stalled onboarding' }
      ]
    };
  }
 
  if (report.interventionsNeeded.length > 0) {
    return {
      action: 'intervention_required',
      tasks: report.interventionsNeeded.map(i => ({
        type: `handle_${i.type}`,
        ...i
      }))
    };
  }
 
  return {
    action: 'continue_monitoring',
    tasks: []
  };
}
 
function checkOnboardingTimeout(report) {
  const maxDays = {
    self_service: 14,
    guided: 30,
    enterprise: 60
  };
 
  const daysSinceStart = Math.floor(
    (Date.now() - new Date(report.startedAt).getTime()) / (1000 * 60 * 60 * 24)
  );
 
  const timeout = maxDays[report.onboardingType] || 14;
  return daysSinceStart > timeout && report.progress.percentage < 100;
}
 
// Build completion report
const completionReport = {
  customerId: progressReport.customerId,
  email: progressReport.email,
  plan: progressReport.plan,
  onboardingType: progressReport.onboardingType,
  finalStatus: isComplete ? 'completed' : isTimedOut ? 'timed_out' : 'in_progress',
  completionPercentage: progressReport.progress.percentage,
  healthScore: progressReport.healthScore,
  completedMilestones: progressReport.progress.completedMilestones,
  pendingMilestones: progressReport.progress.pendingMilestones,
  timeToComplete: isComplete ? calculateTimeToComplete(progressReport) : null,
  nextSteps: determineNextSteps(progressReport),
  recommendations: generateRecommendations(progressReport),
  reportedAt: new Date().toISOString()
};
 
function calculateTimeToComplete(report) {
  const start = new Date(report.startedAt);
  const end = new Date();
  return Math.floor((end - start) / (1000 * 60 * 60 * 24)); // days
}
 
function generateRecommendations(report) {
  const recommendations = [];
 
  if (report.progress.percentage < 50) {
    recommendations.push({
      type: 'engagement',
      message: 'Consider personalized outreach to improve engagement'
    });
  }
 
  if (!report.progress.completedMilestones.includes('invited_team')) {
    recommendations.push({
      type: 'expansion',
      message: 'Encourage team invitations for better adoption'
    });
  }
 
  if (report.healthScore < 70) {
    recommendations.push({
      type: 'support',
      message: 'Proactive support call recommended'
    });
  }
 
  return recommendations;
}
 
return { json: completionReport };

Best Practices

Onboarding Design

  1. Personalize by segment: Different customers need different onboarding paths
  2. Track milestones: Define clear success metrics for each onboarding stage
  3. Intervene early: Monitor health scores and act before customers churn
  4. Iterate continuously: Improve based on completion rates and feedback

Automation Tips

  • Use conditional email sequences based on user actions
  • Implement smart delays between touchpoints
  • Combine in-app guides with email for multi-channel engagement
  • Track every interaction for optimization

Automated onboarding with n8n ensures consistent, personalized experiences that drive customer success and retention.

Weekly AI Security & Automation Digest

Get the latest on AI Security, workflow automation, secure integrations, and custom platform development delivered weekly.

No spam. Unsubscribe anytime.