Back to Playbooks

Catching Ghost Visitors: An Abandoned-Site Playbook for Shopify App Devs

Free

A detailed Spreeflo journey for Shopify app teams to re-engage abandoned-site visitors, tagging their behavior, sending a single helpful follow-up email, and using that data to refine segmentation, messaging, and conversion across the funnel.

Industry

Niche

Pattern

Loading sequence...

The traffic chart in your analytics dashboard looks healthy. Lots of sessions, plenty of new visitors, app store clicks rolling in.

Then you check deeper: barely anyone hits your pricing page. Almost no one clicks “Install app”. It feels like a crowd walking past your booth at a conference, glancing at your banner, then moving on without saying a word.

That’s the “abandoned site” problem for SaaS and Shopify apps: people land, look around for a few seconds, never view a real “product” or content page, and vanish.

CartWizard, a fictional but typical Shopify app doing about $80k MRR, ran into exactly this. They’d already nailed cart recovery flows for their merchants. But for their own growth, they were leaking hundreds of potential installs every month from visitors who hit the homepage and disappeared before ever seeing a live demo or pricing.

The sequence at the top of this page is the whole journey, end to end. It’s a lightweight automation that spots those ghost visits and sends a single, helpful, zero-pressure email: “Can we help you find what you were looking for?”

This article walks through that journey node by node, explains why it’s built the way it is, and shows how to adapt it to your own funnel.

Why bother with people who barely looked at your app?

At first glance, these early-bounce visitors feel low intent. They didn’t hit “Pricing”, didn’t read your “Use cases for fashion stores”, didn’t start a trial. Should you really spend cycles emailing them?

For e‑commerce apps, the answer is usually yes, with guardrails:

  • A big share of these visitors are not cold. They’re merchants who clicked through from your Shopify App Store listing, a partner blog, or an old newsletter.

  • They’re already in your CRM or billing database from another touch: a previous trial, a past support chat, a content download.

  • The marginal cost of sending them a single targeted email is close to zero, and even a tiny bump in install rate pays for the automation many times over.

Put differently: most app businesses think hard about “cart abandonment” for their merchants, but ignore abandoned site sessions in their own pipeline. That’s classic lifetime-value leak. You paid to attract the visit (through content, partnerships, or App Store SEO). Then you let it go silent.

This pattern fixes that by doing two things:

  1. Capturing a bit more detail on who is bouncing and how often, so you can speak to them more uniquely later.

  2. Nurturing that fragile engagement with a helpful touch at exactly the right moment, instead of letting it die.

What this journey actually does

Before we dive into nodes, here’s the behavior in plain language:

  • Every time a known contact triggers a site_visit event, they’re eligible to enter the journey.

  • You hold them for a short window to see if they self-serve into a higher-intent state by viewing a product page (pricing, features, demo, etc.).

  • If they progress, you quietly tag that behavior for later segmentation and end the flow. No email.

  • If they don’t, you send one gentle “Can we help you?” email with no discount and no fake urgency.

  • After a couple of days, you check how they interacted with that email and tag them accordingly so your future campaigns can distinguish “engaged but not ready” from “truly cold”.

All of this is wired inside Spreeflo’s journey builder. If you’ve never seen it before, this is a good moment to explore how to build a journey visually; the same interface powers everything in this playbook.

Now let’s go step by step.

Step 1: Track the right kind of visit with a Custom Event trigger

Pattern: Custom Event (site_visit) trigger\nNode: Custom Event

You start with a Custom Event trigger configured on an event like site_visit.

On your marketing site or app listing landing page, you instrument:

  • A site_visit custom event via the Spreeflo SDK (Spreeflo.track("site_visit", {...})), or

  • A server-side call via the Spreeflo API when a known contact is associated with a session.

The key details:

  • Fire site_visit only when you can tie the visitor to a contact (for example, they’re logged in, clicked from an email with tracking, or you’ve already called Spreeflo.identify with their email).

  • Add properties that help you filter later: source (app-store, partner-blog, ads), device, maybe is_shopify_partner if you know it.

In the trigger configuration:

  • Event name: site_visit.

  • Property conditions (optional): filter out current customers if you don’t want to email them here (e.g. property is_customer is false).

  • Re-enrollment: set this to off for most apps. You typically don’t want to send this “can we help?” email more than once per contact across their lifetime. If you change your mind later, you can always clone the journey with different logic.

This trigger starts the journey every time a qualifying site_visit happens, but the next node immediately protects you from emailing people you shouldn’t.

Step 2: Only continue for emailable, opted-in contacts

