Copy as markdown[View .md](https://docs.funnelfizz.com/features/splitting "View the raw markdown for this page")[Open in Claude](https://claude.ai/new?q=Read%20https%3A%2F%2Fdocs.funnelfizz.com%2Ffeatures%2Fsplitting.md%20and%20help%20me%20with%20this%20FunnelFizz%20topic%3A%20Splitting "Open this page in Claude with context")[Open in ChatGPT](https://chat.openai.com/?q=Read%20https%3A%2F%2Fdocs.funnelfizz.com%2Ffeatures%2Fsplitting.md%20and%20help%20me%20with%20this%20FunnelFizz%20topic%3A%20Splitting "Open this page in ChatGPT with context")

# Splitting

Splits let you filter a funnel by one (or more) conditions, so you can see conversion rates for specific cohorts instead of the blended whole-funnel average.

For conceptual background, start with [Concepts → Splitting & Extensions](https://docs.funnelfizz.com/concepts/splitting-and-extensions.md). This page is the complete reference for every split condition.

## How splits are evaluated[​](#how-splits-are-evaluated "Direct link to How splits are evaluated")

When you add a split, it becomes a **node on the canvas** between two stages. Everything downstream of the split is filtered. Internally, FunnelFizz translates the split condition into a SQL WHERE clause against the `trackingEvents` or `profileSubscriptions` tables.

Conditions chain with **AND**. If you nest splits, each additional split adds another AND clause — a visitor must match every split in the chain to appear in the deepest branch.

## The eight split conditions[​](#the-eight-split-conditions "Direct link to The eight split conditions")

### Traffic source[​](#traffic-source "Direct link to Traffic source")

**Internal name:** `traffic_source` **Filters on:** `trackingEvents.referrer` (ILIKE pattern match)

**Use case:** "show me only traffic that came from reddit.com."

**Configuration:**

* **Domain** — a substring of the referrer URL. E.g., `reddit.com` matches `https://www.reddit.com/r/saas/...` and `https://old.reddit.com/...`.

**Example value:** `twitter.com`, `news.ycombinator.com`, `producthunt.com`.

### UTM parameter[​](#utm-parameter "Direct link to UTM parameter")

**Internal name:** `utm` **Filters on:** `trackingEvents.utm` (JSONB field)

**Use case:** "show me only traffic from my summer campaign."

**Configuration:**

* **UTM key** — pick one of: `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term`.
* **Value** — exact string match.

**Example value:** `utm_campaign = summer-launch`, `utm_source = newsletter`.

### Channel[​](#channel "Direct link to Channel")

**Internal name:** `channel` **Filters on:** `trackingEvents.channel` (server-side categorization)

**Use case:** "show me only organic search traffic."

**Categories:**

* `direct` — no referrer, no UTM.
* `organic_search` — Google, Bing, DuckDuckGo, Brave, etc.
* `social` — X, LinkedIn, Reddit, TikTok, Instagram, YouTube, Facebook.
* `paid` — `utm_medium` in `cpc`/`paid`/`ads`, or recognized ad networks.
* `email` — `utm_medium = email` or email-client referrers.
* `ai_llm` — chatgpt.com, claude.ai, perplexity.ai, gemini.google.com, copilot.microsoft.com.
* `referral` — everything else with a referrer.

**Configuration:**

* **Channel** — pick one from the list above.

### Device type[​](#device-type "Direct link to Device type")

**Internal name:** `device_type` **Filters on:** `trackingEvents.deviceType` (UA-parsed)

**Use case:** "is my mobile flow converting at a different rate than desktop?"

**Options:** `desktop`, `mobile`, `tablet`.

### Country[​](#country "Direct link to Country")

**Internal name:** `geography` **Filters on:** `trackingEvents.country` (ISO 3166-1 alpha-2, from MaxMind GeoIP)

**Use case:** "only show me US + Canadian traffic."

**Configuration:**

* **Country** — pick from a 249-country dropdown.

**Note:** we don't currently support *multi*-country splits as a single branch. For "US + CA," use two splits stacked together, or filter in the dashboard exports.

### Custom event[​](#custom-event "Direct link to Custom event")

**Internal name:** `custom_event` **Filters on:** `trackingEvents.props->>'goal'` (JSONB extract)

**Use case:** "only show me people who clicked the pricing CTA."

**Configuration:**

* **Event name** — pick from the list of events your tracking script has observed.

**How to define events:** fire them from your site with `funnelfizz('event', 'pricing_clicked')` or mark elements with `data-fn-goal="pricing_clicked"`. Once you've fired an event, it appears in the dropdown here.

### A/B variant[​](#ab-variant "Direct link to A/B variant")

**Internal name:** `ab` **Filters on:** `trackingEvents.abVariant`

**Use case:** "compare conversion rates of my hero copy variants."

**How it works:** when a visitor lands on your site with `?ab=<variant>` in the URL, the tracking script stores that variant in a cookie and tags every subsequent event with it.

**Configuration:**

* **Variant name** — the string you used in the URL. E.g., `?ab=frog` → filter value `frog`.

**Example:** you send two newsletter campaigns, one with `?ab=frog` and one with `?ab=elk`. Split on `ab = frog` and `ab = elk` side by side to see which variant drove more conversions.

### Stripe product[​](#stripe-product "Direct link to Stripe product")

**Internal name:** `stripe_product` **Filters on:** `ProfileSubscription` tables (not tracking events)

**Use case:** "show me only people on the Pro tier."

**Configuration:**

* **Product** — pick from the list of Stripe products in your connected account.

**Limitation:** this split only applies at the TRIAL and CUSTOMER stages. Since it's a subscription-level filter, it doesn't make sense at AWARENESS or CONSIDERATION (there's no Stripe data yet).

## Nesting splits[​](#nesting-splits "Direct link to Nesting splits")

You can split a split. "US visitors from YouTube on mobile" is a three-level chain:

1. **Country = US** → US branch.
2. On the US branch, **Traffic source = youtube.com** → US + YouTube branch.
3. On that branch, **Device = mobile** → US + YouTube + mobile branch.

The canvas auto-lays-out nested branches so they don't overlap. There's no hard depth limit but in practice three levels is about as much as remains readable.

## Compound conditions (within a single split)[​](#compound-conditions-within-a-single-split "Direct link to Compound conditions (within a single split)")

Each split node has exactly one condition. If you want "A AND B," that's two splits stacked. If you want "A OR B," that's two sibling splits (you'll see both branches on the canvas).

There is no "NOT" condition today. If you want "everyone except US traffic," split by country and look at the *other* unfiltered stages — or use the opposite country list.

## Split metrics[​](#split-metrics "Direct link to Split metrics")

Each split branch shows:

* **Profiles in the branch** at each downstream stage.
* **Conversion rates** between stages, computed only for matching profiles.
* **Channel, device, country** breakdown of the branch's traffic.
* **Top referrers** and **Top UTMs** within the branch.

All metrics re-compute when you change the time window.

## Adding a split in the UI[​](#adding-a-split-in-the-ui "Direct link to Adding a split in the UI")

1. On the canvas, click the **+** button between any two stages (or between split and stage).
2. Pick a **condition** from the modal.
3. Fill in the **value**.
4. (Optional) **Name** the branch — shows up as a label on the canvas.
5. **Color** the branch — each split auto-picks a tint to stay visually distinct.
6. **Save**.

The branch fills in within a second or two.

## Removing a split[​](#removing-a-split "Direct link to Removing a split")

Right-click the split node → **Delete**. Everything downstream of it collapses. The main funnel stays intact. Historical data isn't deleted — if you re-add the same split later, the numbers re-appear.

## Behind the scenes[​](#behind-the-scenes "Direct link to Behind the scenes")

The SplitModal in `src/components/canvas/SplitModal.tsx` lists every condition. The SQL translation happens in `src/lib/metrics/split-filter.ts`. If you're curious how a condition ends up as a WHERE clause, that's where to look.

## Patterns we see a lot[​](#patterns-we-see-a-lot "Direct link to Patterns we see a lot")

* **Source-of-truth split.** Main funnel + one split per top traffic source. Answers "where does my best traffic come from?"
* **UTM campaign split.** Each campaign gets its own branch. Answers "which campaign actually converted, not just got clicks?"
* **A/B variant split.** Paired branches comparing two hero copy variants. Combined with [percentage-split automations](https://docs.funnelfizz.com/features/automation.md#percentage_split) for email A/B testing.
* **Country + device cross.** Two-level nest. Answers "is my US mobile experience broken?"

***

**Next:** [Extensions →](https://docs.funnelfizz.com/features/extensions.md) — the upsell tracking pipeline.
