Canvas Branching
Create advanced branch logic based on events and attributes.
Behavior split triggers
A behavior split parks each user and routes them by what they do within a time window ("Did the event…"). On each branch you pick one or more triggers; the user takes the first branch whose trigger fires:
- Perform Custom Event / Place Order / Start Session - the user performs that event (optionally filtered by event properties).
- Add an Email Address / Change Custom Attribute Value - a user attribute (or their email) is set or changes. This fires whether the change comes from the dashboard, your API, or an SDK
identifycall; for an attribute change you can match any new value or the specific value. - Update Subscription Status - a contact's subscription status changes for a channel (Email, SMS, WhatsApp, or Push). Match any status change, or only when it changes to a specific status (Subscribed, Unsubscribed, or Opted in).
- Send a WhatsApp Inbound Message - the contact replies on WhatsApp. Optionally limit it to a specific WhatsApp account, and optionally match the message body - Contains, Doesn't contain, Matches, or Doesn't match a piece of text.
- SMS Inbound Message - the contact replies by SMS. Conditions match the Message Text or Message Type with operators like equals / contains / starts with. Inbound SMS is captured by the number's inbound webhook. In a message sent right after this branch matches,
{{ reply.text }}resolves to that reply - the same as WhatsApp. - Entity changed - a record of a custom entity (linked to the contact) is created, updated, or deleted - optionally on watched fields or matching field conditions. The entity must have a Contact link configured so the change resolves to the right contact(s). This is the same option you'll find on the journey entry trigger and on campaigns.
Users who don't trigger any branch within the window fall through to the timeout path. Choose immediate advance to route as soon as a trigger fires, or end of window to wait the full window and rank matches by branch order.
Choosing a branching node
Four node types route users down different paths, and they answer different questions:
| Node | Routes by | Use when |
|---|---|---|
| Branch (condition) | Who the user is right now - attributes, event history, segment membership | "Has this user purchased?", "Are they a VIP?" |
| Behavior Split | What the user does next, inside a wait window | "Do they purchase within 24 hours of this email?" |
| Experiment | Random percentage assignment | "Which of these two flows performs better?" |
| AI-Decision | The AI's per-user prediction of the best path | "Send each person the offer they're most likely to act on" |
The full configuration reference for each lives in Canvas Nodes - this page covers how conditions evaluate and the patterns that come up in practice.
Condition branches (Branch node)
A Branch node evaluates the user at the moment they reach it and routes them immediately - no waiting. It has two modes:
- Yes / No - one named path plus
Everyone else, for binary questions. - Multi - up to 10 named, ranked groups plus
Everyone else(11 paths total), for multi-way routing.
What conditions can check
Branch groups are built from the same filter rows used by the segment editor and campaign audience picker, so a branch can check anything a segment can:
- User attributes - custom attributes and default fields (email, phone, name, country, ML scores), with operators like equals, greater/less than, contains, exists, and in-list.
- Event history - performed / didn't perform an event, optionally within a time window (minutes, hours, or days) and optionally matching event properties (for example, "placed an order in the last 30 days with value of at least 100").
- Segment membership - in or not in a segment (segments may reference other segments).
- Journey participation - currently in, completed, or exited another journey.
- Channel subscription and list membership - subscribed/opted in to a channel, or member of a subscription list.
- Email bounce status, e-commerce state (RFM segment, order count, spend, cart state), entity records, and app presence.
The complete operator catalog per filter type is in the Branch node filter reference.
AND / OR conditions
Each path or group is defined by one or more filter groups:
- Filters inside a group are joined by that group's inner joiner -
AND("premium plan AND active last 7 days") orOR. - The groups themselves are joined by an outer operator, typically
OR- so a path matches if any of its groups match.
Narrow with AND, broaden with OR: "(VIP AND active) OR (spent over 500)" is two groups, each with an inner AND, joined by an outer OR.
Priority branches (ranked resolution)
In Multi mode, groups are evaluated top to bottom - the first matching group wins. This makes group order a real routing decision:
- Put the most specific group first. If "Made any purchase" ranks above "VIP customers", a purchasing VIP routes down the generic purchase path and never reaches the VIP one.
- Drag rows in the modal's rail to re-rank.
- Users matching no named group route to
Everyone else- always wire it, or flag it Exit canvas deliberately.
Any group (including Everyone else) can be flagged Exit canvas instead of routing - users hitting it complete the journey at the branch.
Condition branches vs experiment and variant splits
The distinction that matters: conditions are deterministic, experiments are random.
- A Branch always sends the same user (in the same state) down the same path - routing is a function of who they are. Use it when the paths are for different people.
- An Experiment node assigns users to paths at random by percentage - routing is a coin flip you control the weights of. Use it when the paths are alternative treatments for the same people and you want to learn which performs better (optionally locking in a winner). See the Experiment node guide.
- Whole-journey variants split at the entry trigger instead of mid-flow - A/B/n entire journeys against each other, optionally with a held-out control group to measure uplift. See Variants and control group.
- An AI-Decision node is neither: it deterministically picks the predicted-best path per user, learning from outcomes. See AI-Decision nodes.
A useful composition: an Experiment node to learn which message wins, downstream of a Branch that first routes by who the person is.
Common patterns
Purchased vs not
Two ways to ask, and they aren't interchangeable:
- Looking backward - a Branch with an event filter (
not_performed_event_in_last"Order Completed", 1 hour) after a Delay. Evaluates once, instantly, when the user arrives. This is the classic abandoned-cart shape: Trigger (Product Added) → Delay 1h → Branch → recovery email on the "didn't purchase" path. - Watching forward - a Behavior Split with a
purchase_completedtrigger and a 24-hour window. The user parks at the node; purchasing routes them immediately down the "did" path, the window expiring routes them down "No event in window". Use this when you want to react the moment the purchase happens rather than checking after a fixed delay.
Channel-preference routing
A Multi Branch using channel subscription filters, ranked by your channel priority:
- Push-reachable - opted in to push → Push message
- WhatsApp subscribers - subscribed to WhatsApp → WhatsApp message
- Everyone else → Email message
Because resolution is ranked, a user opted in to both push and WhatsApp gets push - the ranking is the preference order. For a prediction-driven version ("which channel will this user actually respond to?"), use an AI-Decision node instead and let the model route per user.
Lifecycle and value tiers
A Multi Branch on e-commerce filters - RFM segment equals "champions" for VIPs, days-since-last-order for at-risk customers, has-never-purchased for prospects - each tier routed to its own message sequence. A worked version of this is in the Multi-path RFM routing example.
Profile-completeness gating
A Yes / No Branch with an attribute exists check (for example, phone exists) before an SMS step, routing users without a phone down an email fallback path instead of relying on the send-time skip. Both work - the branch makes the fallback explicit in the flow, while the skip silently advances the user with no message. See subscription consent behavior.
Debugging paths
When a branch routes users somewhere you didn't expect:
- Per-path counts - in the analytics view, click the branch node to open its Metrics drawer; the Paths section shows how many users took each named path and what share of the node's entrants that is. A path at zero usually means a group that can never match or is shadowed by a higher-ranked group;
Everyone elseswallowing most traffic usually means your named groups are too narrow or mis-ordered. - Follow one user - open Analytics → Journey Runs, search the user ID, and expand the run: the timeline shows exactly which node and path each step took, and the per-user journey view highlights their route on the canvas. The run's Context Variables panel shows the values conditions had available.
- Check the evaluation moment - a Branch reads state at arrival. If the user's attribute changed after they passed the branch, they were routed on the old value; put the Branch after the Delay (not before) when you mean "state at send time".
- Watch for warning chips - a Behavior Split group with an empty trigger list shows a warning chip on the card: that group can never match until you add a trigger or set Exit canvas.
- Segment filters evaluate live - a
segmentcondition re-evaluates the segment's definition against the user at the moment they hit the branch (recursively, for segments that reference other segments), rather than reading a cached membership list - so a user who newly qualifies matches immediately.
See Canvas Analytics for the full analytics surface.
Related
- Canvas Nodes - full Branch and Behavior Split configuration reference
- Experiment node
- Variants and control group
- Canvas Analytics