Back to Playbooks

Turn Usage Caps Into Upgrade Conversations: A Freemium Handoff Journey for Shopify Apps

Free

A detailed journey for Shopify apps using Spreeflo to turn "usage limit reached" moments into automated, personal upgrade flows, coordinating emails and internal alerts to capture more freemium-to-paid revenue and distinguish self-serve from sales-assisted expansions.

Industry

Niche

Pattern

Loading sequence...

Your Stripe dashboard shows a familiar pattern.

installs are steady. Active usage is up. But MRR barely moves.

When you dig into the logs, you see it: a big chunk of free-plan stores are hitting their usage cap, getting blocked in-product, then quietly churning without ever upgrading or talking to you.

For a Shopify app like CartWizard (fictional, $90k MRR, cart recovery + post‑purchase upsells), that’s thousands in expansion ARR leaking every month. Their stack is pretty standard: Ruby backend, Shopify Admin API, Stripe, Intercom, Mailchimp. All their “upgrade” logic lives inside the app wall. Once a store owner closes that tab, there’s no follow‑up.

The sequence at the top of this page is the whole journey, end to end. It turns “usage limit reached” into an automated yet personal handoff to sales, so high‑intent free users either upgrade themselves or hear from a human at exactly the right moment.

This article walks through that journey node by node using Spreeflo: how to trigger on behavior, when to message the user vs your team, and how to track which upgrades were self‑serve vs sales‑assisted.

Why usage caps deserve their own playbook

A free user hitting a usage limit is not a generic marketing lead. It’s one of the highest‑intent signals you’ll ever get:

  • They’ve installed and configured your app.

  • They’ve used it enough to max out the free allowance.

  • The cap is now actively blocking something they want: more recovered carts, more reports, more automations.

Most apps handle this only with an in‑app paywall. That works for a slice of people who are in “I’m ready to upgrade right now” mode. Everyone else postpones, gets busy, and never comes back.

The gap is everything that happens after that moment. That’s where this behavior‑driven handoff lives:

  1. Detect when a free store hits the cap.

  2. Send a tailored upgrade email while the pain is fresh.

  3. Alert your team with context so they can reach out personally.

  4. Wait for self‑serve upgrades before sending a follow‑up or escalating.

  5. Tag and attribute upgrades so you can quantify sales‑assisted vs self‑serve revenue.

You build this once as a journey in Spreeflo, and it quietly works for every free store that crosses the line. That’s founder‑level leverage.

What this journey does at a glance

Before we go node by node, here’s the behavior in plain English:

  • A backend event like usage_limit_reached comes into Spreeflo for a free‑plan user.

  • Spreeflo tags the contact into an “upgrade pipeline,” checks if you’re allowed to email them, and:
    - Sends them a personalized “you’ve hit the cap, here’s the benefit of upgrading” email if they’re subscribed.
    - Always sends an internal email with full context to whoever owns sales.

  • The journey then waits up to 48 hours to see if they upgrade on their own.

  • Upgraders get a quick “welcome to paid” email and are tagged as converted from freemium.

  • Non‑upgraders are split by value (for example, store size) and either:
    - Get a human follow‑up plus a more targeted second email, or
    - Get a lighter final nudge, then exit.

All of that is driven by a handful of nodes: Custom Event, If/Else, Add Tag, Time Delay, Wait Condition, Multi‑way Split, Send Email, Send Internal Email, Remove Tag, and Update Contact Attribute.

Let’s walk it.

Step 1: Trigger on the exact moment a free user hits the wall

The journey starts with a Custom Event trigger configured on something like usage_limit_reached.

In your app, when a free store attempts to send the 501st abandoned cart sequence or generate their 101st report, your backend calls the Spreeflo API with that event for the account owner’s email:

  • Event name: usage_limit_reached

  • Properties: plan = "free", limit_type = "emails", current_usage = 500, etc.

In the Custom Event trigger:

  • Event name: usage_limit_reached

  • Add property conditions: on
    - plan is "free" (so you don’t pester paying customers)
    - Optionally limit_type is one of the caps you care about for this flow

  • Re-enrollment: on

Re‑enrollment is important here. You want this journey to run again the next time the same store hits a cap on a new cycle, as long as they’re still on the free plan. Spreeflo will ignore duplicate events while the contact is mid‑journey, so you won’t get parallel enrollments.

Immediately after the trigger, add an Add Tag action:

  • Tags: usage-cap-hit, freemium-upgrade-pipeline

  • Force tag trigger: off (you’re not using downstream Added Tag triggers here)

This simple tag is gold later when you build reports or segments like “Free users who hit the cap but never converted.”

Brand message in action: you’re capturing fine‑grained behavior on every contact, not just “is free / is paid”.

