Conversion Funnel Analysis on Website
Funnel analysis identifies at what stage users leave without completing goal. For e-commerce: view → cart → checkout → payment. For SaaS: signup → onboarding → activation → payment.
GA4 Funnel Setup
// Event markup for each funnel step
// Step 1: Product page view
gtag('event', 'view_item', {
items: [{ item_id: product.id, item_name: product.name, price: product.price }]
});
// Step 2: Add to cart
gtag('event', 'add_to_cart', {
currency: 'RUB',
value: product.price,
items: [{ item_id: product.id, quantity: 1 }]
});
// Step 3: Checkout start
gtag('event', 'begin_checkout', {
currency: 'RUB',
value: cartTotal,
items: cartItems
});
// Step 4: Payment info
gtag('event', 'add_payment_info', {
payment_type: 'card',
value: cartTotal
});
// Step 5: Purchase
gtag('event', 'purchase', {
transaction_id: order.id,
value: order.total,
currency: 'RUB'
});
Create funnel in GA4: Explore → New exploration → Funnel exploration. Add steps, include breakdown by device/segment.
Analysis via BigQuery
-- Conversion at each funnel step
WITH funnel AS (
SELECT
user_pseudo_id,
MAX(CASE WHEN event_name = 'view_item' THEN 1 ELSE 0 END) AS viewed,
MAX(CASE WHEN event_name = 'add_to_cart' THEN 1 ELSE 0 END) AS added,
MAX(CASE WHEN event_name = 'begin_checkout' THEN 1 ELSE 0 END) AS checkout,
MAX(CASE WHEN event_name = 'purchase' THEN 1 ELSE 0 END) AS purchased
FROM `project.analytics.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20240301' AND '20240331'
GROUP BY user_pseudo_id
)
SELECT
COUNT(*) AS total_users,
SUM(viewed) AS viewed,
SUM(added) AS added_to_cart,
SUM(checkout) AS started_checkout,
SUM(purchased) AS purchased,
ROUND(SUM(added) * 100.0 / SUM(viewed), 1) AS view_to_cart_rate,
ROUND(SUM(checkout) * 100.0 / SUM(added), 1) AS cart_to_checkout_rate,
ROUND(SUM(purchased) * 100.0 / SUM(checkout), 1) AS checkout_to_purchase_rate,
ROUND(SUM(purchased) * 100.0 / SUM(viewed), 2) AS overall_cvr
FROM funnel;
Funnel Segmentation
-- Funnel by device
SELECT
device_category,
COUNT(DISTINCT CASE WHEN step >= 1 THEN user_id END) AS step1_users,
COUNT(DISTINCT CASE WHEN step >= 2 THEN user_id END) AS step2_users,
COUNT(DISTINCT CASE WHEN step >= 3 THEN user_id END) AS step3_users,
ROUND(COUNT(DISTINCT CASE WHEN step >= 3 THEN user_id END) * 100.0 /
NULLIF(COUNT(DISTINCT CASE WHEN step >= 1 THEN user_id END), 0), 1) AS cvr
FROM funnel_data
GROUP BY device_category;
Analyzing Drop-off Reasons
After identifying "bottleneck"—investigate why:
Tools:
- Hotjar/Clarity: session recordings of users stuck on step
- Heatmaps: where they click on problem page
- Form Analytics: which fields they abandon
// Track abandonment on checkout form
document.querySelectorAll('#checkout-form input').forEach(field => {
field.addEventListener('blur', () => {
gtag('event', 'checkout_field_blur', {
field_name: field.name,
has_value: field.value.length > 0
});
});
});
// Track page exit without submission
window.addEventListener('beforeunload', () => {
if (document.querySelector('#checkout-form') && !formSubmitted) {
gtag('event', 'checkout_abandonment', {
last_field: lastFocusedField
});
}
});
Funnel Timing Analysis
Time between steps is also informative:
SELECT
user_id,
MIN(CASE WHEN event = 'view_item' THEN timestamp END) AS view_time,
MIN(CASE WHEN event = 'add_to_cart' THEN timestamp END) AS cart_time,
MIN(CASE WHEN event = 'purchase' THEN timestamp END) AS purchase_time,
TIMESTAMP_DIFF(
MIN(CASE WHEN event = 'purchase' THEN timestamp END),
MIN(CASE WHEN event = 'view_item' THEN timestamp END),
MINUTE
) AS time_to_purchase_minutes
FROM events
GROUP BY user_id
HAVING purchase_time IS NOT NULL;
If average view→purchase time = 3 days, need retargeting reminder within these days.
Timeline
Event markup + BigQuery analysis + segmentation + report: 3-5 business days.







