funnel

package
v0.9.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package funnel computes ordered conversion funnels — the headline feature: of the users who did step 1, how many went on to do step 2, then 3, and where do they drop off. The computation is deterministic and storage-agnostic: it works on a slice of events from any store.Store — memory, the single-file log, or the columnar segment tier for scale.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Options added in v0.9.1

type Options struct {
	Order       Order
	Exclusions  []string            // event names that disqualify between step 0 and conversion
	StepFilters []map[string]string // per-step property equals-filters; nil entry = no filter
}

Options extends Compute with the disciplines the incumbents document: ordering mode, exclusion events (a user who fires one between first-match and full conversion is dropped from the funnel entirely), and per-step property filters (step N only matches when the event carries prop=value).

type Order added in v0.9.1

type Order string

Order is the step-matching discipline.

const (
	Ordered   Order = "ordered"   // default: steps in order, other events may interleave
	Strict    Order = "strict"    // steps in order with NO other events between matched steps
	Unordered Order = "unordered" // all steps within the window, any order
)

func ParseOrder added in v0.9.1

func ParseOrder(s string) (Order, error)

ParseOrder maps a request string to a discipline; empty = ordered. Unknown is an error, never silently ordered — a wrong-discipline funnel is a silent-wrong answer.

type Result

type Result struct {
	// the discipline + options this funnel ran under, echoed so every surface
	// (HTTP, MCP, dashboard) emits byte-identical JSON for identical questions
	Order             string       `json:"order"`
	ExcludedEvents    []string     `json:"excluded_events,omitempty"`
	Steps             []StepResult `json:"steps"`
	OverallConversion float64      `json:"overall_conversion"`     // last step / first step
	Converted         int          `json:"converted"`              // users who completed every step
	MedianConvSecs    float64      `json:"median_conversion_secs"` // median time first->last step for converters (0 if none)
}

Result is the full funnel: per-step counts + the overall conversion.

func Compute

func Compute(events []event.Event, steps []Step, window time.Duration) Result

Compute runs the funnel over events. A user counts toward step i only if they did steps[0..i] IN ORDER, each strictly after the previous, and all within `window` of the FIRST step (the conversion window; 0 = no limit). Other events in between are ignored. This matches the standard Mixpanel/Amplitude semantics.

func ComputeOpts added in v0.9.1

func ComputeOpts(events []event.Event, steps []Step, window time.Duration, opts Options) Result

ComputeOpts is Compute with Options. Options{} degrades to exactly Compute's behavior, and Compute delegates here so there is ONE matching engine (the agreement guarantee depends on that).

type SegmentResult added in v0.9.0

type SegmentResult struct {
	Value  string `json:"value"`
	Result        // the funnel for users in this segment
}

SegmentResult is one value of a breakdown property and that segment's full funnel.

func ComputeBreakdown added in v0.9.0

func ComputeBreakdown(events []event.Event, steps []Step, window time.Duration, property string) []SegmentResult

ComputeBreakdown runs the funnel separately for each segment, where a user's segment is the value of `property` on their FIRST step-0 event. This is the correct Mixpanel semantics: a source/plan set at signup carries the user through the whole funnel even if later steps don't repeat the property, unlike filtering events by the property (which would drop steps that never carry it and report a broken conversion). Segments are sorted by step-0 users descending; users who never reach step 0 belong to no segment.

type Step

type Step struct {
	Event string `json:"event"`
}

Step is one stage of the funnel, matched by event name.

type StepResult

type StepResult struct {
	Event              string  `json:"event"`
	Count              int     `json:"count"`                // distinct users who reached this step
	ConversionFromTop  float64 `json:"conversion_from_top"`  // count / step0 count
	ConversionFromPrev float64 `json:"conversion_from_prev"` // count / previous step count
	DroppedFromPrev    int     `json:"dropped_from_prev"`    // previous count - count
}

StepResult is the outcome for one funnel stage.

type UserOutcome added in v0.9.1

type UserOutcome struct {
	DistinctID string `json:"distinct_id"`
	Reached    int    `json:"reached"` // steps completed (1 = step 0 only)
	Converted  bool   `json:"converted"`
}

UserOutcome is one user's funnel result — the Microscope's raw material: the people BEHIND a funnel bar, not just its height.

func Users added in v0.9.1

func Users(events []event.Event, steps []Step, window time.Duration, opts Options) []UserOutcome

Users returns every user's outcome under the same matching engine as ComputeOpts — counts derived from this list always agree with the funnel's bars, because they are the same computation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL