Skip to content
Funnel Analysis logo

Funnel Analysis

Analyze user conversion funnels, identify drop-off points, and optimize conversion rates for conversion optimization and user flow analysis

SKILL.md

Full skill instructions

Funnel Analysis

Overview

Funnel analysis tracks user progression through sequential steps, identifying where users drop off and optimizing each stage for better conversion.

When to Use

  • When optimizing user conversion paths and improving conversion rates
  • When identifying bottlenecks and drop-off points in user flows
  • When comparing performance across different segments or traffic sources
  • When measuring product feature adoption or onboarding effectiveness
  • When improving customer journey efficiency and user experience
  • When A/​B testing different funnel configurations or designs

Funnel Structure

  • Stage 1: Initial entry (landing page, app open)
  • Stage 2-N: Intermediate steps (signup, selection, payment)
  • Final Stage: Goal completion (purchase, subscription, sign-up)
  • Drop-off: Users not progressing to next stage
  • Conversion Rate: % progressing to next step

Key Metrics

  • Drop-off Rate: % leaving at each stage
  • Conversion Rate: % progressing per stage
  • Funnel Efficiency: Overall conversion (Stage 1 to Final)
  • Friction Score: Identifying problem areas

Implementation with Python

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Create sample funnel data
np.random.seed(42)

funnel_stages = ['Landing Page', 'Sign Up', 'Product Selection', 'Add to Cart', 'Checkout', 'Payment', 'Confirmation']

# Simulate user journey (progressive drop-off)
data = []
users_at_stage = 100000
for i, stage in enumerate(funnel_stages):
    # Progressively lower retention
    drop_off_rate = 0.15 + (i * 0.05)  # Increasing drop-off
    users_at_stage = int(users_at_stage * (1 - drop_off_rate))

    for _ in range(users_at_stage):
        data.append({
            'user_id': f'user_{np.random.randint(0, 1000000)}',
            'stage': stage,
            'timestamp': np.random.randint(0, 365),
        })

df = pd.DataFrame(data)

# 1. Funnel Counts
funnel_counts = df['stage'].value_counts().reindex(funnel_stages)
print("Funnel Counts by Stage:")
print(funnel_counts)

# 2. Funnel Metrics
funnel_metrics = pd.DataFrame({
    'Stage': funnel_stages,
    'Users': funnel_counts.values,
})

funnel_metrics['Drop-off'] = funnel_metrics['Users'].shift(1) - funnel_metrics['Users']
funnel_metrics['Drop-off %'] = (funnel_metrics['Drop-off'] / funnel_metrics['Users'].shift(1) * 100).round(2)
funnel_metrics['Conversion %'] = (funnel_metrics['Users'] / funnel_metrics['Users'].iloc[0] * 100).round(2)

print("\nFunnel Metrics:")
print(funnel_metrics)

# 3. Visualization - Funnel Chart
fig, axes = plt.subplots(1, 2, figsize=(14, 6))

# Traditional funnel visualization
ax = axes[0]
colors = plt.cm.RdYlGn_r(np.linspace(0.3, 0.7, len(funnel_metrics)))

for idx, (stage, users) in enumerate(zip(funnel_metrics['Stage'], funnel_metrics['Users'])):
    # Create trapezoid-like bars
    width = users / funnel_metrics['Users'].max()
    y_pos = len(funnel_metrics) - idx - 1
    ax.barh(y_pos, width, left=(1 - width) / 2, height=0.6, color=colors[idx], edgecolor='black')
    ax.text(-0.05, y_pos, stage, ha='right', va='center', fontsize=10)
    ax.text(0.5, y_pos, f"{users:,}", ha='center', va='center', fontsize=9, fontweight='bold')

ax.set_xlim(0, 1)
ax.set_ylim(-0.5, len(funnel_metrics) - 0.5)
ax.set_xticks([])
ax.set_yticks([])
ax.set_title('Conversion Funnel')

# Step-by-step conversion
ax2 = axes[1]
x_pos = np.arange(len(funnel_stages))
colors2 = plt.cm.Spectral(np.linspace(0, 1, len(funnel_stages)))

bars = ax2.bar(x_pos, funnel_metrics['Users'], color=colors2, edgecolor='black', alpha=0.7)

# Add value labels
for i, (bar, users, conv) in enumerate(zip(bars, funnel_metrics['Users'], funnel_metrics['Conversion %'])):
    height = bar.get_height()
    ax2.text(bar.get_x() + bar.get_width() / 2., height,
             f'{int(users):,}\n({conv:.1f}%)',
             ha='center', va='bottom', fontsize=9)

