SaaS Copy Weekly

Branching Logic Design for Feature Adoption Campaigns

Tie adoption campaigns to product actions, not calendar dates, to reach users at the right moment.

Contributing Editor · · 10 min read
Cover illustration for “Branching Logic Design for Feature Adoption Campaigns”
Campaign Architecture · October 4, 2026 · 10 min read · 2,293 words

A SaaS onboarding email triggers correctly when it's tied to a specific product action rather than a calendar date. Define one activation event that separates accounts that stick around from accounts that churn, check whether a given user or account has reached it, and only send guidance to the ones who haven't, filtered by whether their plan and role even allow them to get there. Everything else, including day-three nudges and day-seven reminders sent to everyone regardless of what they've done, is a guess dressed up as a sequence.

Why static campaign paths fail users who have already moved past them

A growth team builds a seven-day onboarding sequence. The welcome note goes out on day one. Day three is a tooltip walkthrough email. Day seven is a check-in asking if the user needs help getting started. The day-three email landed in the inbox of someone who didn't need it, and the day-seven email reads like a mild insult to someone who's been using the feature daily for five days straight.

That's the mechanical failure at the center of most adoption campaigns. A static path treats a user who already completed the target action the same as a user who never tried it. Both get the same message. For the first user, it's redundant. For the second, it's often mistimed, arriving too late or too early relative to where they actually are in the product.

The deeper issue isn't a sequencing tool, and it isn't a scheduling bug. A static campaign uses time as a proxy for progress, and time is a bad proxy. An adoption agent approach reads product data and account state to understand where each user actually is, then sends only when the evidence justifies it, skipping anyone who has already moved past the step the message was built for.

What counts as a signal worth branching on

Not every event a product logs deserves to drive a decision. The first real design choice in branching logic is figuring out which signals say something true about where a user is, and which ones are too shallow or too noisy to trust.

Three categories of evidence hold up well enough to branch on. The first is database state: what the account record says right now, including plan tier, role, whether configuration is complete, how many seats are provisioned. This moves slowly and rarely lies. The second is behavioral history: what the user has actually done over time, which features they've touched, how often, whether engagement is deepening or flattening out. This is the signal that shows trajectory rather than a single snapshot. A user on an advanced plan who has never triggered its core workflow is a fundamentally different case from a user on a starter plan who has hit every activation milestone available to them, even though a time-based campaign would treat them identically.

Some events look like signals but aren't. Adoption is repeated use folded into a workflow, while a moment of curiosity is not.

That distinction, between a feature trial and feature adoption, matters more than it looks on paper. Branch conditions should be built to detect adoption, not trial, because mistaking one for the other is how campaigns end up congratulating users who clicked once and never came back.

One more check has to happen before any of this works: confirm the person the signal describes is actually eligible to reach the behavior in question. Identifying which signals are stable enough to act on means reading database state and behavioral history together, and platforms that investigate each person's current account configuration and product usage before deciding whether to send treat the absence of evidence as a reason to skip rather than send, so branch logic stays grounded in what that specific user can actually do.

Defining the activation event that anchors every branch

Every branching campaign needs one anchor: a specific, measurable product action that reliably separates users who get real value from the product from users who don't. Without that anchor, branches end up organized around whatever milestone felt convenient to track rather than the moment that actually predicts whether an account sticks around.

Finding it doesn't require new instrumentation. It requires looking at the feature interactions and workflow completions a team already has data on, and asking which one shows up most often in accounts that converted or renewed, and least often in accounts that churned. That asymmetry, strong among the accounts that stayed and rare among the ones that left, is what marks an event as the activation fingerprint rather than just a popular feature.

The activation event has to be a real action rather than a page view. A completed workflow, a generated report, a collaboration initiated with a teammate, something that required the user to understand enough about the product to actually do something meaningful with it. Once that event is defined, every branch in the campaign has a direction: branches before activation guide a user toward the event, and branches after activation work on deepening usage or introducing features adjacent to it.

Defining the event this way also makes the whole campaign auditable in a way a vague goal never could be. An account either reached the activation event or it didn't. That binary outcome means a campaign's effectiveness can be checked against real product data instead of proxy metrics like open rate.

The most common mistake teams make here is defining activation as a usage threshold, logged in three times, viewed the dashboard twice, rather than a meaningful action. A threshold measures activity. An activation event measures whether someone actually got somewhere.

Designing branch conditions that reflect evidence rather than assumptions

A branch condition makes a claim about where a user currently stands, and that claim needs to rest on evidence, not on how many days have passed since they signed up.

The basic shape of a behavior-grounded branch looks like this:

If [account state] AND [behavioral evidence] THEN [path A]; ELSE [path B].

The account state leg, plan, role, configuration, filters for who's even eligible to reach the target behavior. The behavioral evidence leg confirms or denies whether progress actually happened. Neither leg works alone. An account on the right plan with the right role but no behavioral evidence of progress is not the same case as an account with strong behavioral evidence but the wrong plan to act on it.

Picture a B2B SaaS product with a collaboration feature available only on its Team plan. A stalled branch checks whether the user started building a workspace, invited no one, and has had no related activity in seven days, and routes to a message addressing that specific stall point rather than restarting the whole onboarding flow from scratch.

