Home Blog Contact
Home/Blog/Why Repeat Buyers Stay Stuck in Your Welcome …
How toKlaviyoKlaviyoWelcome FlowRetention

Why Repeat Buyers Stay Stuck in Your Welcome Flow

10 min readBy Miloš Mitrović

When loyal customers keep receiving your new subscriber welcome series, the cause is almost always the gate rather than the flow logic. Entry and exclusion are keyed on a profile property (something like customer_type or first_purchase_complete) that was written once at signup and never rewritten when the second order landed. The diagnostic is a join: pull everyone who received welcome message two or later in the last 90 days, compare that list against order count in Shopify, and count the profiles with two or more orders. If that number is above a fraction of a percent, your gate is stale and you are paying for it in margin.

Key takeaways

  • Custom profile properties do not refresh themselves. A property set by an import, an app, or a one time backfill will still say "new" after the fifth order.
  • Gate on a metric count (Placed Order zero times since the beginning of time), not on a property that something else is responsible for updating.
  • Trigger filters run once at entry. Flow filters run before every step. Putting the purchase exclusion only in the trigger means anyone who buys mid series keeps getting first purchase offers.
  • Sometimes the order data is genuinely missing: second sales channel, guest checkout under a different email, dropped webhooks. Fix the data before you fix the flow.
  • Measure the leak as a rate (repeat buyers reached divided by total recipients per message), then watch it after the rebuild rather than trusting the config.

What the failure actually looks like in the account

The visible symptom is a customer with eight orders replying to ask why you are offering them 15 percent off their first purchase. Underneath, one of three things is true. The profile entered the welcome flow before its first order and never left, because the flow has no per step exclusion and the delays run 21 days. Or the profile re enters on every list subscribe (a popup refill, a checkout opt in, a giveaway import) and the exclusion property still reads as new. Or the profile never had a correct value in the first place because the property is written by an integration that only fires on profile creation.

None of these show up in flow level reporting. Open rate and click rate on a welcome series that reaches repeat buyers usually look good, because repeat buyers engage. Revenue per recipient looks good too, because those customers were going to order anyway and the discount code attaches itself to the purchase. The flow appears to be one of your strongest performers while it quietly subsidises orders you would have received at full price and trains your best segment to wait for a code.

The 20 minute diagnostic that names the offender

Start from the recipient list, not the flow builder. Pull the message level recipients for each step of the welcome series over a 90 day window, then join on order count. In Klaviyo you can enumerate the flow and its actions through the Flows API (developers.klaviyo.com/en/reference/get_flows) to get stable message IDs, and read the property values on each profile through the Profiles API (developers.klaviyo.com/en/reference/get_profiles). For the order side, the Shopify Admin GraphQL customer object exposes a lifetime order count and total spend per customer (shopify.dev/docs/api/admin-graphql/latest/objects/Customer), which is the number you trust over anything cached in the email platform.

query CustomerOrderCounts($cursor: String) {
  customers(first: 250, after: $cursor) {
    edges {
      cursor
      node {
        id
        email
        numberOfOrders
        amountSpent { amount currencyCode }
      }
    }
    pageInfo { hasNextPage }
  }
}

Then produce one table. Rows are welcome messages one through five. Columns are total recipients, recipients with zero orders at send time, recipients with one order, recipients with two or more. The shape of the numbers tells you which failure you have.

Pattern in the tableWhat it means
Repeat buyers appear in message oneEntry is wrong. The trigger or trigger filter is not excluding customers, or a segment trigger is re adding them.
Message one is clean, messages three and later are notThe exclusion is a trigger filter only. People buy mid series and stay in it.
Repeat buyers spread evenly across all messagesThe gate reads a property, and the property is stale for a whole cohort (usually an import or an app installed at a known date).
Small, scattered, mostly high value customersIdentity or event data problem, not flow logic. Go look at duplicates and missing events.

If you are already running a broader flow audit, this joins naturally onto the same recipient extract you would build for a flow double sending audit, because both questions come from the same table of who received what and when.

Why a profile property is the wrong thing to gate on

A property is a value that some system is responsible for keeping current. Ask who that system is and the answer is often nobody. Common sources of a permanently stale value:

  • A one time backfill. Somebody exported customers, tagged them customer_type = repeat or new, and imported the CSV. That value is a photograph of a single afternoon.
  • An update profile action inside another flow. It only fires for profiles that reach that step, which excludes everyone who unsubscribed, skipped, or was in a different flow.
  • A third party app property. Loyalty, reviews, and subscription apps often write a property on install and on signup, not on every order.
  • A property set from the popup itself. Signup source properties describe how someone joined, and people read them as customer state, which they are not.

Metric counts do not have this problem. A condition like "Placed Order zero times since the beginning of time" is computed against the event stream at evaluation time, so it is correct the moment the order event arrives. Properties are convenient for content personalisation and dangerous for eligibility. Use them for the former only.

Trigger filters, flow filters and conditional splits do different jobs

