Back to Playbooks

The SEO SaaS “Next-Best-Offer” Journey That Quietly Lifts Expansion MRR

Free

Playbook showing SEO SaaS teams how to build a behavior-driven next-best-offer journey in Spreeflo, using events, segments, and targeted email paths to turn single-module customers into multi-module accounts and quietly grow expansion MRR and LTV.

Industry

Niche

Pattern

Loading sequence...

Most SEO SaaS products have a quiet plateau: customers buy one core module, stick with it, and never touch the rest of your stack. Your LTV stays flat, even while you keep shipping features.

The sequence at the top of this page is the whole journey, end to end. It shows how a tool like “RankForge” (our fictional SEO SaaS: rank tracking, content briefs, and technical audits at ~$60k MRR) turns single-module customers into multi-module accounts with a simple, behavior-driven cross-sell.

This is a playbook for that: a next-best-offer journey that uses actual usage patterns and purchase history, not a blanket “try everything” upsell.

Why next-best-offer beats generic “upgrade” banners

RankForge’s numbers look good at a glance:

  • Healthy trial volume

  • Decent trial-to-paid conversion

  • Agencies sticking around a few months

But when they broke down the data, two things jumped out:

  • Accounts using two or more modules had 40–60% higher LTV than single-module accounts.

  • Most customers never even tried a second module.

Their “cross-sell” was a single generic email: “Did you know we also do content briefs and audits?” Open rates were fine. Conversion was almost zero.

The problem: no context. Agencies who lived in rank tracking saw no reason to care about content briefs. Content teams who loved briefs did not wake up wanting a crawling engine.

A next-best-offer journey fixes that by doing two things:

  1. Capturing detail on how each customer actually uses the product (brand message 1).

  2. Using that detail to nurture them into the one adjacent feature that makes obvious sense for them (brand message 3: plugging the LTV leak).

Let’s walk through how to build that journey in Spreeflo.

The data you need before you build the journey

Before you drag a single node, you need enough detail on each account to make a smart cross-sell decision.

RankForge tracks four key behaviors and one purchase signal:

Purchase / subscription events:

  • subscription_started or plan_upgraded with plan name, billing term, and seat count.

Activation and usage events:

  • rank_check_run when someone checks keyword rankings.

  • content_brief_generated when they create a brief.

  • site_audit_run when they run a technical audit.

Implementation wise:

  • In the web app, the frontend calls Spreeflo.track('rank_check_run', { … }), Spreeflo.track('content_brief_generated', { … }), and Spreeflo.track('site_audit_run', { … }) whenever those features are used in the browser.

  • When Stripe or Paddle sends a successful payment or upgrade webhook, RankForge’s backend posts a subscription_started or plan_upgraded event to the Spreeflo events API. You can see the exact POST shape in the Spreeflo API docs.

They also maintain a few contact-level attributes in Spreeflo:

  • current_plan (Starter, Pro, Agency)

  • seats (number)

  • Tags like owns_rank_tracker, owns_content_briefs, owns_site_audit

Those attributes can be upserted either from the app (via Spreeflo.identify) or server-side via the same API.

With that in place, you can use the segment builder to distinguish three practical cohorts:

  1. Rank-first: heavy rank checks, no content briefs, owns rank module.

  2. Content-first: lots of briefs, few or no audits, owns content module.

  3. Audit-first: lots of audits, few rank checks, owns audit module.

Each cohort has a different obvious “next best” offer. That is the backbone of the journey.

Step 1: Decide when someone becomes cross-sell ready (triggers)

This is a journey, not a one-off campaign, so you’ll build it in the journeys section. If you’ve never built one before, the overview of how to build a journey is useful context.

In the sequence at the top of this page there are two entry points:

  1. Custom Event trigger: “New purchase”

  2. Criteria Match trigger: “Mature single-module account”

Trigger A: Custom Event (purchase)

Add a Custom Event trigger listening for subscription_started and plan_upgraded. Set:

  • Event name: subscription_started (add a second trigger for plan_upgraded if you like).

  • Property conditions: plan is not Trial, status is Active.

  • Re-enrollment: on (true), because a customer might upgrade from Starter → Pro → Agency over time and you often want a fresh cross-sell after each step.

Every time a paying subscription starts or upgrades, the customer enters this journey from that trigger.

Trigger B: Criteria Match (usage-based opportunity)

Some accounts won’t change plan for a while but will clearly show “ready for more” behavior. For that, add a Criteria Match trigger:

