# Branches

How the split steps route each contact by tag, list, segment, contact field, event, consent, reachability or a random A/B split.

**Language:** en
**Audience:** platform
**TLDR:** A split step sends each contact down the first branch they match, top to bottom; anyone who matches none takes the last default branch (Everyone else or Otherwise). Split by tag, list, segment, contact field, the entry event, an event the contact did, consent policy, channel reachability, or a random A/B split by percentage. After its branch the contact continues below the split.
**Translation key:** platform.automations.flows.branches
**Search keywords:** split, condition, conditional, if/else, if then else, routing, route contacts, decision, segment branch, tag branch, attribute branch, consent branch, A/B test, multivariate, percentage split, random split, no mobile number, VIP message, message by country
**Related pages:** /platform/es/automations/flows/branches, /platform/en/automations/flows, /platform/en/automations/flows/building-a-flow, /platform/en/automations/flows/waits, /platform/en/automations/flows/sending-messages, /platform/en/automations/flows/contact-updates, /platform/en/automations/flows/flow-analytics, /platform/en/audience/segments, /platform/en/campaigns/compliance-policies, /platform/en/consent
**Docs index (every page):** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/llms.txt
**This zone's index:** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/platform/en/llms.txt
**This page:** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/platform/en/automations/flows/branches/ (HTML) · https://staging-instasent-docs-nextjs.oscar-284.workers.dev/platform/en/automations/flows/branches.md (Markdown)
**Other language (es):** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/platform/es/automations/flows/branches.md

A split is the step that lets two contacts of the same flow live different journeys. When
a contact reaches it, the step looks at something about them — a tag, a segment, a field
of their profile, the order that brought them in, their consent, whether a channel can
reach them — and sends them down one **branch**, the path of steps prepared for people
like them. A Spanish customer gets the message in Spanish, a VIP gets the VIP offer, a
contact who declined marketing gets a tag instead of a promotion. The decision is
instant: the contact doesn't wait at the split, and the step itself never sends anything.

The panel groups these steps under **Split the flow** in the step palette, and there are
nine of them. Eight route by a condition and one, the **A/B split**, routes at random by
percentage. All of them follow the same rules, explained first; each one then has its
own section. Some waits also have several outputs — **Timezone delay** and **Smart
delay** on whether an allowed moment was found, **Wait for delivery** on whether the
message arrived and **Wait for activity** on a click, a reply or an event — and they are
explained in [Waits](/platform/en/automations/flows/waits).

## How branches work

Every split step is configured in its settings panel under **Branches**, with **Add
branch** at the bottom. Each branch holds a condition, and the panel reminds you of the
one rule that governs them all: *Contacts take the first branch they match, top to
bottom.*

| Step                   | What it looks at                            | Default branch                                      |
| ---------------------- | ------------------------------------------- | --------------------------------------------------- |
| **Check tag**          | The tags the contact carries                | **Everyone else**                                   |
| **Check list**         | The lists the contact belongs to            | **Everyone else**                                   |
| **Check segment**      | The segments the contact is in              | **Everyone else**                                   |
| **Check attribute**    | Any field of the contact's profile          | **Otherwise**                                       |
| **Check entry event**  | The data of the event that started the flow | **Otherwise**                                       |
| **Check event**        | Whether the contact did an event            | **Otherwise**                                       |
| **Check consent**      | Whether the contact meets a consent policy  | Two fixed outputs: **Has consent** / **No consent** |
| **Check reachability** | Whether a channel can reach the contact     | **Otherwise**                                       |
| **A/B split**          | Nothing: a random draw by percentage        | The last slice of the split                         |

### The first matching branch wins

Branches are checked in order, from the top of the list to the bottom, and the contact
takes the **first** one whose condition they meet. Later branches are not looked at, even
if the contact would match them too. Each contact therefore takes exactly one branch.

Order is how you set priority. In a split by tag with a branch for **One of: vip** above a
branch for **One of: newsletter**, a VIP who is also on the newsletter goes down the VIP
branch. Swap the two and the same contact gets the newsletter path. When two conditions
can overlap, put the most specific one, or the one that matters most, at the top.

### The default branch

Below the branches you add there is always one more: the **default branch**, which the
panel describes as *Taken when no branch above matches.* It is what guarantees that every
contact leaves the split, including the ones you didn't plan for. It is always the last
one: it can't be moved, deleted or given a condition, but it can be renamed. Its name
depends on the step: **Everyone else** in Check tag, Check list and Check segment, and
**Otherwise** in Check attribute, Check entry event, Check event and Check reachability.

