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.

Loading the live Studio…
A funnel, step by step. Live, in your browser.Open in Studio

Funnels & audienceStudio tour · 8 steps

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:

Terminal
squiggle product funnel save "Sign in" \  --step screen:index \  --step screen:stress \  --step action:sign_in \  --step screen:checklist

A 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

Terminal
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 reach

Each 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:

Add a step
  1. 1screen:home
  2. 2screen:cart
  3. 3screen:checkout
  4. 4screen:receipt

5 / 10 sessions converted

  • home10 (100%)—
  • cart7 (70%)med 11s
  • checkout6 (60%)med 10s
  • receipt5 (50%)med 22s
  • #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:

Terminal
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.

Terminal
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.