ax2.set_ylabel('User Count')
ax2.set_title('Users by Stage')
ax2.set_xticks(x_pos)
ax2.set_xticklabels(funnel_stages, rotation=45, ha='right')
ax2.grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.show()

# 4. Drop-off Analysis
fig, ax = plt.subplots(figsize=(12, 6))

# Filter out first stage (no drop-off from before)
drop_off_data = funnel_metrics[1:].copy()
drop_off_data = drop_off_data[drop_off_data['Drop-off'] > 0]

colors_drop = ['#d62728' if x > drop_off_data['Drop-off'].median() else '#2ca02c'
               for x in drop_off_data['Drop-off']]

bars = ax.barh(drop_off_data['Stage'], drop_off_data['Drop-off %'], color=colors_drop, edgecolor='black')

# Add value labels
for i, (bar, drop_pct) in enumerate(zip(bars, drop_off_data['Drop-off %'])):
    width = bar.get_width()
    ax.text(width, bar.get_y() + bar.get_height() / 2.,
            f'{drop_pct:.1f}%',
            ha='left', va='center', fontsize=10, fontweight='bold')

ax.set_xlabel('Drop-off Rate (%)')
ax.set_title('Drop-off Rates by Stage')
ax.grid(True, alpha=0.3, axis='x')

plt.tight_layout()
plt.show()

# 5. Funnel Efficiency Matrix
efficiency_matrix = funnel_metrics[['Stage', 'Conversion %']].copy()
print("\nFunnel Efficiency (% of Initial Users):")
print(efficiency_matrix)

# 6. Stage-to-stage conversion
fig, ax = plt.subplots(figsize=(12, 6))

stage_conversion = []
for i in range(len(funnel_metrics) - 1):
    conversion = (funnel_metrics.iloc[i + 1]['Users'] / funnel_metrics.iloc[i]['Users'] * 100)
    stage_conversion.append({
        'Transition': f"{funnel_metrics.iloc[i]['Stage']}\n→ {funnel_metrics.iloc[i+1]['Stage']}",
        'Conversion %': conversion
    })

stage_conv_df = pd.DataFrame(stage_conversion)
colors_stage = ['#2ca02c' if x > 80 else '#ff7f0e' if x > 60 else '#d62728'
                for x in stage_conv_df['Conversion %']]

bars = ax.bar(range(len(stage_conv_df)), stage_conv_df['Conversion %'], color=colors_stage, edgecolor='black')

# Add value labels
for bar, conv in zip(bars, stage_conv_df['Conversion %']):
    height = bar.get_height()
    ax.text(bar.get_x() + bar.get_width() / 2., height,
            f'{conv:.1f}%',
            ha='center', va='bottom', fontsize=10, fontweight='bold')

ax.set_ylabel('Conversion Rate (%)')
ax.set_title('Stage-to-Stage Conversion Rates')
ax.set_xticks(range(len(stage_conv_df)))
ax.set_xticklabels(stage_conv_df['Transition'], fontsize=9)
ax.set_ylim([0, 105])
ax.axhline(y=80, color='green', linestyle='--', alpha=0.5, label='Good (80%+)')
ax.axhline(y=60, color='orange', linestyle='--', alpha=0.5, label='Acceptable (60%+)')
ax.legend()
ax.grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.show()

# 7. Funnel by Segment (e.g., traffic source)
np.random.seed(42)
df['traffic_source'] = np.random.choice(['Organic', 'Paid', 'Direct'], len(df))

# Create funnel for each segment
fig, axes = plt.subplots(1, 3, figsize=(15, 6))

for idx, source in enumerate(['Organic', 'Paid', 'Direct']):
    df_segment = df[df['traffic_source'] == source]
    segment_counts = df_segment['stage'].value_counts().reindex(funnel_stages)

    segment_metrics = pd.DataFrame({
        'Stage': funnel_stages,
        'Users': segment_counts.values,
    })
    segment_metrics['Conversion %'] = (segment_metrics['Users'] / segment_metrics['Users'].iloc[0] * 100).round(2)

    ax = axes[idx]
    x_pos = np.arange(len(funnel_stages))
    bars = ax.bar(x_pos, segment_metrics['Users'], color='steelblue', edgecolor='black', alpha=0.7)

    for bar, conv in zip(bars, segment_metrics['Conversion %']):
        height = bar.get_height()
        ax.text(bar.get_x() + bar.get_width() / 2., height,
                f'{conv:.1f}%',
                ha='center', va='bottom', fontsize=8)

    ax.set_title(f'Funnel: {source}')
    ax.set_ylabel('Users')
    ax.set_xticks(x_pos)
    ax.set_xticklabels(funnel_stages, rotation=45, ha='right', fontsize=8)
    ax.grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.show()

