Funnels
For AI agents: this page is Markdown at https://squiggle.sh/docs/product/funnels.md. Every docs page is listed at https://squiggle.sh/llms.txt, and all of them are one file at https://squiggle.sh/llms-full.txt.
A funnel is the list of steps in a journey, such as sign-in or checkout. It shows how many sessions reached each step, where the rest dropped out, and how long each step took.
Build a funnel
A step is a screen or a named action, in order. In Studio, open the Product screen’s Funnels tab and add steps; it suggests the screens and actions your sessions already have. From the terminal:
squiggle product funnel save "Sign in" \ --step screen:index \ --step screen:stress \ --step action:sign_in \ --step screen:checklistA funnel needs at least two steps. A step can accept more than one name, for a journey with two routes through it: --step "screen:login|sso". Action names are the ones you gave defineAction.
Funnels are saved in .squiggle/perf/config.json, so Studio, the terminal and your agent all use the same ones.
Read it
squiggle product funnel run "Sign in" --last 50Sign in 2/50 sessions converted index ████████████████████████████ 20 (100%) med — stress ████░░░░░░░░░░░░░░░░░░░░░░░░ 3 (15%) med 3.5s sign_in ███░░░░░░░░░░░░░░░░░░░░░░░░░ 2 (10%) med 1.4s checklist ███░░░░░░░░░░░░░░░░░░░░░░░░░ 2 (10%) med 51ms share of the first step · median time to reachEach row is how many sessions reached that step, as a share of the first step, and the median time it took to get there from the step before. Add --json to also get the 90th percentile: a step most people finish in four seconds while some take four minutes is a different problem from one everyone finishes in four seconds.
In Studio you can also limit how long a conversion may take. Leave it empty to count a conversion anywhere in the session.
A session reaches a step when it happens after the step before it. Whatever happens in between doesn’t matter, and if a session starts the funnel more than once, its furthest attempt counts. Build a funnel over ten sessions to see which events each one matched:
5 / 10 sessions converted
- #1, convertedhome0sproduct4sadd_to_cart9scart11scheckout20spay41sreceipt42s
- #2, reached 2 stepshome0sproduct3sproduct15sadd_to_cart22scart24shome40s
- #3, convertedhome0scart2scheckout8spay30sreceipt31s
- #4, reached 1 stepsproduct0sadd_to_cart5scart6scheckout14shome1m 0s
- #5, reached 1 stepshome0sproduct6shome12s
- #6, convertedhome0sproduct5sadd_to_cart7scart9scheckout18spay5m 0sreceipt5m 1s
- #7, convertedhome0sproduct2sadd_to_cart4scart5sproduct8sadd_to_cart11scart12scheckout19spay33sreceipt34s
- #8, reached 3 stepscart0shome3sproduct7sadd_to_cart12scart14scheckout25s
- #9, reached 1 stepshome0s
- #10, convertedhome0sproduct8sadd_to_cart13scart15scheckout29spay47sreceipt48s
Compare groups
Split a funnel by any trait you set with identify(), such as plan, experiment variant or app version, to get one funnel per value:
squiggle product funnel listsquiggle product funnel run "Sign in" --segment-by plansquiggle product funnel rm "Sign in"Or split it by something your app was holding, if it sends state samples. You get two funnels: sessions that reached that state, and sessions that sent samples but never did.
squiggle product funnel run "Checkout" --where "zustand:useCart.items#len >= 3"A state is a feature path, a comparison (>=, <=, >, <, =, !=) and a value. A text value, such as an allowed theme, compares only with = or !=. squiggle product state lists the paths your sessions have; see State paths. Sessions that sent no state samples are counted apart and are in neither funnel, because nothing is known about what they held.
Pass either --segment-by or --where, not both. --where works the same way on screens, friction, retention, usage and the other squiggle product reports. Your agent passes it as whereState to product_funnel_eval, product_screens, product_friction and product_retention.