Back to Playbooks

Let Merchants Choose Their Own Adventure: A Preference-Center Journey That Actually Routes Traffic

Free

Walk through a complete Spreeflo journey that turns a Shopify app’s preference center into real routing logic, updating contact attributes and tags, reshaping onboarding and campaigns in near real time, and lifting engagement while protecting “billing only” merchants.

Industry

Niche

Pattern

Loading sequence...

CartWizard had a classic Shopify app problem.

They were doing “the right things”: welcome series, feature updates, best-practice playbooks, occasional promo pushes. All through a single broadcast list in their email tool.

Then high-value merchants started replying with some version of: “I only want critical updates and billing notices. Please stop the rest.”

The team added a basic in-app preference center. But under the hood it was just toggling booleans in their database. Their email tool still had one marketing list. Once a week, someone exported CSVs, filtered by columns like billing_only = true, and tried not to mess it up.

That manual layer is exactly where most teams leak trust and engagement. A merchant updates “billing only” on Monday, and still gets the Tuesday promo blast. They unsubscribe. Or worse, they churn.

The sequence at the top of this page is the whole journey, end to end, that fixes this: a preference-center-driven path selection journey that reroutes each contact’s marketing path within hours of any change.

In this article, we’ll walk through how a Shopify app like CartWizard wires their preference center into Spreeflo so that:

  • Every preference change fires a Custom Event.

  • The journey reacts within an hour.

  • Other automations and campaigns immediately respect the new intent.

And because you’re running a lean SaaS team, you build this once and let it run. No more weekly CSV surgery.

Why preference centers matter more for Shopify apps

If you sell a Shopify app, your audience is not generic “subscribers.” They’re operators running six or seven-figure stores, often on thin margins. Their inbox is full of:

  • Shopify announcements

  • Theme, plugin, and app updates

  • Vendor pitches

If your onboarding and marketing streams ignore their preferences, they do not patiently wait for you to get better. They mute, filter, or uninstall.

A preference center is your promise that you’ll only send what’s relevant. But that promise only holds if your marketing automation respects it quickly and consistently.

That’s the job of this journey:

  • Treat every preference as first-class customer data.

  • Route each contact into the right stream based on those preferences.

  • Keep that routing up to date whenever they change their mind.

Spreeflo gives you the pieces to do this properly: Custom Event triggers, the segment builder, branching nodes like Multi-way Split, and actions like Update Email Subscription Status and Add Tag. The flow you see in the sequence at the top of this page is one concrete way to assemble them.

Step 1: Turn preferences into structured contact data

Before you even touch the journey canvas, decide how you’ll store preferences on the contact.

For a typical e-commerce app, a clean pattern is:

  • A TEXT attribute email_pref_mode with values like billing_only, low_touch, standard.

  • A TEXT attribute email_frequency (weekly, monthly, never_marketing).

  • Topic-level tags such as topic-product-updates, topic-best-practices, topic-partner-offers.

Your preference center UI (inside the app or on a standalone page) should do two things whenever a user hits “Save”:

  1. Fire Spreeflo.track('email_preferences_updated', { ... }) so the event can trigger journeys.

  2. Call Spreeflo.identify(email, { email_pref_mode: 'billing_only', ... }) (or the equivalent via the Spreeflo API) to update those attributes and tags on the contact record.

That second step is important. The Update Contact Attribute node in Spreeflo cannot copy values from event payloads at runtime. It only writes static literals you set during design. So the system of record for “what did they choose?” must be your app or backend pushing attributes into Spreeflo, not the journey itself trying to infer it.

Once that’s in place, every contact has a durable, queryable picture of their preferences. Now the journey can react to it.

Step 2: Listen for changes with a Custom Event trigger

At the far left of the sequence is a Custom Event trigger:

  • Event name: email_preferences_updated

  • Re-enrollment: enabled (isReEnrollment=true)

You don’t filter by properties here. Any time a merchant changes their mind, they should re-enter the journey, even if they did it last week. That’s the whole point: the journey is the enforcement layer for “what they want right now.”

Spreeflo’s journey-level re-enrollment model means:

  • If re-enrollment is on for this trigger, the contact can go through the journey again after they’ve exited it.

  • While they’re mid-journey, duplicate enrollments are blocked so they don’t get interleaved actions.

That’s fine here because this journey is intentionally short. We want it to fire, make the necessary adjustments, and end. If a merchant toggles preferences twice in one afternoon, the most recent change will trigger the next pass through the journey as soon as they’ve exited the prior one.

