For the complete documentation index, see llms.txt. This page is also available as Markdown.

Track a signup funnel

A full signup funnel — pageview, CTA click, form view, signup, activation — with drop-off queries.

A signup funnel is the canonical "did this work?" question. We'll instrument five steps:

$pageview (landing)  →  clicked_cta  →  viewed_signup_form  →  signup  →  activated

…then query the conversion rate of each step and break it down by traffic source.

Step 1 — instrument the funnel

Landing page (auto)

The browser SDK already fires $pageview on load. Nothing to do.

CTA click

import { track } from "@millimetric/track";

export function HeroCTA() {
  return (
    <button
      onClick={() => track("clicked_cta", { location: "hero", label: "Start free" })}
    >
      Start free
    </button>
  );
}

Form view (when the signup form renders)

Signup itself

Send from the server so failed clientside submits don't pollute the funnel. Tie it back to the visitor with the anonymous_id they were carrying.

The browser sends anonymous_id along with the signup body — read it from your auth state or the SDK directly:

Activation

"Activated" is product-specific — the moment a user does the thing your product is for. For Acme Notes, it's "created their first note that has at least 10 characters".

Step 2 — verify in the dashboard

Quick smoke test before you query at scale:

You should see clicked_cta events with properties containing location: "hero".

Step 3 — funnel drop-off via /v1/stats

A simple count per step:

Conversion rates: 24% (CTA), 79% (form view), 35% (signup), 73% (activation). End-to-end: 4.7%.

Step 4 — the proper funnel query (ClickHouse)

The right way is a single window function over events, computing first-time-each-step per user:

The s_n >= s_{n-1} predicates enforce ordering (a user who signed up before they viewed the form doesn't count as a valid funnel — they came back through a deep link).

Step 5 — break down by source

Where are the highest-converting visitors coming from?

You'll see Facebook paid on a different row than Facebook social — that's the classifier doing its job.

For per-session attribution (better for revenue), query the sessions view directly. See Marketing attribution dashboards.

Common pitfalls

  • Tracking on the click handler and in useEffect — you'll double-count. Pick one, usually the click handler.

  • Not threading anonymous_id to the server — your signup event lands without it, and the funnel breaks at step 4. Pass it through your auth body.

  • Tracking activation on a re-render — gate it with isFirstNote. Otherwise the metric is "users who edited a note", which isn't the same.

  • Forgetting to call /v1/identify — your post-signup events keep user_id = NULL and you lose per-user retention. Call it once on signup.

See also

Last updated

Was this helpful?