BlogAnalytics

Your funnel has one broken step. Find it without writing a single SQL query.

A hundred people saw your paywall this week. Three upgraded. Is that a copy problem, a price problem, or did ninety of them never generate anything worth paying for? You cannot fix what you cannot locate.

Flat revenue is a location problem

When conversion is bad, the instinct is to redesign the paywall - because the paywall is the step you can see. But "3% of paywall viewers upgrade" is the last number in a chain: how many signups activated, how many activated users used the core feature, how many heavy users ever saw the paywall at all. The broken step is usually upstream of the one you keep redesigning, and the only way to know is a funnel over real events. Most indie teams skip this because it smells like a data-engineering project. It is four capture calls.

Instrument the four moments that matter

Vevee’s analytics surface rides the same SDK and keys as your metering - capture is one call, browser-safe with a public key. Resist the urge to track everything; a funnel needs its steps, not a firehose. Reserved event names like paywall_shown and checkout_completed get special dashboard treatment (preset funnels, property dropdowns, typo hints), and your custom names flow through the identical pipeline.

// The minimum viable funnel - four moments
await vevee.analytics.capture({ distinctId: userId, event: 'signup_completed' });

await vevee.analytics.capture({ distinctId: userId, event: 'onboarding_step',
  properties: { step: 'first_generation' } });

await vevee.analytics.capture({ distinctId: userId, event: 'paywall_shown',
  properties: { trigger: 'limit_reached' } });

await vevee.analytics.capture({ distinctId: userId, event: 'checkout_completed',
  properties: { plan: 'pro' } });

The step you don’t have to instrument

The most important funnel step in an AI app is "user actually used the AI" - and you are already tracking it, as metering events. Feature mappings bridge the two surfaces: map event_type LIKE image_generation% to a feature slug in the dashboard, and funnels can use "used the image generator" as a step derived from metering data. No duplicate capture() calls sprinkled through code paths that already call track(). Your funnel mixes behavioral moments (saw the paywall) with consumption truth (generated 10 images) and both come from calls you had already written.

Reading the cliff

Build the funnel in the dashboard - signup, first generation, paywall, checkout - and the broken step announces itself as the biggest drop. The diagnosis differs per cliff. Signup-to-first-generation cliff: onboarding problem, nobody reaches value. First-generation-to-paywall cliff: engagement problem - users try it once and leave, or your limits are so generous nobody ever meets the wall. Paywall-to-checkout cliff: now, and only now, is it actually the pitch or the price. Each diagnosis has a completely different fix, which is exactly why redesigning the paywall on a hunch fails two times out of three.

Close the loop with the fix

The funnel also grades your repair work. Shipped a personalized upgrade nudge? Add upgrade_nudge_shown as a step and compare its cohort’s checkout rate against paywall-only users. Loosened the free tier? Watch whether more users reach the paywall step at all. Because metering and analytics share one user id and one dashboard, "did the pricing change move conversion" stops being a quarterly debate and becomes a chart you check on Friday. Locate, fix, verify - all three from the same four events you wired in an afternoon.

See your own numbers in two minutes.Add the SDK and your users, costs and revenue fill in on the next request.
Join waitlist

Keep reading

ShareCopy a link to this post.

Set your first limit in about five minutes.

50k operations free every month. No card required.
Join waitlist