Leaving the default branch empty is a perfectly valid choice: contacts who take it skip
straight to whatever comes after the split.

### Adding, ordering and naming branches

- **Add branch** adds a branch at the end of the list, just above the default one. A split
  holds up to **10** branches plus the default branch, and at least one.
- **Order**: drag a branch by its handle, or use **Move up** and **Move down** in its menu.
- **Rename branch**, in the same menu, asks for a **Branch name**. Leave it empty to go
  back to the automatic title.
- **Remove** deletes the branch, together with the steps placed in it; the menu greys the
  option out when only one branch is left. **Undo**, in the editor toolbar, brings it
  back.

A branch without a name takes an automatic title from its condition: **One of: vip** or
**None of: vip** in Check tag, Check list and Check segment, the event's name in Check
event, the states it covers in Check reachability (**Supported / Unknown**), and
**Branch 1**, **Branch 2**… everywhere else. That last case includes Check attribute,
where a branch for *Country is Spain* is still called **Branch 1** until you rename it.
The same title appears on the branch's label on the canvas.

A branch that can never match blocks publishing: a branch of Check tag, Check list or
Check segment with no value, a branch of Check attribute or Check entry event with no
condition, a branch of Check event with no event, or a branch of Check reachability with
no state. The draft can still be saved, and the problem is listed under **Fix your flow
to publish it** (see [Building a flow](/platform/en/automations/flows/building-a-flow#fix-what-blocks-publishing)).

### After the branch, the contact continues below the split

A branch is a detour, not a separate ending. When a contact reaches the end of their
branch, they continue with whatever is placed **below the split**, where all its branches
rejoin; you never draw that join. How this looks on the canvas, and where each **+**
inserts a step, is explained in
[Building a flow › Splits, branches and where a step lands](/platform/en/automations/flows/building-a-flow#splits-branches-and-where-a-step-lands).

To end the run inside a branch instead, put an **Exit flow** step at the end of it: the
contact's run ends there and they don't continue below the split (see
[Goals and exits](/platform/en/automations/flows/goals-and-exits)).

### How recent the information is

Branches decide on what Instasent knows about the contact at that moment:

- **Check tag**, **Check list**, **Check consent** and **Check reachability** read the
  contact as it is right now.
- **Check segment**, **Check attribute** and **Check event** can take a few seconds to
  reflect a very recent change: a field updated, or an event received, in the last few
  seconds before the contact reaches the split may not be seen yet.
- **A branch placed right after an Update tags or Update lists step sees the value from
  before that update.** If a split has to see a tag or list that the same flow has just
  added, put a wait between the two steps (one minute is the minimum, and enough).

Flows that use the **Instant** processing mode get a similar warning in the trigger
settings: without the short processing window before entry, branches may not see the
last few seconds of activity (see [The trigger: who enters and when](/platform/en/automations/flows/triggers-and-entry)).

### Knowing which branch a contact took

The contact's journey lists every step the run went through, with its name and status,
but it doesn't say which branch of a split was taken. You can tell from the step that
follows, or, after a message, from **View message**. That is the best reason to name
your branches and the steps inside them after what they mean — "Spain", "VIP offer" —
rather than leaving **Branch 1** (see
[Monitoring a flow](/platform/en/automations/flows/monitoring-a-flow)).

Once the flow is published, the canvas of the live version shows each branch with its
share of the contacts that have already chosen a branch at that step (they add up to at most 100 %). Shares are counted over runs, not people,
so a contact who entered the flow twice is counted twice (see
[Flow analytics](/platform/en/automations/flows/flow-analytics)). When you test a draft
with one contact, you can force which branch the test run takes at each split (see
[Testing, publishing and versions](/platform/en/automations/flows/versions-and-publishing)).

Splits add no charge of their own: only the messages a flow sends are billed (see
[Sending messages](/platform/en/automations/flows/sending-messages)).

## By tag, list or segment

**Check tag**, **Check list** and **Check segment** route by what the contact belongs to.
They are the quickest way to give a group its own path: VIP customers, the members of a
"wholesale" list, the contacts in a "Bought in the last 90 days" segment.

Each branch has two parts:

- A mode: **is one of** (the default) matches a contact who has **at least one** of the
  values; **is none of** matches a contact who has **none** of them.
- The values: tags (**Pick tags or type a new one**), lists (**Pick lists or type a new
  one**) or segments (**Pick segments**). Tags and lists can be typed even if no contact
  carries them yet — useful when another step or flow is going to add them. Segments
  must already exist.

The default branch is **Everyone else**.

Tags and lists are checked against the contact as they are at that moment. A segment is
a dynamic view over your audience that updates as contact data changes (see
[Segments](/platform/en/audience/segments)), so Check segment can lag a very recent change
by a few seconds. When a condition is too complex for a single branch — several fields
combined with "or", for example — build a segment for it and route with Check segment.

## By contact field

**Check attribute** routes by any field of the contact's profile: country, language,
city, date of birth, number of orders, a custom attribute from your data source (see
[Attributes & events](/platform/en/audience/attributes-events)). Use it for the
differences that live in the profile — a message in the contact's language, a different
offer by country, a path for customers who have ordered before.

Each branch takes one or more conditions with **Add condition**, each made of a field,
an operator and a value. Inside a branch the conditions combine with **AND**: the
contact must meet all of them. There are no "or" groups inside a branch; to accept
either of two conditions, add a second branch, or build a segment and use Check segment.
Every branch needs at least one condition, and the default branch is **Otherwise**.

Unnamed branches are titled **Branch 1**, **Branch 2**… whatever their condition says, so
rename them: on the canvas and in reports, "Spain" says much more than **Branch 1**.

### Example: a welcome message by country and for VIPs

A store wants every new contact to get a welcome SMS in the right language, with a
special one for VIP customers. The flow *Welcome by country* starts on **Customer created
/ updated**, once per contact:

1. A **Check attribute** step with one branch, renamed "Spain", for *Country is Spain*.
   It holds an SMS in Spanish.
2. The **Otherwise** branch holds a **Check tag** step with one branch, **is one of**
   `vip`, which holds the VIP SMS. Its **Everyone else** branch holds the generic SMS.
3. Below the first split, where every branch rejoins, an **Update tags** step adds
   `welcome-sent`.

```mermaid
flowchart TD
    T["Trigger: Customer created / updated"] --> A{"Check attribute"}
    A -->|Spain| ES["Send SMS in Spanish"]
    A -->|Otherwise| V{"Check tag"}
    V -->|"One of: vip"| VIP["Send VIP SMS"]
    V -->|Everyone else| G["Send generic SMS"]
    ES --> U["Update tags: add welcome-sent"]
    VIP --> U
    G --> U
```

A contact in Spain gets the Spanish SMS, even if they are a VIP, because the country
branch comes first. A VIP outside Spain gets the VIP SMS, and everyone else the generic
one. Each contact receives a single message, and all of them end up with the
`welcome-sent` tag, which a single step below the split is enough to add. To give Spanish
VIPs their own message, add a Check tag step inside the "Spain" branch too.

![A flow that splits by country and then by VIP tag, with each branch sending its own message](/platform/en/automations/flows/images/branches--1-split-canvas.png)
*After its branch, each contact continues below the split.*

## By the event that started the flow

**Check entry event** routes by the data of the event that brought the contact into this
run: the amount of the order, the discount code used, the form that was submitted. Use it to treat entries differently without building several
flows on the same event.

Each branch takes one or more conditions on the parameters of the trigger event, added
with **Add condition** and combined with **AND**. Every branch needs at least one
condition, and the default branch is **Otherwise**. The data is always that of the event
that started *this* run, so two contacts who entered with different orders are routed by
their own order.

For example, in a *Thank you for your order* flow on **Order created**, a branch for
orders with a total of 100 or more can send a thank-you with a gift code, while
**Otherwise** sends the standard thank-you.

The trigger's own event conditions and this step do different jobs: the trigger's
conditions decide **who enters** the flow (see
[The trigger: who enters and when](/platform/en/automations/flows/triggers-and-entry)),
while Check entry event routes the contacts who have already entered.

## By an event the contact did

**Check event** asks whether the contact has done an event — bought, filled in a form,
clicked a campaign — and routes them by the answer. Each branch has:

- `Data source` — default: `Any data source`
  Restricts the search to the events of one data source. Optional.
- `Event` — required
  The event to look for (**Select an event**). An unnamed branch is titled with the
  event's name.
- `Only since entering the flow` — default: `on`
  Counts only events that happened after the contact entered this run of the flow.
  Switch it off to look at the contact's earlier history too.
- `Within the last … days` — default: `Any`
  Counts only events from the last number of days you enter. Empty means no time limit.
- `Add event condition`
  Optional conditions on the event's data, such as a minimum order amount.

When both time options are set, the stricter one wins: with **Only since entering the
flow** on and 30 days, only events since entry count. With both off, the contact's whole
history counts. The default branch is **Otherwise**, and recent events can take a few
seconds to be seen.

Check event looks back at that moment and decides at once; it doesn't wait for anything.
For example, in a flow that starts on **Product viewed**, a day later a branch for
**Order created**, since entering the flow, holds an **Exit flow** step for contacts who
have already bought, and **Otherwise** sends everyone else a reminder about the product. To wait for the event to happen — and react as soon
as it does — use a **Wait for activity** with a **Did an event** branch instead (see
[Waits › Wait for activity](/platform/en/automations/flows/waits#wait-for-activity)).

With **Only since entering the flow**, the event that started the run itself does not count. To branch on that event's own data, use **Check entry event**.

## By consent

**Check consent** routes by whether the contact meets a consent policy on a channel. Use
it to give contacts who haven't accepted marketing a path of their own — a tag, a message
on another channel, the end of the flow — instead of a promotion.

It is the only split with fixed branches. As the panel puts it, *This step always has two
outputs:*

- **Has consent** — the contact satisfies the policy and can be messaged on this channel.
- **No consent** — the contact doesn't meet the policy (unsubscribed or without consent).
  Sending already skips them; use this output to route them elsewhere.

Its settings:

- `Channels` — default: `SMS`
  The channels whose consent is checked: SMS, RCS or both. At least one.
- `Require consent on` — default: `All selected channels`
  Only with two channels selected. **All selected channels**: Has consent only if every
  channel allows messaging the contact. **Any of the channels**: Has consent if at
  least one channel allows it.
- `Consent policy` — default: `Opt-in`
  The policy the contact is checked against, one for all the selected channels:
  **Opt-in** (only contacts who explicitly accepted marketing), **No opt-out** (excludes
  contacts who explicitly declined marketing) or **Basic** (all subscribed contacts,
  ignoring marketing preferences).

Exactly which contacts each policy lets through, including those with no marketing
preference recorded, is explained in
[Compliance policies](/platform/en/campaigns/compliance-policies). RCS uses the contact's
SMS consent, so checking RCS gives the same answer as checking SMS (see
[Shared consent (RCS & SMS)](/platform/en/consent/rcs-sms-shared-consent)).

> **Warning**: Check consent **routes**; it doesn't protect. Every message already checks the contact
> against **its own** consent policy when it is sent, with or without this step — and a
> new message starts on **Basic**, which reaches contacts who declined marketing but never
> unsubscribed. Check consent starts on **Opt-in**: the two settings are independent, and
> a message keeps its own policy whichever branch it sits in. See
> [Sending messages › Who receives it](/platform/en/automations/flows/sending-messages#who-receives-it-the-consent-policy).

Check consent looks at the policy, not at whether the contact can actually be reached. A
contact who accepted marketing but has no mobile number goes down **Has consent**, and
the SMS that follows can't be sent to them. To separate those contacts, add a **Check
reachability** step as well.

![Check consent settings with its two outputs and the Opt-in policy](/platform/en/automations/flows/images/branches--2-consent-branch.png)

### Example: an offer only for contacts who accepted marketing

The *Spring offer* flow from [Sending messages](/platform/en/automations/flows/sending-messages)
starts when a contact views a product (**Product viewed**). A **Check consent** step,
left as it comes (SMS, **Opt-in**), goes first:

- **Has consent** → the SMS with the discount.
- **No consent** → an **Update tags** step that adds `no-marketing-consent`.

Laura declined marketing SMS but never unsubscribed. She goes down **No consent**: she
receives nothing, gets the tag, and her run ends normally. A contact who accepted
marketing goes down **Has consent** and receives the offer. A contact who accepted
marketing but has no mobile number also goes down **Has consent**; the SMS isn't sent and,
with the message's default setting, their run stops at that step with the status
**Stopped**.

## By channel reachability

**Check reachability** routes by whether a channel can reach the contact, so you can react
before trying to send: tag the contacts who have no mobile number, end the flow for them,
or give contacts whose phone is known to support RCS a different path from the rest.

The step works on **one channel**, chosen under **Channel**: SMS (the default) or RCS.
Each branch selects one or more of three states:

| State             | SMS                                         | RCS                                                  |
| ----------------- | ------------------------------------------- | ---------------------------------------------------- |
| **Supported**     | The contact has a valid mobile number.      | Their phone is known to support RCS.                 |
| **Unknown**       | Never used: SMS contacts are never Unknown. | It isn't known yet whether their phone supports RCS. |
| **Not supported** | The contact has no valid mobile number.     | Their phone is known not to support RCS.             |

A new Check reachability step starts with one branch, **Supported / Unknown**, and the
**Otherwise** branch, which in practice catches **Not supported**. You can change the
states of each branch, add more branches, and every branch needs at least one state.

Only **Not supported** is definitive; **Unknown** means there isn't conclusive data yet.
The step doesn't decide whether a message goes out: a **Send message** step still
decides on its own when it sends, and a Send RCS step with its SMS fallback on still
sends the SMS when RCS can't reach the contact (see
[SMS fallback](/platform/en/channels/rcs/sms-fallback)). Check reachability is for
building a different path; the fallback is the safety net inside the message.

For example, a flow that starts with Check reachability on SMS can send **Not supported**
contacts to an **Update tags** step that adds `no-mobile` and an **Exit flow**, so they
don't reach any message, and let everyone else continue. Check reachability looks only
at the channel, not at consent: to check both, chain it with **Check consent**.

## A/B split

The **A/B split** sends each contact down a branch **at random**, according to percentages
you set. Use it to compare two or more versions of a message — a 10 % discount against
free shipping, a short text against a long one — or two different paths, with real
contacts.

Its settings hold a single section, **Split**, with the hint *Contacts are randomly split
by these percentages. The rest go to the default branch.*

- A new A/B split starts at **50 % / 50 %**: one variant and the default branch.
- **Add variant** adds a branch that starts at 10 %, taken from the others. You can have up
  to **10** variants plus the default branch, and at least one variant.
- Each variant has a slider, in steps of 1 %. Moving one rebalances the others so that the
  split always adds up to 100 %, each variant can go down to **1 %**, and the default branch keeps at least **2 %**: dragging a variant stops where the default branch would drop below that, so the most uneven split with one variant is 98 % / 2 %.
- The last branch, the default one, *Automatically receives the remaining percentage.* It
  can't be set directly.
- Branches are titled by their percentage — on the canvas a 50/50 split shows **50%** and
  **50%** — and can't be renamed. Their order doesn't matter, because the draw doesn't
  depend on it.

The draw is made for each run, at the moment the contact reaches the step. A contact who
enters the flow again can land in a different branch the next time. With few contacts
the real shares can be far from the ones you set; they get closer as more contacts go
through.

To compare the results, put a different message, or path, in each branch, publish, and
read each message's figures: on the live version, each Send message step shows its own
metrics, and the flow report breaks them down by message (see
[Flow analytics](/platform/en/automations/flows/flow-analytics)). The A/B split compares
paths inside one version of a flow. Testing a new version of the whole flow on part of
your contacts is a different feature, the live test (see
[Testing, publishing and versions](/platform/en/automations/flows/versions-and-publishing)).

### Example: which welcome offer works better

A store wants to know whether new contacts respond better to a 10 % discount or to free
shipping. In its welcome flow, an **A/B split** at 50 % / 50 % holds an SMS with the
discount code in one branch and an SMS with the free-shipping code in the other. Each
new contact receives one of the two SMS, chosen at random, never both. After a few weeks,
the figures of each Send message step show which offer got more clicks; the store keeps
the winning SMS and removes the split in a new version.

## Related

- [Waits](/platform/en/automations/flows/waits) - Branch on delivery, a click, a reply or an event, with a time limit.
- [Updating the contact](/platform/en/automations/flows/contact-updates) - Add tags and lists that later splits can route by.
- [Segments](/platform/en/audience/segments) - Build the groups that Check segment routes by.
- [Consent & subscriptions](/platform/en/consent) - Marketing preference, opt-outs and suppression.

---

This is one page of the Instasent documentation. For the complete machine-readable index of every guide and API reference, fetch https://staging-instasent-docs-nextjs.oscar-284.workers.dev/llms.txt — start there for full context.
