Reed Iredale Reed Iredale Nav:
← All posts

Your Klaviyo Flows Are Guessing. One Custom Property Can Make Them Stop.

Most Shopify brands run a dozen Klaviyo flows and every single one is making the same bet: that the offer baked into the template (10% off, free shipping, "here's a discount") is the right offer for whoever happens to land in that flow next. It isn't. It's the right offer for nobody in particular, sent to everybody, because nobody built the machinery to do anything smarter.

There's a fix that doesn't require rebuilding your flows: stop hardcoding the offer inside each flow, and start writing a single next_offer custom property onto the Klaviyo profile, then let every flow, campaign, and on-site element read from that one field.

What

next_offer is a Klaviyo custom property that holds the single best offer for a given contact at this moment, something like free_shipping, 10_percent, bundle_upsell, or early_access. It's not a discount code. It's a decision, computed once and stored on the profile, that every downstream send can reference with {{ person.next_offer }} instead of a static block of copy.

The automation is the piece that keeps that field current: a job that looks at what you know about a contact, browsing behaviour, cart history, purchase history, discount usage, and anything you've captured directly from them, and writes an updated value back to Klaviyo whenever something meaningful changes.

That last input is the part most stores are missing. Klaviyo, out of the box, mostly knows email address and order history. It doesn't know that a visitor said they're shopping for a gift, or that they're price-sensitive, or that they came in looking for a specific product variant you don't have on the homepage. Tools like Better Segment exist specifically to capture that zero-party data on-site and push it into Klaviyo as a real-time custom property, which is exactly the raw material a next_offer model needs to be worth building in the first place.

Why

Right now, your welcome flow, your abandoned cart flow, your browse abandonment flow, and your win-back flow are each independently guessing what will move someone to buy, and none of them are talking to each other. That causes two expensive problems.

First, discount leakage. A chunk of your list would have bought at full price. Every flow that defaults to "10% off" is giving away margin to people who never needed the nudge.

Second, offer collisions. Someone abandons a cart and is sitting in your win-back flow and just triggered a browse-abandonment email, and now they've received three different, uncoordinated offers in 48 hours, which either trains them to wait for a fourth or just looks sloppy.

A single next_offer property collapses this into one decision, computed centrally, applied everywhere. Change the logic once, and every flow gets smarter at the same time, instead of hunting through a dozen flow builders trying to remember which one has which discount hardcoded into which email block.

How

1. Get the signal into Klaviyo. Layer zero-party data on top of what Shopify and Klaviyo already track. On-site pop-ups and micro-questions ("Shopping for yourself or a gift?", "What's stopping you from buying today?") answer questions your behavioural data can't. Better Segment's whole model is mapping those answers straight to a Klaviyo profile property in real time, no export or batch delay, which is what makes the next step possible without building your own data pipeline first.

2. Build the offer logic. This doesn't need to be a machine learning model. A rules table gets you most of the value:

  • High intent, no discount history, browsed a specific product twice: free_shipping (protects margin, still removes friction)
  • Cart abandoned, previously used a discount code: 10_percent
  • Repeat customer, high LTV, browsing a new category: early_access or bundle_upsell
  • Said "just browsing" on-site and low engagement: no offer yet, nurture content instead

3. Automate the write-back. Whenever a triggering event fires (a pop-up answer, a cart event, a scheduled nightly re-score), run the logic and update next_offer via the Klaviyo API, or through whatever's already syncing your zero-party data in real time. This is the part that turns it from a one-off segment into a living automation: the property should never go stale.

4. Point every flow and campaign at the same field. Replace hardcoded discount blocks in your emails with {{ person.next_offer }}-driven content blocks. Do the same on-site, so the offer someone sees in a pop-up matches the offer waiting in their inbox. One source of truth, everywhere the customer touches the brand.

5. Add guardrails. An expiry timestamp so a stale offer doesn't linger for months. A simple priority order so two flows firing at once don't stack conflicting offers. And a holdback group, a slice of contacts who get no personalised offer, so you can actually prove the lift instead of assuming it.

Result

Done properly, you get three things static, per-flow discounting can't give you:

  • Offers that match the customer, not the flow. The same person gets a consistent, appropriate offer whether they're in a welcome series, a cart recovery email, or looking at a pop-up on the homepage.
  • Margin recovered from people who didn't need a discount. Full-price buyers stop getting trained to wait for 10% off.
  • One place to get smarter. Improving the targeting logic once improves every flow that reads from it, instead of manually updating a dozen email templates every time you learn something new about what converts.

None of this requires ripping out your existing flows. It requires one new field on the Klaviyo profile, a decision layer that keeps it current, and a data source, zero-party, on-site, rich enough to make the decision worth automating.