At this point, every change is flowing into the journey in real time. Now we need to avoid overreacting to every click.

Step 3: Add a short Time Delay to absorb “flailing”

Immediately after the trigger, the sequence uses a Time Delay:

  • Duration: 1 hour

  • Unit: Hour(s)

Two reasons:

  1. Humans flail. They land on the preference screen, tick a few boxes, untick others, change their mind. A one-hour buffer lets that micro-session settle before you reshape their entire messaging experience.

  2. You still keep the promise of “within hours.” The minimum delay unit in Spreeflo is one hour, and for preferences, that’s a solid default.

If you know your customers rarely tweak settings more than once, you can shorten to the minimum. If you see a lot of back-and-forth during onboarding, bump to a few hours. Either way, this node ensures you don’t fire a cascade of Add Tag / Remove Tag / Update Email Subscription Status actions for every intermediate state.

Step 4: Branch on preference mode with a Multi-way Split

Next, the journey hits a Multi-way Split process node, which is where the real routing happens.

Each branch condition is defined with the segment builder, but instead of creating saved segments, you embed the criteria right in the node.

A typical setup for a Shopify app might be:

  • Branch billing_only
    - Condition: Contact Attribute email_pref_mode is billing_only.

  • Branch low_touch
    - Condition: Contact Attribute email_pref_mode is low_touch.

  • Branch standard
    - Condition: Contact Attribute email_pref_mode is standard.

  • Else branch
    - No condition. Catches anyone whose preferences are missing or unexpected.

Order matters in a Multi-way Split. Branches are evaluated top to bottom, so put the most specific conditions first. In this example, the three explicit modes are mutually exclusive, so any order is fine, but in more complex setups (for example, modes combined with plan type) you’ll want to pay attention.

Why Multi-way Split instead of a chain of If/Else nodes? Because preference modes are exactly the kind of thing that tends to grow over time. Maybe you add product_updates_only or partner_offers_only later. A Multi-way Split keeps that logic in one place instead of scattering it.

From here, each branch implements a different policy.

Step 5: Enforce “billing only” properly

When a merchant asks for “billing only,” they’re asking you to stop marketing to them, not to get a slightly different newsletter.

On the billing_only branch, the journey typically does three things:

  1. Use Update Email Subscription Status
    - Status: Email unsubscribed

  2. Normalize tags
    - Remove Tag: any marketing-topic tags such as topic-product-updates, topic-best-practices.
    - Add Tag: pref-billing-only.

  3. Do not send a marketing confirmation email
    For this branch, the contact has literally asked you to reduce noise. You can show a confirmation message in-app, but resist the urge to send “You’re unsubscribed” by email. The Update Email Subscription Status node already ensures they’re out.

After these branch-specific actions, the path connects into a Merge node that recombines all the branches, which we’ll come back to in Step 7.

Step 6: Tune “low touch” and “standard” streams

For merchants who still want marketing, just less of it, you use the other branches to tune their future path.

Low-touch branch

Here’s a common pattern for a low_touch branch:

  1. Update Contact Attribute
    - Attribute: email_frequency
    - Update type: Update
    - Value: monthly

  2. Add Tag
    - Tags: pref-low-touch
    - Optionally remove a previous pref-standard tag if you use one.

  3. Send Email
    - A single, clear confirmation: “We’ll only email you our best monthly highlights.”
    - The Send Email node’s “send only once” toggle is a judgment call. If you think merchants will bounce between modes occasionally, leaving it on prevents duplicate confirmations. If you prefer them to get a fresh summary every time they come back from billing_only, turn it off.

That confirmation email can be built quickly with Spreeflo’s email builder, and it doubles as a chance to set expectations: “No promos, just one roundup with key metrics and product improvements.”

The key is what you do elsewhere. Your monthly digest campaign should be a Cyclic journey or campaign that targets only contacts with:

  • Email subscription status is Subscribed.

  • Tag contains pref-low-touch.

  • Tag does not contain pref-billing-only.

Because this preference journey keeps those tags and attributes accurate, your digest campaign stays honest.

Standard branch

For standard mode, the actions are similar but tuned for higher engagement:

  1. Update Contact Attribute email_frequency to weekly.

  2. Add Tag pref-standard, remove pref-low-touch if present.

  3. Optionally Send Email summarizing the types of emails they’ll get.

