A Klaviyo workflow is four mechanisms, not one canvas
A Klaviyo workflow is four mechanisms wired together: a trigger that decides who enters, a conditional split that branches people onto different paths, a wait step that paces how fast the next email goes out, and an exit condition that pulls someone out before a send that no longer applies to them. Most guidance on Klaviyo workflow setup walks through building a single flow from a blank canvas: pick a trigger, add three emails, publish. It skips the part that actually breaks in production — the flow that keeps sending a nurture email to someone who has already placed the order the flow was written to encourage.
This article stays on structure: how the trigger, the split, the wait step and the exit condition interact. It isn’t a guide to segmentation strategy, account setup or which flows to build first — those are covered elsewhere. The step most teams get wrong is not the trigger. It’s the exit condition: without one, a flow keeps running against its original entry state, and a browse-abandonment nurture lands in someone’s inbox forty minutes after they’ve already checked out.
The audience for this piece is a scaling brand on Shopify Plus or a comparable subscription platform running Klaviyo at real send volume. A store sending a handful of emails a month, with one or two flows total, won’t hit most of the failure modes covered here, and the engineering time to fix them won’t be worth it yet. Klaviyo’s own benchmark data across 183,000+ brands puts 41% of email revenue through automated flows, vendor-reported, which is exactly why a structural mistake in one flow costs more than the identical mistake in a single campaign send: the flow keeps repeating it against every new person who enters.
Choose the trigger before you build anything else
A trigger decides more than when a flow starts. It decides what data exists at the moment someone enters, and whether the same person can go through the flow more than once. Klaviyo lets a flow trigger from a list, a segment, or a metric — Klaviyo’s term for a tracked event, such as a checkout being started or an order being placed. List and segment triggers evaluate membership; metric triggers fire on the event itself, at the moment it happens.
The three behave differently once you look past the setup screen. A list trigger fires when a profile is added to a static list, so entry is deliberate and usually one-directional — someone joins a welcome sequence once, because being added to the list is itself the action. A segment trigger fires when a profile starts matching a segment’s conditions, and because segment membership can change over time, the same person can potentially re-enter later if they drop out of the segment and then qualify again; the exact re-entry behaviour is a separate setting from the trigger choice itself and is worth confirming directly in Klaviyo’s current documentation rather than assumed. A metric trigger fires per instance of the event, which means someone who abandons a cart twice in a week can, depending on entry settings, start the flow twice.
The practical rule: match the trigger’s granularity to what the message actually depends on. A post-purchase nurture needs a metric trigger tied to the order being placed, not a static list, because the timing of every email after it depends on the order’s own timestamp — not on when a marketer happened to add the customer to a list three days later. Using a list trigger for a time-sensitive sequence decouples the flow’s clock from the event it’s supposed to be reacting to, and every wait step downstream inherits that error.
Set the conditional split on behaviour, not on intent
A conditional split evaluates a condition at the exact moment a profile reaches that step in the flow, and routes them down one of two paths based on the result. The condition can check a profile property or an event that has happened. The distinction that matters here is between behaviour and intent. Behaviour is something the profile has actually done — clicked a link, placed an order, viewed a specific product. Intent is a guess made at an earlier point — a quiz answer, a signup source, a cart’s contents at the moment someone entered the flow. Splitting on behaviour keeps the flow accurate to what’s true right now. Splitting on intent captured at trigger time can be stale by the time the split step is reached, particularly after a wait step has let hours or days pass.
Take a cart abandonment flow with a split partway through. Splitting on “has this person placed an order since entering the flow” routes anyone who bought off the persuasion path entirely and sends everyone else the next reminder. Splitting instead on “cart value at time of entry” tells you nothing about whether they’ve since checked out — it’s a snapshot of intent, not a check on outcome, and using it as a proxy for “should this person still get this email” is exactly how a purchaser ends up back in the reminder sequence.
A conditional split itself is a yes-or-no fork: it produces exactly two paths. A flow that needs to route someone into three or four different treatments — high-value cart, mid-value cart, loyalty-tier customer, first-time visitor — needs splits chained one after another, each asking a single question, rather than expecting one node to sort everyone into every bucket at once. Flows that try to cram too many conditions into a single split tend to become unreadable within a few months, which is its own maintenance cost separate from whether the logic is correct on day one.
What a flow filter checks that a conditional split doesn’t
A flow filter works differently from a split. Where a split creates a visible fork with two paths that both continue, a filter is a gate: it holds a condition, and a profile that doesn’t meet it either waits or is removed from the flow at that point, with no second branch to follow. The mechanism that makes a filter useful for cleanup work a split can’t do well is re-evaluation — a filter attached ahead of a specific send can be set to check its condition again immediately before that email goes out, rather than only once when the profile first reached that point in the flow.
That re-check timing is the piece worth confirming directly against Klaviyo’s current documentation before you rely on it for anything consent-sensitive, because filter evaluation behaviour has changed across product versions and varies by exactly where in the flow the filter sits. What’s stable is the conceptual difference: a conditional split is for routing people onto genuinely different content, and a flow filter is for deciding, right before a send, whether this particular email should go out at all. Using a split where a filter would do the job means building and maintaining a second branch of the flow that exists only to do nothing — every “no” path in that split has to terminate cleanly, which is extra structure for a decision that a single gate could make.
Set the wait step to a length the trigger event can support
A wait step, sometimes called a time delay, is a pure pause. It doesn’t evaluate anything, check any condition, or look at what’s happened to the profile during the delay — it counts elapsed time and then continues to whatever comes next. This is the single most common source of confusion in a Klaviyo workflow, because people build the flow as if the wait step were also checking something. If a wait step is followed directly by an email with no filter or split in between, that email sends once the wait completes, full stop, regardless of what happened to the customer during the wait.
Here’s the mechanism laid out with hypothetical, illustrative numbers: say a browse-abandonment flow triggers, waits four hours, then sends its first email. A shopper who was browsing checks out two hours into that wait. If there’s no filter or split sitting between the wait step and the email, the email still sends two hours after they’ve paid — the wait step did exactly what it was built to do, pause for four hours, and the flow had no other mechanism positioned to notice that the reason for the email had already disappeared. The fix isn’t a shorter wait step. It’s a filter or split placed between the wait and the send, checking the thing that would make the send wrong.
How long a wait step should run depends on how reliably the trigger event’s timestamp reflects reality. Waiting against an order-placed event is comparatively simple, because that event fires once and is cleanly timestamped at the moment of purchase. Waiting against a fulfilment or delivery milestone is harder, because those depend on carrier data reaching the store’s systems, which introduces its own lag that a fixed wait step can’t account for — a three-day wait step timed against “order placed” to approximate “package delivered” will be wrong for every order that ships from a different warehouse or hits a carrier delay. If it isn’t obvious which of your flows carry enough volume to justify the engineering time to fix this kind of timing gap first, the flow revenue calculator estimates how much revenue is moving through each flow from your own send numbers, rather than a guess.
Add the exit condition that removes someone who already bought
An exit condition checks, ahead of a remaining send, whether the reason the flow started still holds. Structurally it sits ahead of each send it protects — either as a filter attached to that specific email step, or as a flow-level rule evaluated before every remaining action, depending on which mechanism the account is built around. It never sits only at the start of the flow, because a condition checked once at entry tells you nothing about what’s true three days later.
The single most common gap: a cart or browse abandonment flow, or a win-back series, has no check against “has this person placed an order since entering,” so the flow keeps going on its own internal timeline even though the outcome it exists to produce has already happened. Here’s what that looks like on an ordinary Tuesday. Someone abandons a cart at nine in the morning. The flow’s second email is scheduled for hour twenty-four. They complete checkout at eleven, from a different device than the one that abandoned the cart. At nine the next morning, they get an email discounting the exact item they paid full price for twenty-two hours earlier. Nothing in the flow malfunctioned — every mechanism did precisely what it was configured to do. The configuration was simply missing a check.
The diagram shows where that check needs to sit: not as a second entry condition, but as a gate positioned between the wait step and each subsequent send.
The step most teams get wrong isn’t leaving the exit condition off entirely — most flows built by anyone with Klaviyo experience have some kind of exit rule. It’s scoping that rule to only one path a purchase can take. An exit rule watching for a standard placed-order event catches a normal checkout, but it can miss a subscription reactivation, a manually created draft order entered by a support agent, or a purchase completed through a sales channel that doesn’t fire the same tracked event Klaviyo is watching. Every one of those is still, from the customer’s point of view, “I already bought this” — and every one of them, if the exit rule only watches the default event, still gets the next email in the sequence.
Trigger types compared: entry, re-entry and fit
| Trigger type | Fires when | Re-entry to confirm | Best fit |
|---|---|---|---|
| List | A profile is added to a static list | Usually deliberate — check the list’s own add logic | Onboarding, welcome sequences |
| Segment | A profile starts matching segment conditions | Can re-fire if the profile leaves and re-qualifies | Ongoing lifecycle states |
| Metric (event) | A tracked event happens, such as an order being placed | Fires per instance unless filtered | Time-sensitive, single-event sequences |
The takeaway from the table: only an event-based trigger has an entry timestamp that lines up exactly with the moment the thing you’re reacting to actually happened. A list or segment trigger’s timing is a proxy for that moment, which is fine for a welcome flow and a real liability for anything where the wait step’s length matters, such as a post-purchase or abandonment sequence.
Verify the flow with a test profile before it goes live
Verification means pushing a test profile through every branch the flow can produce, not just the happy path. Enter the flow the same way a real customer would, then deliberately force the conditional split both directions — once meeting the condition, once not — and confirm each side ends where you expect. Temporarily shortening a wait step for the duration of a test run, then setting it back to the real value before publishing, is common practice and lets you see the downstream steps without waiting hours or days for each one.
The step worth testing specifically is the exit condition, because this is where assumptions cost the most. Enter the flow as the test profile, then complete a test purchase partway through — after the trigger but before the flow’s later sends. Watch what happens to the next scheduled email. Confirm directly, rather than assume, whether Klaviyo removes an in-progress profile from the flow once the exit condition is met, or only prevents new profiles from entering going forward. That distinction determines whether a profile already queued for the next step still receives it even after the exit condition became true, and it’s exactly the kind of behaviour that’s worth checking against current product documentation, since it affects every flow you build the same way.
One more thing worth verifying before launch: what the flow does with a profile that meets more than one branch condition at once — someone who both clicked the previous email and placed an order in the same window, say. Conditional splits evaluate in the order they’re built, so the first condition a profile matches wins, and it’s worth confirming that’s the order you actually intended rather than the order you happened to build the nodes in.
What changes when a flow has more than one exit-worthy event
A flow rarely has just one reason to stop mid-sequence. A win-back series built to re-engage a lapsed customer needs to exit on a new order, obviously, but it also needs to exit if the customer unsubscribes, if their account gets merged with another profile after a support ticket, or if a completely separate flow has already placed them into a “do not contact for 30 days” holding pattern. Building a single exit condition and assuming it covers every case that should stop the sequence is the same mistake as scoping the exit to only one purchase path, just applied to a wider set of events.
The practical approach is to list every event that should end the sequence before building the flow, not after a customer complains that they got a fourth email a week after they’d already asked to be left alone. Some of those events are easy to check directly, such as a placed order. Others require checking a status set elsewhere in the account, such as a suppression flag set by a different flow entirely, which means the exit condition for one flow can depend on state that another flow is responsible for maintaining. That dependency is worth documenting somewhere outside the flow builder itself, because nothing in the canvas shows it, and a change to the flow that sets the suppression flag can silently break the exit condition in every flow that reads it.
Structuring a Klaviyo workflow correctly is a lifecycle flows problem before it’s an email problem: the trigger, the split, the wait step and the exit condition all need to be built around the sequence of events a customer actually moves through, not around a single starting point and a hope that timing works out on its own. That’s the audit worth running on every flow currently live in an account — checking not whether it has an exit condition, but whether that exit condition is scoped to every path a customer can take to the outcome the flow is supposed to stop reacting to.
Sources
- Klaviyo, benchmark data across 183,000+ brands: 41% of email revenue attributed to automated flows (vendor-reported).