Pattern: If/Else filter\nNode: If/Else

Next, drop in an If/Else node to gate who moves forward.

Using Spreeflo’s segment builder, configure the condition as:

  • Email Subscription Status is Subscribed

  • AND Email address is not blank

Everyone who matches goes down the Yes branch. Everyone else goes down the Else branch, which simply terminates.

Why this matters:

  • You stay inside your own consent rules. No trying to re-engage people who’ve explicitly unsubscribed.

  • You avoid building logic later that assumes an email address exists when it doesn’t.

You could also add a rule here to exclude active paying customers if you want a strict pre-install journey:

  • Contact is not member of segment Active customers

Saving this as a condition at the top keeps the rest of the flow clean.

Step 3: Give them time to show real intent

Pattern: Conditional wait for key page views\nNode: Wait Condition

You don’t want to email someone thirty seconds after they hit your site. Maybe they opened a couple of tabs, or they’re reading your app store listing before clicking through to pricing.

Use a Wait Condition node to pause the journey and watch for meaningful behavior.

Configuration:

  • Condition: a group with OR logic:\n- Page Visited URL contains /pricing at least 1 time in the last 1 day\n- OR Page Visited URL contains /features at least 1 time in the last 1 day\n- OR Page Visited URL contains /demo at least 1 time in the last 1 day

  • Timeout: 4 hours (unit: hours)

Behind the scenes this uses the same activity data that powers Spreeflo’s web tracking and analytics. You’re saying:

“Wait up to 4 hours. If this contact visits any of my key product pages during that time, let them through early. If not, release them after 4 hours anyway.”

Why this shape?

  • Four hours is long enough to cover “I’ll check pricing after this meeting” behavior without delaying so much that the visit is forgotten.

  • Using a 1‑day window on the Page Visited rules gives a safety margin. If someone happened to hit your pricing page earlier that same day from another channel, you won’t send them a confused ‘help you find what you need’ email.

The Wait Condition itself doesn’t branch based on how the wait ended. For that, you add a second decision node.

Step 4: Branch on who progressed vs who vanished

Pattern: Route based on page-visit behavior\nNode: If/Else (again)

Right after the Wait Condition, add another If/Else node with the exact same condition group:

  • Page Visited URL contains /pricing or /features or /demo

  • At least 1 time in the last 1 day

Now you have two clear paths:

  • Yes branch: contacts who did view a key page within that day.

  • Else branch: contacts who never progressed beyond their initial skim.

Yes branch: silently enrich their profile and exit

Here you’re dealing with people who effectively self-qualified. They found what they needed without a nudge, so you don’t need to touch them right now.

Two good actions here:

  1. Add Tag node\n- Tag: site-visit-progressed (or similar)

  2. Optional: Update Contact Attribute node\n- Attribute: a numeric custom attribute like product_page_sessions\n- Update type: Increment by 1

This is what “capture detail on every customer so you can speak to each uniquely” looks like in practice:

  • Later, you can build segments like “visited pricing 3+ times but hasn’t installed” for more assertive outreach.

  • You can exclude site-visit-progressed from more generic awareness campaigns.

After these actions, this branch simply ends.

Else branch: mark as abandoned-site and prepare for outreach

On the Else branch, you do something similar but for the opposite behavior.

  1. Add Tag\n- Tag: abandoned-site-no-product

  2. Optional: Update Contact Attribute\n- Attribute: abandoned_site_visits (NUMBER)\n- Update type: Increment by 1

Now you know not just that this contact bounced once, but exactly how many times they’ve done this, which opens up richer strategies later (for example, different messaging on the third abandoned visit).

With the data layer in place, you’re finally ready to send that email.

Step 5: Send the “can we help you?” email

Pattern: Single, soft-touch nurture\nNode: Send Email

Drop in a Send Email node off the Else branch.

Key settings:

  • Turn Send only once on. If you ever allow re-enrollment on the trigger in the future, this ensures a contact never gets this specific email twice.

  • Choose or create a template in the email builder.

  • Pick a sender identity that matches your brand (founder name often works well for apps at this scale).

Content-wise, keep it short and genuinely helpful. A simple structure:

  • Subject ideas:\n- “Quick question about your Shopify store”\n- “Can I help you figure out if [AppName] fits?”

  • Body outline:\n- Acknowledge their visit without sounding creepy: “I saw you checking out [AppName] earlier.”\n- One-line value prop anchored to their world, not your features: “We help stores like yours lift recovered revenue without touching theme code.”\n- A menu of next steps:\n - “Tell me what kind of store you run and I’ll point you to the most relevant examples.”\n - “Or, here’s a 3‑minute overview and a live demo link if you prefer to click around.”

