Skip to content

Funnel & Conversion Analysis -- Complete Drop-Off Optimization Guide

DodaTech Updated 2026-06-23 8 min read

In this tutorial, you'll learn about Funnel & Conversion Analysis. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Funnel analysis tracks users through sequential steps toward a defined goal, revealing exactly where and why they drop off so teams can optimize conversion rates with precision rather than guesswork.

What You'll Learn

In this tutorial, you will learn how to build multi-step funnel queries in SQL, visualize funnel conversion with Python and plotly, apply statistical tests to identify significant drop-off points, segment funnels by user attributes, and implement optimization strategies backed by data.

Why It Matters

Every percentage point of drop-off in a conversion funnel represents lost revenue. A 1% improvement in checkout conversion for an e-commerce platform doing $5M monthly revenue adds $50K per month. Funnel analysis pinpoints exactly where that optimization should focus. Without it, teams waste resources optimizing steps that are already performing well while ignoring the real problems.

Real-World Use

Durga Antivirus Pro identified a 52% drop-off between "scan initiated" and "scan completed" in their funnel analysis. Investigation revealed that full system scans took 35 minutes on average, causing users to minimize or close the application. The team added a quick scan option completing in 2.5 minutes, which reduced the drop-off to 16% and increased weekly active users by 34%.

Funnel Architecture

flowchart TD
    A[All Visitors: 100%] --> B[Landing Page]
    B --> C[Product Page: 38%]
    C --> D[Add to Cart: 21%]
    D --> E[Checkout Start: 15%]
    E --> F[Payment Info: 10%]
    F --> G[Order Complete: 7%]

    B -.->|Drop: 62%| B1[Exit: No Interest]
    C -.->|Drop: 17%| C1[Exit: Price Concerns]
    D -.->|Drop: 6%| D1[Exit: Abandoned Cart]
    E -.->|Drop: 5%| E1[Exit: Form Friction]
    F -.->|Drop: 3%| F1[Exit: Payment Error]

SQL Funnel with Window Functions

Build a complete funnel using SQL window functions for efficiency:

WITH user_funnel AS (
  SELECT
    user_id,
    session_id,
    MAX(CASE WHEN event_name = 'page_view' AND page_path = '/' THEN 1 ELSE 0 END) AS land_home,
    MAX(CASE WHEN event_name = 'page_view' AND page_path = '/pricing' THEN 1 ELSE 0 END) AS view_pricing,
    MAX(CASE WHEN event_name = 'click' AND element_id = 'start_free_trial' THEN 1 ELSE 0 END) AS click_trial,
    MAX(CASE WHEN event_name = 'form_submit' AND form_id = 'signup' THEN 1 ELSE 0 END) AS submit_signup,
    MAX(CASE WHEN event_name = 'page_view' AND page_path LIKE '%/dashboard%' THEN 1 ELSE 0 END) AS reach_dashboard
  FROM web_events
  WHERE event_date >= CURRENT_DATE - INTERVAL '30 days'
  GROUP BY user_id, session_id
),

funnel_summary AS (
  SELECT
    '1. Homepage' AS step_name,
    COUNT(*) AS user_count,
    100.0 AS pct_from_start
  FROM user_funnel WHERE land_home = 1

  UNION ALL

  SELECT
    '2. Pricing Page',
    COUNT(*),
    ROUND(COUNT(*) * 100.0 / MAX((SELECT COUNT(*) FROM user_funnel WHERE land_home = 1)), 1)
  FROM user_funnel WHERE view_pricing = 1

  UNION ALL

  SELECT
    '3. Click Trial',
    COUNT(*),
    ROUND(COUNT(*) * 100.0 / MAX((SELECT COUNT(*) FROM user_funnel WHERE land_home = 1)), 1)
  FROM user_funnel WHERE click_trial = 1

  UNION ALL

  SELECT
    '4. Submit Signup',
    COUNT(*),
    ROUND(COUNT(*) * 100.0 / MAX((SELECT COUNT(*) FROM user_funnel WHERE land_home = 1)), 1)
  FROM user_funnel WHERE submit_signup = 1

  UNION ALL

  SELECT
    '5. Reach Dashboard',
    COUNT(*),
    ROUND(COUNT(*) * 100.0 / MAX((SELECT COUNT(*) FROM user_funnel WHERE land_home = 1)), 1)
  FROM user_funnel WHERE reach_dashboard = 1
)

SELECT * FROM funnel_summary ORDER BY user_count DESC;