You might also add topic tags here based on what they selected in the preference center (for example, topic-product-updates and topic-best-practices), though the actual assignment of those is usually done by your app via the API, not this journey.

Again, after branch-specific updates and the optional Send Email, the path flows into the same Merge node as the other branches.

Else branch: handle weird states

The else branch is your safety net for:

  • Contacts whose email_pref_mode attribute is blank.

  • Legacy data where values don’t match your current options.

  • Edge cases from partial migrations.

On this branch, a sensible pattern is:

  1. Send Internal Email to your team with the contact’s details so someone can check what went wrong.

  2. Optionally Add Tag pref-review so you can build a segment of “preference records that need cleanup.”

Then send this branch to the Merge node as well. The less time you have contacts sitting in ambiguous states, the better.

Step 7: Tag everyone who has ever set preferences

All the branches converge into a Merge node, which then leads into a simple Add Tag action:

  • Add Tag: has-updated-preferences

This tag serves two important roles:

  1. Targeting
    You can build one-off campaigns or journeys specifically for contacts who have not set preferences, nudging them to the preference center. For example, a Cyclic trigger that, once a month, emails active users without the has-updated-preferences tag and invites them to fine-tune what they receive.

  2. Analytics
    It’s the denominator for your “preference-update rate” metric. The higher this climbs among active subscribers, the more confident you can be that your list is self-optimizing instead of stuck in one-size-fits-all mode.

After this Add Tag, the journey ends. The heavy lifting happens not in this flow, but in how other automations and campaigns use the data it keeps clean.

How this journey reshapes every other email you send

A preference journey doesn’t live in a vacuum. It feeds everything else.

Some practical ways to wire that in:

  • For your onboarding journey (often triggered by Add to Audience), add an If/Else node right after the trigger:
    - Condition: Contact is not tagged with pref-billing-only AND Email subscription status is Subscribed.
    - “Yes” branch: send the normal onboarding series.
    - “Else” branch: skip marketing onboarding entirely or send a minimal “setup checklist” email.

  • For promos and launches, build your audience using the segment builder so it always excludes:
    - pref-billing-only
    - pref-low-touch if the campaign is high-frequency

  • For education content, create separate campaigns:
    - One for pref-standard with weekly tips.
    - One for pref-low-touch with a curated monthly digest.

All of that is possible only because you’re treating preferences as structured data tied to each contact record. Spreeflo’s campaign and journey automation then lets you consistently apply that same logic everywhere without reinventing it per send.

Measuring success: preference-update rate and CTR uplift

Two numbers tell you whether this pattern is doing its job.

1. Preference-update rate

Define three simple saved segments:

  • “All active contacts” (however you define active: recent logins, recent installs, etc.).

  • “Has updated preferences” (tag contains has-updated-preferences).

  • “Active with preferences” (intersection of the two).

The size of “Active with preferences” divided by “All active contacts” is your preference-update rate. CartWizard saw this climb to about 55% of paying accounts within a quarter once they started nudging non-preference users toward the center.

The closer this gets to 100% among your best-fit customers, the less guesswork you’re doing.

2. Downstream CTR uplift

To see whether this translates into engagement, compare:

  • Click-through rate on a few key campaigns for contacts with has-updated-preferences.

  • The same campaigns for contacts without that tag.

You can either:

  • Create two saved segments and send the same campaign to each.

  • Or use a Random Split node inside a journey to keep a 10% holdout that ignores preference topics temporarily (for example, it still respects billing_only but not content topics), then compare behavior via Check Email Activity.

When CartWizard wired their promos to respect both frequency and topics, CTR among “has-updated-preferences” contacts was about 30% higher than the rest. Unsubscribes also dropped noticeably, but the real win was more clicks from people who actually cared.

That’s the compounding effect you’re after.

Why this pattern quietly grows LTV for Shopify apps

Preference centers are easy to treat as a compliance checkbox. “We have a page, we’re good.” For a Shopify app business, they’re more than that. They’re how you prove to busy merchants that you see them as individuals with different tolerances and interests.

Spreeflo’s model is to capture detail on every customer so you can speak to each uniquely. A preference-center journey like the one in the sequence at the top of this page is a very literal expression of that idea:

  • Your app records what they want.

  • Spreeflo listens, updates their profile, and routes them.

  • Every future message “remembers” that choice without extra work from your team.

You keep your promise at scale, and you do it with one small, well-structured journey instead of constant manual list surgery. For a lean, founder-led SaaS team, that kind of automation is exactly what helps you punch above your headcount.