There are three archetypal branch types that cover most real campaigns: the has-reached branch, which needs a confirmed product event as evidence and moves the user toward depth or an adjacent feature; the has-not-reached branch, which needs confirmed eligibility before assuming the gap is meaningful, and moves the user toward the activation event with specific instruction; and the stalled branch, which needs the last event crossed, the time elapsed since, and the absence of further progress, and addresses the exact point where momentum broke rather than the entire journey.

Just as important as when to send is when not to. If the evidence for a branch is weak, the event is ambiguous, the account state is incomplete, or the last activity is too recent to mean anything, the right move is to wait or skip, not to fire a default message anyway. A message sent without real evidence behind it is worse than no message. It teaches users to tune out whatever comes next, because it signals the system sending it doesn't actually know where they are.

Account-level and user-level evidence often need to be evaluated side by side rather than interchangeably. A single user on a five-seat account might have reached the activation event personally, while the account as a whole, four other seats untouched, hasn't. Treating the user's progress as the account's progress, or vice versa, produces the wrong branch for both. Branch conditions need to keep those two levels explicitly separate.

One branch deserves special attention: the PQL routing branch. When a user's behavior crosses a threshold that signals expansion intent, heavy use of a feature gated to a higher plan, repeated attempts that hit a plan limit, the right path is a handoff to a human-assisted conversation. That's the moment a branching campaign stops managing onboarding and starts managing a sales motion.

What AB Tasty's acceleration of feature launch cycles shows about where branching logic fails

A vendor's compression of feature launch cycles is a useful stress test for this whole framework, because shipping faster doesn't help if the guidance attached to each launch still goes to everyone at once. Getting the right message to the right user at the right moment is fundamentally a branching logic problem, and if every user receives the same announcement regardless of account state or history, a faster launch cycle doesn't produce faster adoption. It just produces faster noise.

The failures that follow a pattern here appear even with solid tooling in place. Branch conditions get designed against assumed user states and only later turn out to be wrong once the campaign is live, with some users the campaign treated as pre-activation having already activated, and some treated as activated having never actually gotten there. The activation event itself is often defined too loosely, so a has-reached branch fires for anyone who touched a feature once, conflating a single moment of curiosity with real adoption. And the cohort used for measurement is frequently wrong in a quieter way: adoption gets measured against everyone who received a message, including users on plans where the feature isn't even available, which drags down the apparent adoption rate and makes it hard to tell which branches actually worked.

The thread running through all three failures is the same: the branch conditions were built before anyone confirmed the underlying data could actually support them. The design principles from the previous section only hold if the data behind them is trustworthy, which the next section addresses.

The data prerequisites that branching logic depends on

The strongest pushback against behavior-grounded branching is that it demands event data clean enough to trust, and most teams built their tracking for dashboards and reporting, not for making automated decisions. Data that looks fine in a chart can still fire the wrong branch in a live campaign.

Three things need to be true, in order, before branching logic will hold up. First, there has to be a defined activation event with a scrubbed, eligible cohort behind it: the team agrees on what activation means and who is eligible to reach it. Without that agreement, branch conditions end up designed against a population that doesn't really exist. Second, account and user records need to be kept distinct. Third, behavioral history has to connect back to current account state through a stable identifier. Product events logged without a reliable link to the account record can't be joined to plan, role, or configuration. The behavioral leg of a branch condition then has nothing to check itself against. The two have to be joinable on a shared key, or the whole structure falls apart at the first branch.

None of this requires a new tracking plan, a new instrumentation layer, or a new data warehouse. The actual bar is lower: the database and the analytics data a team already has need to be joinable and consistent enough to evaluate the specific branches they plan to use.

A fast way to check readiness before launching anything: try writing a query that returns every eligible user, right plan, right role, who hasn't yet reached the activation event. If that join doesn't work, the stalled-branch condition has no reliable way to fire.

Measuring whether the branch changed behavior in the product

A branching campaign succeeds or fails based on whether the targeted behavior actually changed in the product, not on whether anyone opened or clicked the message that prompted it.

Three lenses work well here, applied strictly to the eligible cohort rather than the full list of people who received something. Reach asks what share of eligible, active accounts used the feature at least once after the branch fired. Depth asks how much real use happened per adopting account, enough interaction to suggest the feature is becoming part of someone's actual workflow, not just a single touch. Repeat asks what share of accounts that adopted in one period came back to use the feature again in a later eligible period, which is the clearest evidence available that value was realized rather than sampled once and abandoned.

The denominator matters as much as the metric. Measuring against the entire recipient list, including people who were never going to be able to adopt in the first place, deflates the real adoption rate and makes every branch look weaker than it actually is.

Cohort comparison does the heavy lifting in this kind of measurement. Group users by the period in which they activated, then track what share of each cohort keeps using the feature afterward. Once the activation event anchors every branch in a campaign, the real test of the whole system is whether the people who received guidance changed their behavior in the product afterward. Measuring successful activation means separating users who merely saw a message from users whose product behavior actually moved, and that gap, between message engagement and real adoption impact, is the one number that tells a team whether its branching logic was built on evidence or on a guess that happened to look reasonable at the time.

More in Campaign Architecture