Criteria (using the Segment Builder):

  • Tag contains customer

  • AND custom event rank_check_run triggered at least 10 times in the last 30 days

  • AND tag contains owns_rank_tracker

  • AND tag does not contain owns_content_briefs

  • AND custom event content_brief_generated has not triggered in the last 30 days

That is your “Rank-first, content opportunity” cohort. You can add similar Criteria Match triggers for “Content-first, audit opportunity” and “Audit-first, rank opportunity” or keep it simple and start with one.

Re-enrollment here is usually off (false). Once you’ve attempted to cross-sell this specific adjacent product, you do not want to re-enroll that customer into the same path over and over. You’ll enforce that further with tags later.

Remember the re-enrollment rule in Spreeflo: once a contact has completed this journey, any trigger with isReEnrollment=false will ignore them in future. The purchase triggers have re-enrollment on; the usage-opportunity triggers usually keep it off.

Step 2: Give new customers a short value window

From the purchase trigger path, you do not go straight into “buy more stuff.” New customers need to feel value first.

Add a Time Delay after the purchase trigger:

  • Delay: 7 days

  • Unit: Days

Seven days is enough for most SEO SaaS tools to show some early wins:

  • Rankings populating

  • First content briefs created

  • First audit surfaced issues

For the Criteria Match trigger paths, you can skip this delay or keep it very short (1 day), because those customers are already active.

Right after each trigger (before the delay), many teams also add a quick safety If/Else to check email subscription:

  • Condition: Email Subscription Status is Subscribed

  • Then branch: continue journey

  • Else branch: end

That keeps you from emailing customers who have opted out of marketing communications.

Step 3: Split customers by how they actually use your SEO tool

After the delay, you want to decide which next-best offer to make. This is where cohort logic lives.

Add a Multi-way Split node. You can either:

  • Use Segment Membership rules (if you created saved segments like “Rank-first, no-content”), or

  • Define the rules inline with Custom Event criteria.

A simple three-branch setup looks like this.

Branch 1: Rank-first cohort

  • Condition group:

  • Tag contains owns_rank_tracker

  • AND custom event rank_check_run triggered at least 10 times in the last 30 days

  • AND custom event content_brief_generated has not triggered in the last 30 days

  • AND tag does not contain owns_content_briefs

Branch 2: Content-first cohort

  • Condition group:

  • Tag contains owns_content_briefs

  • AND custom event content_brief_generated triggered at least 5 times in the last 30 days

  • AND custom event site_audit_run has not triggered in the last 30 days

  • AND tag does not contain owns_site_audit

Branch 3: Audit-first cohort

  • Condition group:

  • Tag contains owns_site_audit

  • AND custom event site_audit_run triggered at least 5 times in the last 30 days

  • AND custom event rank_check_run has not triggered in the last 30 days

  • AND tag does not contain owns_rank_tracker

Else branch: everyone who doesn’t clearly fall into one of those patterns. In the example sequence, the else branch gets a light, educational “tour the rest of the product” email rather than a hard cross-sell.

Order matters here: Multi-way Split evaluates branches top to bottom and sends a contact down the first matching branch. Make the most specific cohorts first.

This node is the heart of the “not blanket” part of the pattern. All the personalization comes from the behavior data you captured earlier.

Step 4: Send one focused next-best-offer email per cohort

Each branch now gets its own cross-sell message via a Send Email node.

Use the same sender identity, but:

  • Different subject lines

  • Different angles

  • Different product pitches

Examples:

Rank-first branch email

  • Pitch: Content briefs module.

  • Angle: “You already know where you need to win; briefs help you create what ranks.”

  • Content: Case study from an agency that started with rank tracking, then added briefs and improved content output.

Content-first branch email

  • Pitch: Site audits module.

  • Angle: “Your content is strong; audits fix crawl and technical issues holding it back.”

  • Content: Before/after from a site that improved crawlability and Core Web Vitals, leading to better rankings for existing content.

Audit-first branch email

  • Pitch: Rank tracking module.

  • Angle: “You’re fixing issues; rank tracking proves the impact and gives clients reporting.”

  • Content: Sample white-label report, how many hours it saves agencies monthly.

Build these in Spreeflo’s email builder so your team is not wrestling with HTML. For each Send Email node:

  • Pick the appropriate template.

  • Leave “Send only once” on (default) so re-enrollment via future triggers cannot resend the same cross-sell email endlessly.