You can use Spreeflo’s AI personalization (see the help on personalizing with AI variables) to tailor lines based on attributes you already have: store size, vertical, whether they’re on Shopify Plus, etc.

The important constraint: no discount, no fake deadline. This is an earlier-funnel touch. Your only goal is to get them back and pointed at the right information.

Step 6: Listen for engagement instead of blasting a second offer

Pattern: Tag based on email behavior\nNodes: Time Delay → Check Email Activity → (optional tags)

After sending the email, add:

  1. A Time Delay of 2 days.\n- Unit: days\n- Count: 2

  2. A Check Email Activity node targeted at this specific template:\n- Branch on:\n - opened (branch id: opened)\n - clicked (branch id: clicked)\n- Else branch covers “did nothing”.

You’re giving them enough time to open, click, and possibly come back to the site.

You now have three outcomes:

  • Clicked branch: clearly high intent. Tag them early-funnel-engaged or even push to a sales-assist queue using a Send Internal Email or Webhook if you have that motion.

  • Opened but didn’t click: interested but not urgent. Tag them early-funnel-warm.

  • Else branch: no interaction; tag early-funnel-cold or do nothing.

In the sequence at the top of this page, each of these branches ends after tagging. That keeps this journey disciplined: one email, then silence. You can pick these tags up in your broader lifecycle journeys later.

Adapting the pattern to your app’s funnel

The core flow stays the same, but you can tweak nodes to fit your product and audience.

Split messaging by lifecycle stage

Drop a Multi-way Split between the first If/Else and the Wait Condition. Use conditions like:

  • Member of segment Trial users

  • Member of segment Active customers

  • Else: Leads

Each branch can then use a slightly different email template later:

  • Trials get “Need help finishing setup?”

  • Leads get “Is [AppName] right for your store?”

  • Existing customers might skip the email entirely but still get tagged on abandoned visits for success outreach.

Add web push as a secondary nudge

If you’re on the Professional plan and have web push configured, you can add a Send Web Push node instead of, or in addition to, the email. Given how intrusive back-to-back notifications can feel, follow two rules:

  • Only send push to visitors who have already granted permission via your on-site prompt.

  • If you do both email and push, insert at least a 1‑hour Time Delay between them so the experience feels considered.

Throttle based on how often they bounce

Because you’re incrementing abandoned_site_visits, you can add another If/Else right before the Send Email node:

  • Condition: abandoned_site_visits is less than 3

Only those on their first or second abandoned visit get the email. Repeat skimmers simply get tagged and folded into other nurture.

Measuring whether this is working

The headline metrics for this journey map directly to the pattern definition:

  • Return-visit rate: of contacts who enter the flow and get the email, how many return to your site within 7 days? You can build this as a segment: tagged abandoned-site-no-product AND Page Visited URL contains /pricing at least 1 time in the last week.

  • First-purchase (or first-install) conversion: how many of those return visitors go on to install your app or start a trial? Tie your app_installed or trial_started custom events back to the tags you set here.

  • Unsubscribe rate: if this email spikes unsubscribes relative to your other nurture, your tone is off or your timing is too aggressive.

Because every important branch in this journey adds tags or updates attributes, you don’t need to guess. You can use the segment builder to slice your audience however you like and inspect behavior in your analytics.

This is the deeper benefit of building flows like this: they don’t just send messages. They continuously annotate your contacts with behavior, so future campaigns can be much more precise.

The bigger play: stop treating visits as disposable

Founders often obsess over “How do I get more installs from the App Store?” while ignoring a cheaper question: “How many warm merchants am I losing between first click and first serious look at my product?”

An abandoned-site journey like this doesn’t feel flashy. It’s one email, a couple of tags, some conditions.

But it quietly plugs a leak that almost every e‑commerce app has:

  • It catches people who were interested enough to click, but not focused enough to explore.

  • It offers real help at the exact moment they’re most likely to remember you.

  • It turns anonymous bounce statistics into named, segmented contacts you can talk to differently over time.

That’s the compounding effect founder-led teams can get from thoughtful automation. You design a journey once, wire it up with site_visit events, and let it run in the background while you ship product. Every week, a few more “ghost visitors” come back, look properly at what you built, and some of them become customers.

Set this up, watch the tags accumulate, and pay attention to who responds. That’s your early-funnel gold, and with Spreeflo doing the monitoring, you don’t need a big marketing team to stop leaving it on the table.