Funnel Analysis
Track how many users reach each step of a multi-step funnel and compute conversion rates between consecutive steps.
Funnel Analysis is a free Pandas & NumPy Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Pandas & NumPy Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is a Conversion Funnel?
A conversion funnel models a user journey through a sequence of required steps: for example, Homepage → Product Page → Add to Cart → Checkout → Purchase. At each step, some users drop off and never reach the next step. Funnel analysis quantifies these drop-offs so teams can prioritise which step to improve first. The output is a table showing user count and conversion rate at each step.
import pandas as pd
FUNNEL_STEPS = [
'homepage',
'product_page',
'add_to_cart',
'checkout',
'purchase'
]
df = pd.read_csv('clickstream.csv', parse_dates=['timestamp'])
print(df['event_type'].value_counts())Counting Unique Users at Each Step
For each funnel step, count the number of unique users who triggered that event at least once. Use df[df['event_type'] == step]['user_id'].nunique() inside a loop and collect the results into a dictionary. Converting to a Series makes subsequent percentage calculations straightforward with a single division.
step_counts = {}
for step in FUNNEL_STEPS:
users = df[df['event_type'] == step]['user_id'].nunique()
step_counts[step] = users
funnel = pd.Series(step_counts, name='users')
print(funnel)Computing Step-to-Step Conversion Rates
The step-to-step conversion rate shows what fraction of users who completed step N also completed step N+1. Compute it with funnel.shift(1) (which gives the previous step's count) and divide: funnel / funnel.shift(1) * 100. The first step has no prior step, so its rate is NaN or 100 % depending on how you define the baseline.
funnel_df = funnel.to_frame()
funnel_df['prev_users'] = funnel_df['users'].shift(1)
funnel_df['step_conversion_%'] = (funnel_df['users'] / funnel_df['prev_users'] * 100).round(1)
print(funnel_df)Computing Overall Conversion Rate
The overall conversion rate measures what fraction of all users who entered the funnel at step 1 eventually completed the final step. Divide the last step's user count by the first step's count. A 2–5 % overall conversion from homepage to purchase is typical for e-commerce; numbers below this signal a critical drop-off somewhere in the funnel.
overall_rate = funnel.iloc[-1] / funnel.iloc[0] * 100
print(f'Overall conversion rate: {overall_rate:.1f}%')
funnel_df['overall_conversion_%'] = (funnel_df['users'] / funnel_df['users'].iloc[0] * 100).round(1)
print(funnel_df[['users', 'overall_conversion_%']])Ordered Funnel: Requiring Step Sequence
A simple unique-user count treats users who jumped directly to checkout without visiting the product page as valid funnel entries, which inflates conversion at early steps. To enforce ordering, check that each user reached step N only after reaching step N-1. This requires comparing timestamps: the user must have a product_page event before their add_to_cart event.
# Get first occurrence of each step per user
first_events = df.groupby(['user_id', 'event_type'])['timestamp'].min().unstack('event_type')
# Enforce ordering: each step must come after the previous
first_events['valid_to_cart'] = first_events['add_to_cart'] > first_events['product_page']
print(first_events[['product_page', 'add_to_cart', 'valid_to_cart']].head())Funnel by Segment: Device Type
Different user segments may convert at very different rates. Run the same funnel calculation separately for desktop and mobile users using groupby('device_type'). If mobile users drop off heavily at the checkout step, the checkout page likely has a usability issue on small screens. Segmented funnels reveal targeted optimisation opportunities.
def funnel_for_group(group_df):
counts = {}
for step in FUNNEL_STEPS:
counts[step] = group_df[group_df['event_type'] == step]['user_id'].nunique()
return pd.Series(counts)
segmented_funnel = df.groupby('device_type').apply(funnel_for_group)
print(segmented_funnel)Identifying the Biggest Drop-Off Step
The step with the largest absolute user loss is the highest-priority optimisation target. Find it by computing the difference between consecutive step user counts with funnel.diff() — the most negative value corresponds to the biggest drop-off. Surface this insight in both numeric and visual form for stakeholders.
dropoffs = funnel.diff().abs()
biggest_drop = dropoffs.idxmax()
biggest_drop_count = dropoffs.max()
print(f'Biggest drop-off: {biggest_drop} ({biggest_drop_count:.0f} users lost)')Time Between Funnel Steps
The time users take to move from one step to the next reveals friction. If users wait hours between adding to cart and checking out, an abandoned-cart email could recover them. Compute the median time between each pair of steps using the first_events DataFrame by subtracting adjacent timestamp columns and taking the median across all users.
for i in range(1, len(FUNNEL_STEPS)):
prev = FUNNEL_STEPS[i-1]
curr = FUNNEL_STEPS[i]
delta = (first_events[curr] - first_events[prev]).dt.total_seconds() / 60
print(f'{prev} -> {curr}: median {delta.median():.1f} min, 90th pct {delta.quantile(0.9):.1f} min')Weekly Funnel Trend
Track whether conversion rates are improving or degrading week over week by computing the funnel for each week separately. Group the first-event table by week using first_events['homepage'].dt.isocalendar().week and compute the overall conversion rate per week. A sudden drop in a specific week may coincide with a product release or marketing change.
df['week'] = df['timestamp'].dt.isocalendar().week
weekly_conv = []
for week, wdf in df.groupby('week'):
top = wdf[wdf['event_type'] == FUNNEL_STEPS[0]]['user_id'].nunique()
bot = wdf[wdf['event_type'] == FUNNEL_STEPS[-1]]['user_id'].nunique()
weekly_conv.append({'week': week, 'conversion_%': bot/top*100 if top else 0})
print(pd.DataFrame(weekly_conv))Building the Funnel Summary DataFrame
Package all funnel metrics into a clean summary DataFrame that can be exported to a report or fed into a visualisation. Include columns for step name, user count, step-to-step conversion, overall conversion, and users lost. This single DataFrame should be the deliverable from funnel analysis, readable by both engineers and product managers.
summary = pd.DataFrame({
'step': FUNNEL_STEPS,
'users': [step_counts[s] for s in FUNNEL_STEPS]
})
summary['users_lost'] = summary['users'].shift(-1).rsub(summary['users'])
summary['step_conv_%'] = (summary['users'] / summary['users'].shift(1) * 100).round(1)
summary['overall_conv_%'] = (summary['users'] / summary['users'].iloc[0] * 100).round(1)
print(summary)Visualising the Funnel as a Bar Chart
Plot the funnel as a horizontal bar chart where each bar's length represents the user count at that step. A funnel shape emerges naturally when bars are sorted from top (most users) to bottom (fewest). Annotate each bar with the step-to-step conversion percentage so the chart is self-contained and does not require a separate data table to interpret.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 5))
ax.barh(summary['step'][::-1], summary['users'][::-1], color='steelblue')
for i, row in summary[::-1].iterrows():
ax.text(row['users'], i - summary.index[0], f' {row['step_conv_%']}%', va='center')
ax.set_xlabel('Unique Users')
ax.set_title('Conversion Funnel')
plt.tight_layout()
plt.show()Quick Check
Test your understanding of Data Analysis concepts from this lesson.
Lesson Recap
In this lesson you learned: counting unique users at each funnel step, computing step-to-step and overall conversion rates, and segmenting funnels by device type and tracking weekly conversion trends. Next up we explore cohort retention tables to track how many users return week after week.
Frequently asked questions
Is the “Funnel Analysis” lesson free?
Yes — the full text of “Funnel Analysis” is free to read here on the web, and the Pandas & NumPy Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Pandas & NumPy Academy course, upgrade to CoddyKit PRO.
What will I learn in “Funnel Analysis”?
Track how many users reach each step of a multi-step funnel and compute conversion rates between consecutive steps. You practise Pandas & NumPy Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Pandas & NumPy Academy?
No prior experience is required. Pandas & NumPy Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Funnel Analysis” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Pandas & NumPy Academy lesson?
Yes. Every Pandas & NumPy Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.