BlogAnalytics

Reading a split funnel

The funnel chart tells you how many got through. The split table under it tells you who. Here is a row by row reading of one, from a study app's mock month.

The table under the chart

Turn on "Split by" in a Vevee funnel and the chart gets a table underneath, one row per value of the field you picked. The example below is a study app's visit funnel (pageview, login page, signup) split by channel over a mock month. Every number in this post is mock data.

Visit to signup · Split by channel · Visits · last 30 days (mock data)

channel          $pageview   login_page_viewed   signup_completed   overall
paid                 380          61 · 16%            25 · 41%        7% (25 of 380)
organic_search       210          38 · 18%            17 · 45%        8% (17 of 210)
social               150          21 · 14%             8 · 38%        5% (8 of 150)
ai                   127          40 · 31%            24 · 60%       19% (24 of 127)
direct               120          19 · 16%             9 · 47%        8% (9 of 120)
referral              50           9 · 18%             4 · 44%        8% (4 of 50)
email                 33           8 · 24%             5 · 63%       15% (5 of 33)

One cell, two numbers

Each later step shows a count and a rate together, like "61 · 16%". The rate is step to step: of the 380 paid visits that had a pageview, 61 reached the login page. Hover the cell and it says "61 of 380". The overall column divides the last step by the first, so it answers the question you usually came with: what share of this channel's visits ended in a signup. The header says Visits. That word matters. A visit split counts visits, a person split counts people, and a split by an event property counts entries. Whatever the unit, the chart above the table switches to it, and with no row selected the chart is the sum of the rows. Click a row and the chart redraws for that row alone. Click it again, or press Clear, to go back.

Ten rows, then Other

Channel has seven values, so every one gets a row. Split the same funnel by utm_campaign and there are many more, most of them tiny. The table shows the ten values with the most entries at step 1 and folds the rest into one Other row; "Show all" expands it.

Visit to signup · Split by utm_campaign · Visits (mock data, trimmed)

utm_campaign       $pageview   ...   overall
(none)                 541           8% (45 of 541)
oct-pricing            240           7% (16 of 240)
oct-flashcards          98           6% (6 of 98)
exam-week               52          10% (5 of 52)
newsletter-oct          33          15% (5 of 33)
creator-collab          29          10% (3 of 29)
retarget-oct            24          13% (3 of 24)
uni-groups              18          11% (2 of 18)     greyed
spring-promo            11           9% (1 of 11)     greyed
blog-cards               9          22% (2 of 9)      greyed
test                     6          50% (3 of 6)      greyed
Other                    9          11% (1 of 9)

The row with no value

(none) is the top row here, and it is not a mistake: those are visits that arrived without a campaign tag, which is most organic, direct and AI traffic. Missing values always get a row of their own and are never folded into Other, because "how much of my traffic is untagged" is a real question. On a person split by a first_* property the same row is called "(no first touch)", and it starts large: it holds everyone who signed up before the app shipped attribution. It shrinks as new signups arrive. There is a separate case under the table. A visit whose events all lack visit fields, for example one made only of server events, cannot be placed in any row. It is left out of the split, never pushed into direct, and the table says how many, for example "3 visits without visit data not shown."

Grey rows

Rows with fewer than 20 entries at step 1 are greyed out. They keep their numbers, so nothing is hidden; the grey is a warning that the rate is mostly luck. The test campaign above converts at 50% on six visits. Three signups from a link someone shared in a group chat say nothing about the campaign. Sorting respects this. Every column header sorts, and on a step the name sorts by count while the % beside it sorts by rate. Sort by a rate and greyed rows drop below every row that is not grey, so the top of the list is the best rate you can trust. Sort by a count and they stay in place.

Matching Traffic, day for day

The first thing the app did with its visit split was compare it with the Traffic page for the same range. They matched row by row, and that is by design. A visit's channel and other fields come from the earliest event of the visit that carries visit fields, the same rule Traffic uses, so a later event sent without them cannot move a visit to another channel. And both count days in the app's time zone, set under Settings. With the time zone left at UTC, an evening visit in Rome lands on tomorrow in both places, consistently wrong; set it and both are right. The "Open in Traffic" link in the table header takes you there with the same date range, filtered to the selected row when there is one. It only navigates. The two pages never share data beyond the filter in the URL. Two cautions. A visit only converts within its own app day, because the visit hash rotates at local midnight, so a signup the next morning belongs to a new visit; the table says so underneath. And unsplit funnels still use older range handling, so near midnight the same funnel with and without a split can differ by a few.

Share the exact view

The view lives in the URL, so a link reproduces the split, the selected row and the sort. To send someone the campaign table, sorted by signup rate, with the Other row selected:

?split=visit:utm_campaign&row=$other&sort=r2:desc

split=visit:channel | person:first_channel | event:<property> | none
row=<value>         $none is the missing row, $other is Other
sort=<col>:<dir>    value, s0 s1 s2 (counts), r1 r2 (rates), overall
all=1               show every value instead of top 10 plus Other

Then read the other half

The visit split stops at signup. To see which channels bring people who pay, open the person funnel split by first_channel, which counts people and starts at signed_up. The two tables answer different questions and are never joined into one; the funnel splits section of the traffic attribution guide (/docs/guides/traffic-attribution) explains why.

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