Critically, do not stack emails. After each cross-sell email, add a Time Delay of 3 days before you check engagement or send anything else. That respects inboxes and gives people time to think.

Step 5: React differently to clicks, opens, and silence

After the 3‑day delay, add a Check Email Activity node on each branch, pointing to that branch’s cross-sell email.

For each Check Email Activity:

  • Select the relevant marketing email template.

  • Choose at least two activities to branch on:

  • clicked

  • opened

  • The built-in else branch catches “no meaningful engagement.”

You now have three paths per cohort:

  1. Clicked: strong buying intent.

  2. Opened but did not click: some interest, not enough.

  3. No engagement: not interested right now or the timing was off.

For the clicked path:

  • Add an Add Tag action with something like nbo_clicked_content_briefs or nbo_clicked_site_audit.

  • Optionally send a Send Internal Email to yourself or a sales inbox when the account is above a certain size (you can gate that with a short If/Else using a seats attribute). That lets you manually follow up with high-value accounts.

  • Then add a Wait Condition that watches for a purchase event:

  • Condition: custom event module_purchased (or the specific add-on event) triggered at least one time in the last 7 days.

  • Timeout: 7 days.

After the Wait Condition, branch again with an If/Else:

  • If they purchased: add owns_content_briefs (or matching) tag and exit.

  • Else: add a “cooldown” tag like nbo_content_briefs_snoozed and exit.

For the opened-but-did-not-click path:

  • Add a Time Delay of 1 day.

  • Send one gentle follow-up Send Email:

  • Subject: different angle; often more outcome focused and less feature named.

  • Content: maybe a short video or GIF walkthrough, aimed at lowering perceived effort rather than pushing discount.

  • Then merge into the same Wait Condition and If/Else logic as the clicked path.

Be careful with pacing: there is always at least a 1‑day delay before any second email, and you don’t send more than two emails for a single cross-sell attempt.

For the no-engagement else path:

  • Add an Add Tag to mark them as not responsive for this offer (nbo_content_briefs_uninterested for example).

  • Send them to a Merge node that all the “done” paths converge into.

Using tags like this also protects you from accidentally re-targeting the same user later when Criteria Match triggers fire again.

Step 6: Mark who bought, who ignored, and keep things clean

All paths eventually land in a Merge node, then into a short cleanup section:

  1. Add an Update Contact Attribute node to set a timestamp attribute such as last_nbo_ran_at to now (use the SET_NOW update type on a timestamp field). This gives you a throttle if you want to exclude anyone from a future next-best-offer journey for, say, 60 days.

  2. Optionally add a general tag like nbo_journey_completed so you can filter these contacts in reports or future segments.

If you want expansion-revenue reporting outside Spreeflo, you can also drop a Webhook action here that posts contact, cohort, and outcome tags into your data warehouse or CRM. That makes it easy to calculate incremental AOV uplift and attachment rates by cohort.

What this journey does for your AOV and LTV

On paper this is “just” a few triggers, a Multi-way Split, some Send Email and Check Email Activity nodes, and clean tagging. In practice it changes how your business behaves:

  • Every new paying account and every relevant usage pattern automatically gets one thoughtful, context-specific next-best offer.

  • Nobody gets hammered with irrelevant cross-sell. Rank-first users hear about briefs in the language of rankings and topical coverage; content-first users hear about audits in the language of technical blockers.

  • Your team gets a stream of high-intent signals (clicked but did not yet buy) without staring at dashboards.

Most SEO SaaS founders already know expansion revenue is powerful. The leak happens because nurturing that expansion manually does not scale. What this journey gives you is a set-and-keep-running mechanism that:

  • Listens to behavior continuously.

  • Speaks to each customer uniquely, based on a rich behavioral profile.

  • Treats silence as a signal, not something you try to bulldoze through.

It is also cheap time-wise. You build it once inside the campaigns and journeys UI, wire in segments with the segment builder, write three or four focused templates in the email builder, and let it run. Tweaks later are as simple as editing a branch condition or swapping a template.

For a small team, that is the point. Founder-led businesses win on leverage, not headcount. Every hour you spend designing this kind of journey is an hour that compounds: more relevant offers, higher attachment rates, and expansion MRR that grows without you needing to remember who to email next.

You already did the hard work of building modules your customers could benefit from. This next-best-offer journey is how you stop leaving that value—and that lifetime revenue—on the table.