Skip to main content
GET
Get multi-step conversion funnel
Returns the same funnel data the dashboard renders on the Funnels page. For an ordered list of step specs, you get one row per step with the unique-user count, conversion ratios against step 1 and the previous step, drop-off ratio, and median time-to-convert. Use funnel_type=closed (default) for ordered, in-window conversions (the default that powers the dashboard) or funnel_type=open to count whoever fired step k regardless of order - open mode also returns a dropped_off_users column. Set group_by to a dimension (device, browser, os, location, referrer, ref, builder_codes, or any UTM column) to group each step by per-user attribution; limit controls how many categories are kept (default 5) before bucketing the rest as Others. Attribution defaults to first-touch; pass attribution=last_touch to bucket each user by their latest value instead.
The group_by, limit, and attribution params replace the former breakdown and breakdown_top_n params. Direct callers using ?breakdown= / ?breakdown_top_n= must migrate - there are no aliases.

Defining steps

The steps query parameter is a JSON-encoded array of 2 to 10 step specs. Each step is {type, event, name, filters?: [...]}:
  • type - event type (event for page views, track for custom events, transaction, signature, decoded_log).
  • event - the event name to match.
  • name - a unique step id. Use <event>::<index> (e.g. "connect::1") so the same event re-used at multiple steps can be told apart in the response.
  • filters - optional [{field, op, value}].
    • Operators:
      • eq
      • neq
      • in
      • nin
      • gt
      • lt
      • gte
      • lte
      • startsWith
      • endsWith
      • contains
      • notEmpty / isEmpty - value-less existence checks (the value is ignored; rejected on the numeric event columns volume/revenue/points)
    • Canonical tokens only: the retired long-form spellings (equals, notEquals, notIn, includes, greater, greaterOrEqual, less, lessOrEqual) are rejected with a 400 naming the token.
    • For in / nin, pass the values as a |-separated string in value (e.g. "ethereum|polygon|base").
    • field may target a standard event column or a JSON property on properties.

Example

Authorizations

Authorization
string
header
required

Workspace API key (e.g. formo_xxx). Create one in the Formo dashboard under Team Settings > API.

Query Parameters

date_from
string<date>
required

Inclusive ISO date for the start of the funnel window (YYYY-MM-DD). The events scan extends past date_to by window_seconds so a user who fires step 1 just before date_to can still complete the funnel inside their conversion window.

date_to
string<date>
required

Inclusive ISO date for the end of the start-event window (YYYY-MM-DD).

steps
string
required

JSON-encoded array of 2 to 10 step specs. Each step is {type, event, name, filters?: [{field, op, value}]}. type is the event type (e.g. event for page views, track for custom events, transaction, signature, decoded_log). event is the event name. name is the unique step id (use "<event>::<index>" to disambiguate repeated events).

Filter operators: eq, neq, in, nin, gt, lt, gte, lte, startsWith, endsWith, contains, notEmpty, isEmpty (canonical tokens only; the retired long-form spellings equals/greater/includes/… are rejected, notEmpty/isEmpty are value-less existence checks, rejected on numeric event columns volume/revenue/points). For in/nin, pass the values as a |-separated string in value (e.g. "ethereum|polygon|base").

Standard columns (rendered via direct column access): origin, device, browser, os, location, referrer, direct, ref, utm_source, utm_medium, utm_campaign, utm_content, utm_term, builder_codes, version, locale, timezone, page_path. Anything else is treated as a JSON property and read from properties via JSONExtractString (or JSONExtractFloat for numeric comparators).

window_seconds
integer
default:7200

Conversion window length in seconds. Defaults to 7,200 (2 hours). For closed funnels this is the in-order completion cap; for both variants the events scan is extended by this amount past date_to.

Required range: x >= 1
funnel_type
enum<string>
default:closed

closed (default): ordered, in-window. open: unordered per-step; emits an extra dropped_off_users column.

Available options:
closed,
open
group_by
enum<string>

Optional dimension to break each step down by. Defaults to first-touch attribution; pass attribution=last_touch to bucket by each user's latest value. When set, the response gains a breakdown column.

Available options:
device,
browser,
os,
location,
referrer,
ref,
utm_source,
utm_medium,
utm_campaign,
utm_content,
utm_term,
builder_codes
limit
integer
default:5

Top-N breakdown categories to keep (by user count), used only with group_by. Remaining categories are bucketed as Others. Defaults to 5.

Required range: x >= 1
attribution
enum<string>
default:first_touch

Per-user attribution for the group_by dimension. first_touch (default) buckets each user by their earliest value; last_touch by their latest. Ignored unless group_by is set.

Available options:
first_touch,
last_touch

Response

Per-step funnel results

Analytics endpoint response. The data array contains the rows; the exact row shape depends on the endpoint. meta carries column type information for rendering, rows is the row count, and statistics holds query timing metadata.

data
object[]
meta
object[]
rows
integer
rows_before_limit_at_least
integer
statistics
object