This is the distinction that fixes most of these accounts. A trigger filter is evaluated once, at the moment of entry, and decides whether the profile joins the flow at all. A flow filter is evaluated again before every subsequent step, and removes profiles that no longer qualify. A conditional split does not remove anybody, it routes them down a different path. Operators who put the purchase exclusion in the trigger filter and nowhere else have built a flow that is correct for exactly one instant per profile.

With a 21 day welcome series and a store whose median first to second order gap is under 30 days, the mid series purchase is not an edge case, it is a meaningful share of your entries. Every profile that buys on day two and then sits through three more first purchase pushes is a customer learning that your emails contain codes.

When the order data itself is the problem

Before you rebuild anything, rule out the case where the flow is behaving correctly on wrong inputs. Four sources to check, in the order they usually bite:

  1. A second sales channel. POS, Amazon, a subscription app that creates orders through its own path, or a wholesale portal. If those orders never produce a Placed Order event, the customer genuinely has zero orders as far as the email platform knows.
  2. Identity split. Guest checkout with a work address, a typo, or a plus alias creates a second profile. The order count is right, it just lives on the other profile. This is the same root cause you chase when you find and merge duplicate Shopify customers.
  3. Dropped events. Webhook delivery is retried but not guaranteed to arrive in order or at all, and Shopify documents the delivery and retry behaviour for its topics (shopify.dev/docs/api/webhooks). A quiet gap in Placed Order events shows up later as customers who look new. Reconciling those gaps is its own exercise, covered in webhook driven event loss.
  4. Refunds and cancellations. Decide explicitly whether a cancelled first order should make somebody eligible again. Most stores should say yes, but say it on purpose.

If your platform order counts and your store order counts disagree in aggregate, fix that first. The revenue reconciliation exercise surfaces the same gaps from the money side.

The rebuild, step by step

Rebuild the gate in four moves and leave the creative alone until the plumbing is correct.

  1. Replace the property gate with a metric gate. Trigger filter: has placed order zero times since the beginning of time. This stops new entries from customers you already have.
  2. Add the same condition as a flow filter. Now it is re evaluated before every message, so anyone who buys on day two leaves the series instead of receiving the rest of it.
  3. Split the incentive out of the sequence. If your welcome series carries a first purchase code, put a conditional split immediately before that message so a customer who somehow reaches it gets the brand or product education version instead of the code. Belt and braces, and it costs you one branch.
  4. Give buyers somewhere to go. A profile removed from the welcome flow should land in post purchase onboarding, not silence. This is the handoff most stores miss, and it is where the sequencing thinking in flow level revenue design pays off.

One detail worth setting deliberately: put at least an hour of delay between entry and the first message when your popup fires on product pages. Someone who subscribes for the code and checks out four minutes later will otherwise receive welcome message one after they have already bought, and no amount of filtering can catch a send that was already in flight.

Cleaning up the customers you already hit

Do not send an apology broadcast. Pull the list of repeat buyers who received a first purchase code in the last 60 days and check redemption. Customers who never redeemed need nothing, and telling them about the mistake only advertises that a code existed. Customers who redeemed already have their discount, and clawing it back costs more goodwill than the margin is worth.

What does need action is the code itself. If your welcome code is a static, shared, unlimited use code, the leak has probably escaped into browser extensions and coupon sites, in which case the fix is unique codes per profile with an expiry rather than tighter flow filters. The same staleness pattern shows up on the other end of the lifecycle, where winback flows keep emailing customers who already came back, and it is worth auditing both gates in the same sitting since they usually share the offending property.

Trade offs and what I would do

The argument for property based gating is speed of evaluation and simplicity in the builder. Metric conditions evaluated at every step do more work, and on very large lists you will notice flows processing slightly slower. That has never once been the deciding factor in an account I have worked in. Correctness of eligibility beats a few seconds of processing latency every time.

The second trade off is strictness. Gating on "zero orders ever" means a customer who bought once in 2021, went quiet, and just resubscribed will never see the welcome series. Some operators want that person to get a reintroduction. My recommendation: keep the hard gate at zero orders ever, and build a separate reactivation series for lapsed buyers with its own creative and no first purchase framing. Two clean flows beat one flow with clever conditions, because the clever conditions are what broke in the first place.

The third is the mid series exit. Removing a buyer from the welcome flow means they stop getting your brand story, which for a considered purchase category is content you actually want them to read. If that describes your store, do not remove them, route them. Keep the flow filter for the discount messages only and let the education messages continue down a branch that drops the incentive language. That is more work to maintain and it is the right call for higher AOV catalogues.

Whatever you choose, instrument it. Add the repeat buyer leak rate per message to whatever weekly numbers you already look at, and set a threshold you would investigate. Configuration decays, properties go stale, apps get reinstalled, and the only thing that catches the next instance of this is a number somebody reads.

Sources

M
Miloš Mitrović
Email Marketing for Ecommerce

Have a question or a project?

Whether it is about this post or a system you want built, I'm happy to talk.

Get in touch

404

Post not found. It may have been moved or the link is incorrect.

← Back to the blog
Summarize with AI
ChatGPT, Perplexity, and Grok open with the prompt ready to run. Claude, Gemini, and Copilot open a chat with the prompt copied; press Ctrl+V (Cmd+V on Mac) to paste. The full text is included, so it works even without web access.