Step 2: Only email people you’re allowed to talk to

Next, you branch with an If/Else process node to handle consent.

Condition (built with the segment builder):

  • Email Subscription Status is “Subscribed”

Yes branch: you’re allowed to send marketing email.
Else branch: they’ve unsubscribed or never opted in.

Why do this here?

  • You avoid sending a marketing upgrade email to someone who has opted out.

  • You still want sales to know that a high‑intent free user hit a cap, even if you can’t email them. That might turn into an in‑app chat, a partner intro, or nothing — but at least it isn’t invisible.

Everyone, regardless of branch, already has the usage-cap-hit tag from Step 1. That means your reporting and win‑back campaigns later don’t have holes.

Step 3: Send a helpful upgrade prompt, not a punishment

On the “Subscribed” branch, you drop a Send Email action.

Configuration:

  • Use “Send only once” turned on. Even if they somehow re‑enter the journey in the future, this specific email won’t go out twice.

  • Build the content with Spreeflo’s email builder so it’s responsive and easy to personalize.

What goes in this email?

  • A clear subject anchored in their behavior:
    “You’ve recovered 500 carts. Ready to recover 5,000?”

  • A quick recap of what they’ve achieved on the free plan (using contact attributes your app updates over time, like “carts_recovered_last_30_days”).

  • A simple explanation of the cap and what upgrading unlocks in business terms, not feature bullets.

  • A single, prominent call to action that deep‑links to your app’s billing/upgrade screen.

Because Spreeflo keeps this contact’s attributes on one record, you can personalize this email to speak to each store uniquely: currency, recovered revenue, key feature used. That’s a direct lift of Brand Message 1.

Right after this Send Email:

  • Add an Update Contact Attribute node to set something like upgrade_stage to the literal text "limit_email_sent".

  • This is a static marker; you’re not pulling values from events here, just writing a consistent stage string across all contacts who hit this step.

That attribute gives you a clean way to measure later: “What’s the conversion rate from ‘limit_email_sent’ to ‘paid’ within 14 days?”

Step 4: Give your team the full story for a smart follow‑up

Still on the “Subscribed” branch, follow up with a Send Internal Email action.

Configuration:

  • Template name: “Usage cap hit – subscribed”

  • Send only once: on

The internal email should include:

  • Who: the store owner’s name, email, Shopify store URL.

  • What: which plan they’re on, what cap they hit, and their key usage metrics (again, fed as contact attributes from your app).

  • When: timestamp of the usage_limit_reached event.

  • Link: a direct link to their account in your admin, so sales can quickly review context before reaching out.

On the “Not subscribed” branch from Step 2, you skip the customer email and just send a similar internal email (“Usage cap hit – cannot email”) so the team can choose a different outreach channel if it’s worth it.

After these internal alerts, both paths rejoin through a Merge node. From this point on, all cap‑hit users flow through the same logic.

This is founder‑leverage in practice: one journey keeps your tiny team in the loop on every high‑intent free user without anyone watching logs or dashboards.

Step 5: Wait for self‑serve upgrades before pushing again

Once both branches merge, add a Wait Condition action.

Condition (built with the segment builder):

  • Either:
    - Custom Event subscription_upgraded triggered at least 1 time in the last 2 days,
    or
    - Segment Membership is “Paying customers”

Timeout: 2 days
Unit: Days

This node does two things:

  • If they upgrade quickly after hitting the cap (either via your email CTA or in‑app), they’ll satisfy the condition and move on as soon as that happens.

  • If they don’t upgrade, they trickle out of the Wait Condition after 48 hours when the timeout expires.

Right after the Wait Condition, drop another If/Else process node with essentially the same condition:

  • Yes branch: they’re now a paying customer.

  • Else branch: they’re still freemium and over the cap.

Using both the Wait Condition and the If/Else like this gives you a clean way to send different follow‑ups without hammering people who already converted.

Step 6: Treat upgraders and holdouts differently

Path A: They upgraded — reinforce the win

On the “Upgraded” branch:

  1. Add Tag: upgraded-from-freemium, limit-hit-converted

  2. Update Contact Attribute: set upgrade_path to "usage_cap_journey"

Now you have explicit markers tying this revenue to the journey. That’s what lets you, six months from now, compare “All paid users” vs “Paid users who came through the usage‑cap handoff”.

Before sending another customer‑facing email, insert a small Time Delay:

  • Time Delay: 1 hour, unit “Hour(s)”

This keeps a reasonable gap between the original upgrade prompt and the next message, even if they upgrade immediately.

Then add a second Send Email:

  • Content: a short “Welcome to [Plan Name]” message:
    - Confirm their new plan and billing details.
    - Highlight the 2–3 features they now have access to that map to their existing behavior.
    - Offer a quickstart checklist or a link to your docs.