Expected output: A five-row funnel showing sequential user counts from homepage through dashboard. Step-to-step conversion rates reveal where users struggle. A healthy free-trial funnel maintains 25-40% conversion from homepage to signup, with 60-70% of signups reaching the dashboard.

Python Funnel Visualization

Create an interactive funnel chart with plotly:

import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots

def create_funnel_chart(steps_df, value_col="users", label_col="step",
                        title="Conversion Funnel Analysis"):
    fig = make_subplots(
        rows=1, cols=2,
        column_widths=[0.6, 0.4],
        specs=[[{"type": "funnel"}, {"type": "bar"}]],
        subplot_titles=("Funnel Visualization", "Step Conversion Rate"),
    )

    fig.add_trace(
        go.Funnel(
            name="Users",
            y=steps_df[label_col],
            x=steps_df[value_col],
            textinfo="value+percent initial",
            textposition="inside",
            marker={"color": steps_df["color"] if "color" in steps_df.columns
                    else ["#2563eb", "#3b82f6", "#60a5fa", "#93c5fd", "#bfdbfe"]},
            connector={"line": {"color": "#e2e8f0", "width": 1}},
        ),
        row=1, col=1,
    )

    steps_df["step_rate"] = steps_df[value_col] / steps_df[value_col].iloc[0] * 100
    steps_df["step_change"] = steps_df["step_rate"].diff().fillna(0)

    fig.add_trace(
        go.Bar(
            x=steps_df["step_rate"],
            y=steps_df[label_col],
            orientation="h",
            marker_color=steps_df["step_change"].apply(
                lambda x: "#22c55e" if x >= 0 else "#ef4444"
            ),
            text=steps_df["step_rate"].round(1).astype(str) + "%",
            textposition="outside",
            name="Conversion %",
        ),
        row=1, col=2,
    )

    fig.update_layout(height=500, showlegend=False, title=title)
    return fig

funnel_data = pd.DataFrame({
    "step": ["Landing Page", "Pricing Page", "Click Trial",
             "Submit Signup", "Reach Dashboard"],
    "users": [52340, 19889, 10939, 6126, 4288],
})

fig = create_funnel_chart(funnel_data)
fig.show()

Expected output: A funnel chart showing 52,340 visitors dropping to 4,288 dashboard reaches. The side bar chart shows each step's percentage relative to the initial step, with step-to-step drops colored in red and gains in green.

Statistical Drop-Off Testing

Determine whether funnel drop-offs are statistically significant:

import numpy as np
from scipy.stats import chi2_contingency

