Copy as markdown[View .md](https://docs.funnelfizz.com/concepts/splitting "View the raw markdown for this page")[Open in Claude](https://claude.ai/new?q=Read%20https%3A%2F%2Fdocs.funnelfizz.com%2Fconcepts%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%2Fconcepts%2Fsplitting.md%20and%20help%20me%20with%20this%20FunnelFizz%20topic%3A%20Splitting "Open this page in ChatGPT with context")

# Splitting

The whole-funnel average hides everything. **Which slice of traffic is actually converting?** is what splits answer.

A split is a filter node on the canvas between two stages. Everything downstream of it shows only profiles matching the condition. Conditions chain with **AND**. Nest splits to layer filters.

## Splits are filters that propagate[​](#splits-are-filters-that-propagate "Direct link to Splits are filters that propagate")

Every stage downstream of a split — a deeper nested split, an extension on the same track, an extension on a nested track — only contains profiles who **actually** crossed every ancestor split on the prescribed track. The cohort visible on a stage card is the same cohort that:

* Counts toward conversion rates between stages.
* Receives emails when you target that stage or branch.
* Enrolls in automations triggered from that stage.

So if you set up a "Hobby trial" split at TRIAL, then a "US" sub-split at CUSTOMER, then a Pro extension on the US-Hobby track, only profiles who actually went Hobby trial → US → Hobby paid → Pro upgrade land on that extension card. Nobody else can be reached or counted there.

If a profile doesn't match any track variant on a split, they end up unassigned on that branch — they're not silently force-bucketed into a default. The operator can see what's actually in each cohort.

When a profile leaves the cohort (cancels, downgrades, archives), the **historical track membership stays open as a durable record** — you can still see "this customer was in the US-Hobby cohort during their tenure." Current-tier filtering happens at query time, so dashboards and email targeting only count profiles whose CURRENT state still qualifies. If the same person re-trials after churn, a fresh cohort entry opens alongside the historical one. See [profile timelines](https://docs.funnelfizz.com/concepts/users.md#what-lands-on-the-activity-timeline).

## Where splits can sit[​](#where-splits-can-sit "Direct link to Where splits can sit")

Splits sit between two stages — never at AWARENESS. AWARENESS counts impressions from your providers; the cohort doesn't exist as profiles yet, so there's nothing to filter. The earliest you can split is right before CONSIDERATION.

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

| Condition          | Filters by                                               | Stage scope                                       | Example                        |
| ------------------ | -------------------------------------------------------- | ------------------------------------------------- | ------------------------------ |
| **Traffic source** | Referrer domain (substring)                              | CONSIDERATION onward                              | `reddit.com`                   |
| **UTM**            | One of `utm_source`/`medium`/`campaign`/`content`/`term` | CONSIDERATION onward                              | `utm_campaign = summer-launch` |
| **Channel**        | Auto-categorized bucket                                  | CONSIDERATION onward                              | `organic_search`               |
| **Device type**    | UA-parsed device                                         | CONSIDERATION onward                              | `mobile`                       |
| **Country**        | ISO country (MaxMind GeoIP)                              | CONSIDERATION onward                              | `US`                           |
| **Custom event**   | An event you fire from your site                         | CONSIDERATION onward                              | `pricing_clicked`              |
| **A/B variant**    | The `?ab=…` URL parameter, sticky cookie                 | CONSIDERATION onward                              | `frog`                         |
| **Stripe product** | Specific Stripe product ID                               | TRIAL + CUSTOMER (+ extensions for upsell tracks) | `prod_pro_tier`                |
| **Stripe price**   | Specific Stripe price ID (monthly vs yearly etc.)        | TRIAL + CUSTOMER (+ extensions for upsell tracks) | `price_pro_monthly`            |

### Sticky vs late-binding[​](#sticky-vs-late-binding "Direct link to Sticky vs late-binding")

Six conditions lock at FIRST TOUCH ("sticky" splits — once a visitor matches, they stay in that track forever): **Traffic source, UTM, Channel, Device type, Country, A/B variant**.

Three conditions evaluate at the GATING EVENT itself ("late-binding" — the event that lands the profile in the stage IS the condition): **Custom event, Stripe product, Stripe price**.

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

| Bucket           | Matches                                                                         |
| ---------------- | ------------------------------------------------------------------------------- |
| `direct`         | No referrer, no UTM                                                             |
| `organic_search` | Google, Bing, DuckDuckGo, Brave                                                 |
| `social`         | X, LinkedIn, Reddit, TikTok, Instagram, YouTube, Facebook                       |
| `paid`           | `utm_medium` in `cpc`/`paid`/`ads`, 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`       | Anything else with a referrer                                                   |

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

Fire from your site with `funnelfizz('event', 'pricing_clicked')` or mark elements with `data-event="pricing_clicked"`. Once observed at least once, the event name appears in the split dropdown.

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

Land a visitor on your site with `?ab=frog` in the URL. The tracking script stores `frog` in a cookie and tags every subsequent event. Filter for `ab = frog` to see only that cohort.

## Adding a split[​](#adding-a-split "Direct link to Adding a split")

1. Canvas → click the **+** button between two stages.
2. Pick a condition; fill the value.
3. Name and (optionally) color the branch.
4. Save, the branch backfills within a second or two.

When you save, FunnelFizz replays your Stripe history against the new track conditions so existing customers land on the right branches at their actual historical timestamps — no waiting for the next webhook to populate the cards. See [what backfill can and can't resolve](https://docs.funnelfizz.com/getting-started/connect-stripe.md#what-backfill-can-and-cant-resolve).

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

"US mobile traffic from YouTube" is a 3-level chain. Auto-layout keeps branches from overlapping. No hard depth limit; three levels is usually the readability ceiling.

## Compound conditions[​](#compound-conditions "Direct link to Compound conditions")

Each split node holds **one** condition. For:

* **A AND B**. Stack two splits.
* **A OR B**. Two sibling splits (both branches show on the canvas).
* **NOT A**. No native operator. Use the opposite condition (e.g., split country = US, look at the unfiltered branch alongside).

## What each branch shows[​](#what-each-branch-shows "Direct link to What each branch shows")

Per-stage profile counts, conversion rates, channel/device/country breakdowns, top referrers and top UTMs, all scoped to that branch. Re-compute when you change the time window.

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

Right-click the node → Delete. Downstream collapses; the main funnel is unaffected. Historical data is preserved, re-adding the same split brings the numbers back.

## Patterns[​](#patterns "Direct link to Patterns")

* **Source-of-truth**. Main funnel + one split per traffic source.
* **UTM campaign**. Each campaign as its own branch.
* **A/B hero copy**. Paired branches on `?ab=…`. Pair with [percentage-split automations](https://docs.funnelfizz.com/concepts/automations.md) for the email side.
* **US mobile cross**. Two-level nest, answers "is my US mobile flow broken?"

## Plan limits[​](#plan-limits "Direct link to Plan limits")

|                                        | FREE | HOBBY | PRO      |
| -------------------------------------- | ---- | ----- | -------- |
| Total splits per workspace             | 0    | 8     | 20       |
| Splits per main-funnel stage           | 0    | 2     | 4        |
| Sub-splits below a split (nesting)     | 0    | 0     | 1        |
| Distinct condition types per workspace | 0    | 1     | 3        |
| A/B variant condition                  | —    | —     | PRO only |

The "distinct condition types" cap counts the *kinds* of conditions you've used, not individual splits. HOBBY can run many splits as long as they all use the same condition (e.g., all by traffic source). PRO can mix up to three different condition types (e.g., traffic source + country + device).

***

**Next:** [Extensions →](https://docs.funnelfizz.com/concepts/extensions.md), track upsells after CUSTOMER.