Because all of this is still one journey, you don’t have to wire yet another “welcome to paid” automation elsewhere unless you want to.

Path B: They didn’t upgrade — split by value

On the “Still free” branch from the If/Else, drop a Multi‑way Split process node.

You’re going to separate high‑potential stores from everyone else, using whatever attributes you already track via your app and push into Spreeflo:

  • Branch 1 “High value”:
    - Custom attribute monthly_orders greater than 1,000
    or segment membership “Large stores”.

  • Else branch: everyone else.

On the “High value” branch:

  1. Send Internal Email: “High‑value freemium stuck at cap”
    - Include stronger guidance: “Pick this up this week” for the account owner.

  2. Time Delay: 1 day.

  3. Send Email: a more tailored second nudge to the store owner:
    - Reference their scale and the revenue impact of staying capped.
    - Possibly offer a short onboarding call or migration help.

On the Else branch:

  1. Time Delay: 3 days (you don’t want to crowd inboxes for smaller accounts).

  2. Send Email: a lighter follow‑up:
    - Remind them what they’re missing.
    - Offer a limited‑time incentive if that fits your pricing strategy.

In both branches, you can also:

  • Add Tag: second-upgrade-email-sent

  • Optionally Update Contact Attribute: upgrade_stage = "post_wait_followup"

That gives you a way to later slice “people who got only the first email” vs “people we also chased a second time.”

After those sends, use a Merge node to bring both branches back together and end the journey.

You’ve now respected pacing (there’s at least a Wait Condition or Time Delay between every customer email), used behavior to decide who deserves extra human attention, and avoided nagging people who already upgraded.

Measuring free‑to‑paid lift and sales‑assisted impact

This pattern was tagged with two key metrics: free‑to‑paid conversion, and sales‑assisted vs self‑serve revenue. The journey you just saw sets you up for both.

Here’s how to get useful numbers out:

  • Build a segment in Spreeflo for “Free users who have tag usage-cap-hit and later joined segment ‘Paying customers’ within 14 days.” That’s your cap‑triggered conversion rate.

  • Within that, slice by upgrade_stage or tags:
    - Only limit_email_sent + no “post_wait_followup” tag → mostly self‑serve upgrades.
    - Has post_wait_followup tag or lives on the “High value” branch → more likely sales‑assisted or at least sales‑influenced.

You can refine this further by using Email Activity filters in the segment builder to track who clicked the upgrade link in the first email vs who never touched it.

The point is not to get perfect attribution. It’s to have enough structure that, when you look back over a quarter, you can say:

  • “This one journey created 27 new paying stores worth $X in ARR.”

  • “Of those, 9 went through the high‑value branch and were worth extra human effort.”

That’s exactly how a small Shopify‑app team decides whether to invest more in sales, more in self‑serve polish, or both.

Adapting the pattern to your own app

Some ways to tweak the sequence at the top of this page to fit your product:

  • Different triggers: if you don’t have a single usage cap, you can substitute a Criteria Match trigger that fires when total_events_last_30_days > X for free users. The mechanics of the journey stay the same.

  • Multiple caps: run one journey per product line or cap type (emails sent, seats used, orders processed) with slightly different copy and thresholds.

  • Platform‑specific messaging: use custom attributes for “primary use case” or “industry” and refs in your email templates so a fashion store and a supplements brand get different upgrade examples. AI‑assisted personalization in Spreeflo’s editor can help you do this at scale without hand‑writing every variant.

  • Reporting comfort: if you’re still getting used to journeys, you can start with a simpler version: trigger, tag, one upgrade email, one internal email, one Wait Condition. Once that’s performing, add the value‑based Multi‑way Split and second‑touch flows.

However you adapt it, build it as a reusable journey using campaigns and journeys instead of a one‑off campaign. High‑intent behavior like “usage limit reached” happens all the time; your automation should, too.

Why this earns its place in your stack

For e‑commerce apps and Shopify plugins, growth rarely comes from one magic acquisition channel. It comes from systematically capturing more value from the installs you already have.

This free‑to‑paid handoff journey is a textbook example:

  • You capture detailed behavior on every store — exactly when they struggle with your free limits.

  • You respond with targeted, timely messages unique to that store’s usage and value.

  • You bring humans in only where they add the most leverage instead of hiring a room full of SDRs to spray generic outreach.

That’s the heart of good marketing automation for founder‑led SaaS: build a system once that treats every customer like an individual and then runs quietly in the background while you go back to shipping.

And because Spreeflo gives you the event tracking, journey builder, internal alerts, and email tooling in one place — at pricing that doesn’t explode as you grow — this isn’t a huge project. It’s an afternoon of thoughtful setup that can pay you every month.