Skip to content

Build and read the funnel

Open http://localhost:3000 → More apps → ouo11y RUM → Funnels, and set the time range (top right) to Last 1 hour.

  1. Step 1 is already Page, is, /. Click its value box: it lists the paths seen in the range, most frequent first.
  2. Step 2: set starts with, type /products/ and pick “Use this value”. Any product page counts.
  3. Add step: Event, add_to_cart. Custom event names are suggested too.
  4. Add step: switch it to Page, is, /checkout.
  5. Add step: Event, order_paid.
  6. Service: tiny-shop-funnels-frontend, then Enter. Other apps sending to the same stack stay out.

The address bar now holds the funnel (...&step=page:/&step=page:/products/*&step=event:add_to_cart&...). Copy it to share the funnel; there are no saved funnels yet.

Five bars reading 46, 38, 29, 21, 11: the generator’s numbers plus your own purchase. If you ran the generator twice, every number is doubled (plus one).

This is the generator’s part of the funnel, without your purchase. Click the hatched drop-offs.

  1. 1Pageis/
    100%45 sessions
  2. 2Pagestarts with/products/
    82.2%37 sessions82.2% of previous stepmedian · p75: a few seconds
  3. 3Eventadd_to_cart
    62.2%28 sessions75.7% of previous stepmedian · p75: a few seconds
  4. 4Pageis/checkout
    44.4%20 sessions71.4% of previous stepmedian · p75: a few seconds
  5. steepest fall
    5Eventorder_paid
    22.2%10 sessions50% of previous stepmedian · p75: a few seconds
Each bar is the sessions that reached the step. Hatching is what the previous step lost.

What Grafana shows under each bar:

Under each bar Meaning Here
big % sessions that reached this step, of those that entered step 1 22.2% paid
n sessions · m users sessions that reached it, and their distinct users 45 sessions entered
% of previous step the step’s own conversion: the lowest is the leak to fix first 50% of checkouts are paid
median · p75 time from the previous step, over the sessions that made it a few seconds each here
hatched −n sessions that reached the previous step and stopped 10 stopped at checkout

A funnel counts sessions. Users are the distinct user.id of those sessions: one user with three sessions counts three times in sessions and once in users. Each generated session is a fresh browser, so here the two numbers are equal.

A long p75 next to an ordinary median means a slow minority. Their replays show why.

  • Deep links do not enter. 5 sessions land on /products/2, buy, and never see /. They are not in this funnel: step 1 is the door. Make a funnel that starts at Page starts with /products/ and they appear.
  • Order matters. 3 sessions add to cart first and visit / afterwards. They count for step 1 only: steps must happen in order within one session. Other events in between do not matter.
  • Repeats do not inflate. Some sessions go home and pick a second product, some add twice. Each step counts once per session, and a session that tries several times is credited with its best attempt.
  • Checkout is the leak. Half the sessions that reach /checkout do not pay: 6 leave the form, 4 have card ...0002 declined.

Completed within sets the maximum time from step 1 to the last step. Set it to 5 minutes: nothing changes, these sessions are short. A step reached after the window does not count.

The Funnels page asks rum-api through Grafana; the plugin proxy adds the read token. rum-api runs one Loki query per kind of step, joins the results per session.id in memory, and walks each session’s events in order.

Grafana
rum-api
Loki
  1. 1 POST /v1/funnels/query · steps, time range, service
  2. 2 page views in range · event_name navigation, url.path
  3. 3 custom events in range · add_to_cart, order_paid
  4. 4 group by session.id · strict step order
  5. 5 count, users, median, p75 per step
  6. 6 GET /v1/funnels/dropped · after a click on −n
Two Loki queries, whatever the number of steps: one for page views, one for custom events.

The same query from the shell, inside the stack’s network. From ~/Desktop/tiny-shop-funnels/stack:

Terminal window
docker compose exec grafana curl -s -X POST http://rum-api:8080/v1/funnels/query \
-H 'Authorization: Bearer rt_dev_0000000000000000' -H 'Content-Type: application/json' \
-d '{"from":"now-1h","filters":{"service":"tiny-shop-funnels-frontend"},"steps":[
{"kind":"page","value":"/"},{"kind":"page","match":"prefix","value":"/products/"},
{"kind":"event","value":"add_to_cart"},{"kind":"page","value":"/checkout"},
{"kind":"event","value":"order_paid"}]}'

It returns the same counts as the bars, as JSON.

  • Only events inside the time range count. A session whose / visit is before the start of the range does not enter, even if it pays inside the range. Widen the range rather than shifting it.
  • A step is a path, not a URL. url.path has no query string or host: /products/2?ref=ad is /products/2.
  • Prefix means prefix. /products (no trailing slash) also matches /products-sale. Use /products/.
  • Sampling scales a funnel down. With session.sampleRate: 0.1 every step shows a tenth. Conversion percentages stay right, counts do not.
  • Events on the way out. The last events of a page are sent when it is hidden (pagehide). A tab killed by the OS can lose them; the generator leaves each page through about:blank.

Next: from a drop-off to the replay.