# 8. Comparison table of segments
print("\nFunnel Comparison by Traffic Source:")
comparison_data = []
for source in ['Organic', 'Paid', 'Direct']:
    df_segment = df[df['traffic_source'] == source]
    segment_counts = df_segment['stage'].value_counts().reindex(funnel_stages)
    comparison_data.append({
        'Traffic Source': source,
        'Landing': segment_counts.iloc[0],
        'Sign Up': segment_counts.iloc[1],
        'Product': segment_counts.iloc[2],
        'Cart': segment_counts.iloc[3],
        'Final Conv %': (segment_counts.iloc[-1] / segment_counts.iloc[0] * 100),
    })

comparison_df = pd.DataFrame(comparison_data)
print(comparison_df.round(2))

# 9. Sankey diagram representation (text-based)
print("\nFunnel Flow Summary:")
print("="*60)
for i in range(len(funnel_metrics) - 1):
    current = funnel_metrics.iloc[i]
    next_stage = funnel_metrics.iloc[i + 1]
    drop = current['Users'] - next_stage['Users']
    conv_pct = (next_stage['Users'] / current['Users'] * 100)

    print(f"{current['Stage']}")
    print(f"  ├─ Continue: {next_stage['Users']:>7,} ({conv_pct:>5.1f}%)")
    print(f"  └─ Drop-off: {drop:>7,} ({100-conv_pct:>5.1f}%)")
print(f"\n{funnel_metrics.iloc[-1]['Stage']}")
print("  └─ Completed: {0:,}".format(int(funnel_metrics.iloc[-1]['Users'])))

# 10. Key insights visualization
fig, ax = plt.subplots(figsize=(10, 6))
ax.axis('off')

insights = f"""
FUNNEL ANALYSIS SUMMARY

Total Users: {int(funnel_metrics['Users'].iloc[0]):,}
Conversions: {int(funnel_metrics['Users'].iloc[-1]):,}
Overall Conversion Rate: {funnel_metrics['Conversion %'].iloc[-1]:.2f}%

BOTTLENECKS (Highest Drop-off):
1. {funnel_metrics[funnel_metrics['Drop-off %'].idxmax()]['Stage']} - {funnel_metrics['Drop-off %'].max():.1f}%
2. {funnel_metrics[funnel_metrics['Drop-off %'].nlargest(2).index[1]]['Stage']}

BEST PERFORMERS (Highest Conversion):
1. {stage_conv_df.nlargest(2, 'Conversion %').iloc[0]['Transition'].split(chr(10))[1][2:]} - {stage_conv_df['Conversion %'].nlargest(2).iloc[0]:.1f}%
2. {stage_conv_df.nlargest(2, 'Conversion %').iloc[1]['Transition'].split(chr(10))[1][2:]} - {stage_conv_df['Conversion %'].nlargest(2).iloc[1]:.1f}%

RECOMMENDATIONS:
• Focus optimization on highest drop-off stages
• Benchmark against industry standards
• A/​B test improvements at each stage
• Monitor segment performance separately
"""

ax.text(0.05, 0.95, insights, transform=ax.transAxes, fontfamily='monospace',
        fontsize=11, verticalalignment='top', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))

plt.tight_layout()
plt.show()

Funnel Analysis Steps

  1. Define all stages in customer journey
  2. Count users at each stage
  3. Calculate drop-off and conversion rates
  4. Identify biggest bottlenecks
  5. Analyze by segments (traffic source, device, etc.)
  6. Benchmark against goals
  7. Prioritize optimization efforts

Common Drop-off Points

  • Complex signup forms
  • Unexpected fees
  • Confusing navigation
  • Payment issues
  • Technical errors

Deliverables

  • Funnel visualization chart
  • Drop-off analysis table
  • Stage-to-stage conversion rates
  • Segmented funnel analysis
  • Bottleneck identification
  • Actionable optimization recommendations
  • Benchmark comparison report

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View