def analyze_funnel_drop_offs(steps_with_counts):
    results = []
    for i in range(1, len(steps_with_counts)):
        prev_users = steps_with_counts[i-1]["users"]
        curr_users = steps_with_counts[i]["users"]
        dropped = prev_users - curr_users

        contingency = np.array([
            [curr_users, dropped],
            [prev_users // 2, prev_users // 2],
        ])
        chi2, p_value, _, _ = chi2_contingency(contingency)

        drop_pct = round(dropped / prev_users * 100, 1)
        results.append({
            "from_step": steps_with_counts[i-1]["name"],
            "to_step": steps_with_counts[i]["name"],
            "previous_users": prev_users,
            "current_users": curr_users,
            "drop_off_pct": drop_pct,
            "p_value": round(p_value, 4),
            "significant": p_value < 0.05,
            "recommendation": "Investigate urgently" if (drop_pct > 40 and p_value < 0.05)
                              else "Monitor" if p_value < 0.05
                              else "No action needed",
        })
    return results

funnel_steps = [
    {"name": "Landing Page", "users": 52340},
    {"name": "Pricing Page", "users": 19889},
    {"name": "Click Trial", "users": 10939},
    {"name": "Submit Signup", "users": 6126},
    {"name": "Reach Dashboard", "users": 4288},
]

analysis = analyze_funnel_drop_offs(funnel_steps)
for R in analysis:
    print(f"{R['from_step']} -> {R['to_step']}: {R['drop_off_pct']}% drop | "
          f"p={R['p_value']} | {'SIGNIFICANT' if R['significant'] else 'NOT SIGNIFICANT'} | {R['recommendation']}")

Expected output: Each step transition shows the drop-off percentage and a significance test result. Steps with large drops and p < 0.05 are candidates for immediate optimization. Non-significant drops (p >= 0.05) may be random variation or require more data.

Segmented Funnel Analysis

Segment funnels by user attribute to uncover hidden patterns:

WITH funnel AS (
  SELECT
    user_id,
    MAX(CASE WHEN event_name = 'landing' THEN 1 ELSE 0 END) AS step_1,
    MAX(CASE WHEN event_name = 'signup_start' THEN 1 ELSE 0 END) AS step_2,
    MAX(CASE WHEN event_name = 'signup_complete' THEN 1 ELSE 0 END) AS step_3
  FROM events
  GROUP BY user_id
)

SELECT
  u.acquisition_channel,
  u.device_type,
  COUNT(*) AS total_users,
  SUM(f.step_1) AS landing,
  SUM(f.step_2) AS signup_start,
  SUM(f.step_3) AS signup_complete,
  ROUND(SUM(f.step_3) * 100.0 / NULLIF(SUM(f.step_1), 0), 1) AS overall_conversion
FROM users u
LEFT JOIN funnel f ON u.user_id = f.user_id
GROUP BY u.acquisition_channel, u.device_type
ORDER BY overall_conversion DESC;

Expected output: A segmented funnel table showing that mobile users from paid search may have 12% overall conversion while desktop users from organic have 31%. This reveals that optimization should target the mobile paid-search experience first, not the overall funnel.

Tool Comparison

Feature Amplitude Mixpanel PostHog Custom SQL
Funnel visualization Built-in Built-in Built-in + viz library
Step segmentation Yes Yes Yes SQL GROUP BY
Statistical testing No No No Python scipy
Time-to-convert Yes Yes Yes SQL date diff
Realtime funnels Yes Yes Yes Polling
Anomaly detection Yes Yes No Custom
Data source SDK events SDK events SDK events Any source

Common Errors

1. Counting Users Multiple Times Per Funnel

If a user visits the pricing page on Monday and again on Friday, counting both visits inflates step counts. Define funnel scope as first attempt per session or first attempt per user lifetime, and apply consistently.

2. No Time Boundaries Between Steps

A funnel that allows unlimited time between steps counts users who complete step 1 in January and step 5 in July as conversions. Set a maximum time window per step (24 hours for activation, 7 days for purchase consideration).

3. Funnel Steps Too Granular

A 15-step funnel overwhelms analysts and dilutes focus. Group related steps: combine "email entered," "password created," and "profile filled" into a single "registration completed" step. Aim for 4-7 steps maximum.

4. Not Segmenting Before Interpreting Results

An overall funnel showing 30% completion may hide segments with 60% and 5% completion. Always segment by traffic source, device type, user tier, and browser to identify where specific user groups struggle most.

5. Confusing Correlation with Causation

A drop-off coinciding with a page redesign does not prove the redesign caused it. Run A/B tests or use interrupted time-series analysis to isolate causal effects. Consider external factors like seasonality, marketing campaigns, and competitor launches.

Practice Questions

1. What is funnel analysis and when should you use it? Funnel analysis tracks user progression through sequential steps toward a defined goal. Use it whenever you have a multi-step conversion Process: user signup, checkout flow, onboarding sequence, or feature activation path.

2. How do you prioritize which drop-off to fix first? Calculate the revenue impact of each drop-off: (users reaching step) x (drop-off rate) x (average revenue per conversion). The step with the highest absolute revenue loss potential should be prioritized, regardless of its percentage drop-off rate.

3. What is the difference between session-based and user-based funnels? Session-based funnels track a single browsing session (suitable for checkout flows). User-based funnels track across multiple sessions (suitable for B2B SaaS purchases that involve research over days or weeks).

4. Why use chi-squared tests for drop-off significance? A chi-squared test compares observed drop-off rates against expected rates under the null hypothesis of no difference. It determines whether the drop is larger than random variation would explain, preventing teams from optimizing noise.

5. Challenge: Build a complete funnel analysis system for a 6-step checkout flow. Use SQL to extract step counts from raw event data, Python to calculate step-by-step conversion with 95% confidence intervals, segment by traffic source and device type, run chi-squared tests to identify significant drop-offs, and produce a ranked list of optimization opportunities by estimated revenue impact.

Mini Project

Build a funnel analysis dashboard for an e-commerce conversion flow. Track 6 steps from product view through purchase confirmation over 90 days. Segment funnels by traffic source (organic, paid, social, email, direct) and device type (mobile, desktop, tablet). Calculate step-by-step conversion rates with 95% confidence intervals using the Wilson score method. Implement chi-squared significance testing for week-over-week drop-off changes. Create an alert system that notifies the team when any funnel step conversion drops more than 10% in a single week. Identify the biggest drop-off segment and propose three specific UX improvements with estimated impact.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro