Back to the build library
Any industry
Standard

Win-Back for Lapsed Customers

Work out who has gone quiet using their own purchase cycle, then reactivate them in controlled waves instead of one reckless blast.

Industry
Any industry
Build effort
Standard
Typical time to launch
2–3 weeks
On this page
The problemWhat gets builtHow it runsAutomations in detailWhat changesBefore you start
Want this built for you?

Bring your stack to a call and we will scope it against how your business actually runs.

Book a call
01

The problem

Every established business is sitting on a list of people who used to buy and stopped. Nobody fired anybody. There was no complaint, no cancellation, no decision. The customer just drifted (life got busy, the reminder never came, a competitor was closer that week) and the business never noticed, because nothing in the operation fires when a customer fails to return. Systems are built to react to events: a booking, a payment, a form, a call. Lapsing is not an event. It is the absence of events, and absence does not trigger anything.

So the lapsed list grows silently and becomes the largest untouched asset in the company. These are people who already found you, already trusted you enough to pay once, already know where you are and what you do. Reactivating one of them costs a message. Replacing one of them costs whatever your paid channels charge to acquire a stranger. Most businesses spend heavily on the second while the first sits in the database, unmeasured, often not even countable, because "lapsed" has never been defined, and until it is defined, it cannot be worked.

When businesses do finally attack the list, they usually make it worse. Somebody exports everyone who has not bought in a year and blasts a discount to all of them in one afternoon. The list is stale, so bounces spike. Nobody has heard from this sender in eighteen months, so spam complaints spike. The mailbox providers conclude the domain is sending unwanted mail to unengaged addresses, and the sending reputation that the business's live customer communications depend on takes damage that takes months to repair. The discount, meanwhile, is handed to the subset who would have come back anyway, and the people who left for a fixable reason are never asked what it was. The fix is unglamorous and mechanical: define lapsing against each customer's own purchase cycle, clean before you send, go out in throttled waves, ask the reason before you offer anything, and hold back a control group so you can prove the whole exercise did something.

02

What gets built

Pipeline and stages

A Win-Back pipeline, one card per lapsed customer, so a reactivation campaign stops being a one-off export and becomes a standing process with visible state.

  1. Cooling: past their normal cycle but not far past. Watched, not worked. Often rescued by a simple recall or reminder instead.
  2. Lapse Detected: crossed the threshold for their band. Entry point for the campaign.
  3. Hygiene Hold: waiting on validation, re-permission, or a cleaner contact detail. Nothing sends from here.
  4. Wave Queued: eligible and scheduled into a send batch.
  5. Wave 1 Sent: the check-in has gone, no offer attached.
  6. Wave 2 Sent: the reason ask has gone.
  7. Wave 3 Sent: the offer has gone, with an expiry.
  8. Re-Engaged: they replied, clicked, or answered. Out of the waves, into a human-speed conversation.
  9. Booked: an appointment or order exists.
  10. Won Back: they purchased again. Terminal and good; the cycle clock resets.
  11. Lost: Reason Known: they told you why they left. Commercially the second most valuable stage in the build.
  12. Dormant Archive: all waves ran, no response. Suppressed from marketing, retained for reporting.
  13. Suppressed: opted out, bounced hard, or flagged do-not-contact. Terminal and absolute.

Calendars

  • Standard booking calendars, reached through a win-back-specific link so a reactivated booking is attributable without anybody tagging it by hand.
  • Priority return slots: a handful of protected slots per week. A win-back message that offers a time three weeks out converts badly; the whole appeal is "come back easily, now".
  • Outbound call blocks for the high-tier segment, where a human call outperforms every message in this build. One hour a day, booked as a recurring internal appointment, with the call list generated by WF-W10.

Custom fields

  • last_purchase_at (date/time). The spine of the build. If this is wrong, everything downstream is wrong.
  • last_visit_at and last_engagement_at (date/time). A customer who opened an email last week has not lapsed in the same way as one who has been silent for a year, and the copy must differ.
  • purchase_count_lifetime (number). A one-time buyer and a ten-time regular are different problems entirely.
  • avg_cycle_days (number). This customer's own median gap between purchases, calculated rather than assumed.
  • expected_cycle_days (number). The business's expected cycle for their primary_service, used as the fallback where purchase_count_lifetime is 1 and there is no personal cycle to measure.
  • days_since_last_purchase (number): recalculated nightly.
  • lapse_band (dropdown: Active, Cooling, Lapsed, Dormant, Gone): derived, never typed.
  • lapse_detected_at (date/time).
  • primary_service (dropdown) and last_service_taken (text), so the message names something real.
  • value_tier (dropdown: A, B, C). A relative ranking by historic spend and frequency, used only to decide who gets a human call and who gets a message. No figures are stored or shown to the customer.
  • winback_wave (number, 0–3) and winback_attempt_count (number): the cap fields.
  • winback_last_contact_at (date/time): prevents two waves colliding.
  • winback_campaign_id (text), which run of the program this card belongs to, so year-on-year comparison is possible.
  • winback_reason (dropdown: Moved away, Price, Service issue, Went elsewhere, No longer need it, Forgot about us, Life circumstances, Never actually a fit, No reason given) and winback_reason_free_text (long text).
  • winback_offer_code (text) and winback_offer_expires_at (date/time). An offer with no expiry is not an offer, it is a permanent price change.
  • reactivated_at (date/time) and reactivation_source (dropdown: Wave 1, Wave 2, Wave 3, Human call, Organic return, Unknown).
  • email_validation_status (dropdown: Valid, Risky, Invalid, Unverified) and phone_validation_status (dropdown: Mobile, Landline, Invalid, Unverified).
  • repermission_requested_at and repermission_confirmed_at (date/time).
  • holdout_group (checkbox). The control group. The field that lets you prove the program worked.
  • do_not_winback (checkbox). The override that beats every rule in the build.

Tags

lapse-cooling, lapse-detected, winback-hygiene-hold, winback-wave-1, winback-wave-2, winback-wave-3, winback-engaged, winback-booked, won-back, winback-reason-captured, winback-dormant, winback-holdout, winback-suppressed, winback-cap-hit, repermission-sent, repermission-confirmed.

Forms, surveys and pages

  • One-question reason survey: nine buttons, no login, no name field, served from Wave 2. It writes winback_reason on tap. This is the single most valuable asset in the build and it is one screen long.
  • Re-permission page: for contacts whose consent is old or undocumented: one line explaining what they would receive and how often, one button to confirm, one to leave. Short, honest, no offer attached.
  • Return landing page: names their last service, shows live availability or a reorder button, and nothing else. No navigation, no blog, no about page. One decision.
  • Offer page: used only in Wave 3, carrying winback_offer_code and a visible expiry date, with the terms in plain words on the same screen.
  • Preference center: reachable from every send, offering fewer messages and topic choices as well as full unsubscribe. The single most effective way to reduce complaints on a reactivation campaign is to offer "less" as an alternative to "never".

BO's role and guardrails

  • BO handles the inbound wave: a reactivation campaign generates replies in volume, and most of them are short: "what are your prices now", "do you still do X", "I moved", "take me off this".
  • BO's jobs: classify the reply into winback_reason, answer factual questions about services, hours and locations from the knowledge base, offer availability, and book.
  • Guardrails. BO never improvises an offer, a discount, a price or a goodwill gesture: only the exact offer in winback_offer_code, in the words approved for it. BO never speculates about why someone left. BO never apologizes for a specific service failure it cannot verify; it acknowledges, then escalates. BO never argues with someone who says they already asked to be removed. It suppresses immediately and apologizes once.
  • Escalation rules. Any service complaint, any mention of a refund, dispute, bereavement, illness or legal matter, any angry tone, any "I asked you to stop". Immediate handoff, suppress all pending waves for that contact, create a task due in two hours.
  • BO's knowledge base needs the current service list, current locations and hours, what has changed since the customer last visited, and an explicit refusal list.

Numbers and channels

  • Email as the primary wave channel. It is the only channel where this kind of volume is economically and reputationally sane, and the reason the hygiene workflow exists.
  • SMS for the Cooling band and the A tier only, where consent is documented and recent. Texting a list that has not heard from you in two years generates complaints at a rate that is not worth the lift.
  • Voice AI calls for the A tier where a human call block cannot cover the volume. Short, identifies the business immediately, offers a reason to return and a transfer to a person, and never pitches.
  • Human call blocks for the top slice of the A tier. Nothing in this build converts like a real call from someone who remembers them.
  • A dedicated sending subdomain for reactivation email, kept separate from transactional and live-customer mail, so if reputation is damaged the damage is contained.
  • The existing business number for any SMS, so the message arrives from a recognized sender.
03

How it runs, step by step

One lapsed customer, end to end

  1. Overnight, day 0. The nightly sweep recalculates days_since_last_purchase for the whole database. One customer's last purchase was 214 days ago. Her avg_cycle_days, from four previous purchases, is 95. She is at 2.25 times her own cycle.
  2. Band assignment. Past 1.5 times her cycle she was marked Cooling and received the standard recall. Past 2 times, she crosses into Lapsed: lapse_band is set, lapse_detected_at is stamped, and a card is created in the Win-Back pipeline at Lapse Detected.
  3. Holdout draw. Before anything is sent, the workflow draws lots. One in ten lapsed contacts is marked holdout_group and will receive nothing at all for the duration of the campaign. She is not drawn, so she proceeds. The holdouts are what will later prove whether the campaign actually caused anything.
  4. Hygiene. Her email is validated as Valid; her mobile is confirmed as a mobile. Her last documented email consent is 26 months old, which fails the freshness rule, so she enters Hygiene Hold and is routed to re-permission rather than straight into the waves.
  5. Day 1. A single re-permission email goes out: no offer, no pitch, just what she would receive, how often, and two buttons. She clicks confirm. repermission_confirmed_at is stamped and she moves to Wave Queued.
  6. Day 2. The throttle picks her up. Today's batch for this segment is capped, so she is scheduled into the following morning's send rather than going out immediately. Nothing about the campaign is in a hurry.
  7. Day 3, 10:00am. Wave 1 arrives: a short check-in that names the service she actually had, mentions one thing that has genuinely changed since, and asks nothing except whether she would like to come back. No discount. winback_wave = 1.
  8. Day 3. She opens it and does not click. That open is recorded as engagement, which matters: it keeps her out of the sunset path and tells you the address is live.
  9. Day 8. Wave 2 arrives: one question, nine buttons. "Can I ask what happened? One tap, no reply needed." She taps Forgot about us. winback_reason is written, she moves to Re-Engaged, and, critically, every remaining wave is canceled. She has answered; she is now in a conversation, not a campaign.
  10. Day 8, two minutes later. Because the reason was "Forgot about us" rather than price, she gets a reactivation message with no offer in it at all: just two specific appointment times and a one-tap booking link. Discounting someone who simply forgot is money set on fire.
  11. Day 8. She replies asking whether a different service is available on a Saturday. BO answers from the knowledge base, offers two Saturday slots from the priority return calendar, and books one. winback_booked, stage Booked.
  12. Day 9. The confirmation sequence runs with a hardened reminder ladder, because a returning customer after seven months is a fragile booking.
  13. Day 15. She attends and buys. reactivated_at is stamped, reactivation_source = Wave 2, stage moves to Won Back, and last_purchase_at updates, which automatically recalculates her cycle, resets lapse_band to Active, and removes her from the campaign for good.
  14. Day 16. She enters the won-back onboarding track: a thank-you, a prompt to book the next visit before leaving, and enrollment in the recall program that would have prevented the lapse in the first place. Winning someone back without fixing the mechanism that lost them just queues up the same work next year.
  15. Day 30, for a different customer. Someone who received all three waves, never opened anything, and whose address was validated as Risky is moved to Dormant Archive, suppressed from all marketing, and retained for reporting only. No fourth wave exists.
  16. Day 90. The campaign report compares purchase rate in the contacted group against the holdout group. The difference, not the gross number of returns, is what the campaign actually achieved.
04

Automations in detail

WF-W1 · Nightly Lapse Detection and Band Assignment

Why this exists: lapsing is the absence of an event, so it has to be manufactured as one. This workflow is the only thing in the build that creates that event, and it must run against every contact, every night, without anybody asking it to.

Trigger: scheduled, nightly at 02:00.

Calculation, in order:

  1. Recalculate days_since_last_purchase from last_purchase_at.
  2. Recalculate avg_cycle_days as the median gap between purchases where purchase_count_lifetime is 3 or more. Use the median, not the mean. One unusual gap will otherwise push a regular customer into the wrong band for months.
  3. Where purchase_count_lifetime is 1 or 2, use expected_cycle_days for their primary_service instead. Set these deliberately with the client: a quarterly service, an annual check, a two-yearly replacement. Guessing one global number is the most common modeling error in win-back builds and it mislabels half the database.
  4. Assign lapse_band against the applicable cycle:
    • Active: under 1.25 cycles.
    • Cooling: 1.25 to 2 cycles. Route to the recall or reminder program, not to win-back. Most of this band is recoverable with a nudge and should never see a win-back message.
    • Lapsed: 2 to 4 cycles. The win-back audience.
    • Dormant: 4 to 8 cycles. Win-back eligible, but email only and with re-permission mandatory.
    • Gone: beyond 8 cycles, or beyond 36 months regardless of cycle. Not contacted by this build at all. Consent this old is not consent, and the addresses are mostly dead.
  5. Cap every band at an absolute ceiling in months as well as in cycles, so a customer on a two-week cycle is not declared Gone after eight weeks.

Actions on a band change into Lapsed or Dormant:

  1. Stamp lapse_detected_at; set lapse_band; add lapse-detected; create a card at Lapse Detected; write winback_campaign_id.
  2. Exclusion checks: drop the record out of the build entirely if any apply: do_not_winback = true; any opt-out or do-not-contact tag; an open complaint, dispute or unpaid overdue invoice; an active subscription or contract (they have not lapsed, your data is wrong); deceased flag; a booking already in the future; already in another active campaign.
  3. Holdout draw: assign 10% at random to holdout_group = true, add winback-holdout, and exclude them from every send in this build. Draw once per winback_campaign_id and never redraw mid-campaign.
  4. Set value_tier from historic frequency and spend rank, used solely to route A-tier records to human calls in WF-W10.
  5. Continue to WF-W2.

Exit: band returns to Active on any purchase, which also closes the card and stops every pending wave.

WF-W2 · Hygiene and Re-Permission Before Any Send

Why this workflow is the most important one in the build: a reactivation campaign is, by definition, mail to people who have not engaged in a long time. That is precisely the traffic mailbox providers use to judge a sender. Blast an unvalidated two-year-old list and you can damage the sending reputation that your invoices, receipts and appointment confirmations depend on. Repairing that takes months. This workflow is not optional and it is not a nice-to-have.

Trigger: record enters Lapse Detected.

Actions, in order:

  1. Validate the email address. Write email_validation_status. Invalid → suppress from email permanently. Risky → hold out of the main batches and send, if at all, only in a small separate batch after the healthy sends have completed and the reputation picture is clear.
  2. Validate the phone number. Write phone_validation_status. Landline → no SMS, voice only. Invalid → suppress from SMS.
  3. Deduplicate. Merge duplicates before sending, not after. Two copies of one person getting the same win-back email is the most visible possible failure.
  4. Check consent age and provenance. If documented consent is older than 24 months, or its source cannot be identified, route to re-permission: do not simply send and hope.
  5. Re-permission send (one only): subject "Still want to hear from us?". Body: what they would receive, roughly how often, a confirm button, and a leave button that is equally prominent. No offer, no discount, no pitch. An incentive attached to a consent request contaminates the consent. Stamp repermission_requested_at.
  6. Wait 10 days. Confirmed → stamp repermission_confirmed_at, add repermission-confirmed, move to Wave Queued. No response → move to Dormant Archive and suppress from marketing. Silence is an answer and should be treated as one.
  7. Seed the send. Include monitoring addresses across the major mailbox providers in every batch so inbox placement is observed rather than assumed.
  8. Warm the subdomain. If the reactivation subdomain is new, ramp volume gradually over at least two weeks, starting with the most recently engaged slice of the audience and working outwards. The order matters as much as the volume: engaged-first sending is what builds the reputation that lets the cold tail land.

Hard stops: no record proceeds to any wave without a valid channel, a documented consent basis, and a clean deduplication check. Hygiene Hold is excluded from every bulk audience in the account, explicitly.

WF-W3 · Wave Scheduling and Throttle Control

Why: the difference between a reactivation campaign and a reputation incident is almost entirely pacing.

Trigger: record enters Wave Queued; scheduler runs each morning at 08:00.

Conditions and logic:

  • Daily send cap per segment, set as a fraction of normal daily volume from that sending domain. A reactivation campaign should never be the largest thing the domain sends that day. Start small and increase only while complaint and bounce rates stay flat.
  • Send order: most recently engaged first, least engaged last, always. This is the most important setting in the build.
  • Circuit breaker: if hard bounces exceed a threshold, or spam complaints exceed a far lower one, pause the entire campaign automatically, notify the owner, and require a human to restart it. Build this before the first send, not after the first problem.
  • Global frequency cap: no contact receives a win-back message within 5 days of any other marketing message from the account, from this build or any other.
  • Quiet hours and day-of-week: send between 09:00 and 17:00 local, Tuesday to Thursday for email. Avoid Monday morning and Friday afternoon, and avoid public holidays: maintain a holiday calendar per location.

Actions:

  1. Build today's batch from Wave Queued within the cap and in the correct order.
  2. Dispatch, stamp winback_last_contact_at, increment winback_attempt_count, set winback_wave, move the stage.
  3. Record batch-level bounce, complaint, open and click rates against winback_campaign_id within 24 hours, and post the figures to the internal channel.
  4. Hold the rest of the queue if any metric breaches its threshold.

Exit: queue empty, or circuit breaker tripped.

WF-W4 · Wave 1: The Check-In, With No Offer

Trigger: dispatched by WF-W3.

Why there is no offer here: a discount in the first message trains the list to wait for discounts and hands margin to the people who would have returned for free. Wave 1 exists to find out who is still interested, cheaply.

Actions:

  1. Send email. Subject: "Still doing {{last_service_taken}}?". Specific, low-pressure, no exclamation marks and no "we miss you" in the subject line, which is the single most filtered phrase in reactivation mail.
  2. Body, four short paragraphs: name what they had and roughly when; one genuine thing that has changed since (a new service, longer hours, a second location, new equipment); one sentence saying there is no catch; one button to availability. Plain text weighted, light on images, one clear unsubscribe and one preference-center link.
  3. SMS variant: Cooling and A tier only, consent confirmed within 12 months: "Hi {{first_name}}, it's {{business_name}}, it's been a while since your {{last_service_taken}}. We've got {{slot_1}} and {{slot_2}} free this week if you'd like to come back in. Reply STOP to opt out."
  4. Set winback_wave = 1; add winback-wave-1; move to Wave 1 Sent.
  5. Wait 5 days. Branch on behavior:
    • Clicked or replied → move to Re-Engaged, cancel all remaining waves, continue to WF-W7.
    • Opened, did not click → continue to Wave 2. The address is live and the person is curious; this is the best segment in the campaign.
    • No open → continue to Wave 2, but switch the subject line and the send time, and move them behind the engaged cohort in the queue order.
    • Bounced or complained → suppress immediately, move to Suppressed, and exit the build.

Exit: engagement of any kind; suppression; Wave 2 dispatched.

WF-W5 · Wave 2: The Reason Ask

Why this is the wave that pays for the build: a reactivation campaign that produces returns gives you revenue once. One that produces reasons gives you a list of fixable causes of churn, and the reasons are usually not what the owner assumed. Ask before you discount.

Trigger: 5 days after Wave 1 with no click or reply.

Conditions: no suppression, no booking, winback_attempt_count under 3, frequency cap satisfied, circuit breaker clear.

Actions:

  1. Send email. Subject: "Can I ask you one question?" Body: three lines, then the nine reason buttons inline so the answer is a single tap from the inbox. No offer anywhere on the page.
  2. Write winback_reason on tap, not on submit, and stamp the time.
  3. Set winback_wave = 2; add winback-wave-2; move to Wave 2 Sent.
  4. On any answer: cancel every remaining wave, move to Re-Engaged or Lost: Reason Known, and branch:
    • Moved away → check for another location. If one is in range, send its details once. Otherwise thank them honestly, set do_not_winback = true, and close the card. Never discount a geography problem.
    • Price → the only branch where Wave 3's offer is genuinely the right instrument. Queue it immediately rather than waiting the full interval.
    • Service issue → no offer, no automation. Create a task for a named owner, due in 4 hours, for a personal call. Send one short acknowledgement: "Thank you for telling me: that's not the standard we want. {{owner_first_name}} will call you personally; no sales pitch, I'd just like to understand what happened." An offer sent to someone with an unresolved complaint makes things worse.
    • Went elsewhere → one short message, no discount, asking what the other provider does better, and leaving the door open. This reply is competitive intelligence you cannot buy.
    • No longer need it → thank them, set do_not_winback = true, and stop. Do not try to create a need.
    • Forgot about us → the best possible answer. No discount required. Send two concrete times and a booking link, and enroll them in the recall program so it does not happen again.
    • Life circumstances → one gentle, open-ended message, suppress for 6 months, and no offer. Treat with care: this branch frequently involves illness or bereavement, and the standing instruction is to hand anything specific to a human and automate nothing.
    • Never actually a fit → thank them, suppress, and feed it back to whoever owns lead qualification. These records are telling you about an acquisition problem, not a retention one.

Exit: reason captured; booking made; suppression; Wave 3 dispatched.

WF-W6 · Wave 3: The Offer, With an Expiry

Trigger: 7 days after Wave 2 with no response, or immediately on the Price branch of WF-W5.

Conditions: winback_attempt_count under 3; no suppression; offer approved and configured; contact not in holdout_group; winback_reason is not Service issue, Moved away, No longer need it, Life circumstances or Never actually a fit: those branches never receive this wave.

Actions:

  1. Generate winback_offer_code, unique per contact so redemption is attributable, and set winback_offer_expires_at: 14 days is the usual window. Shorter feels like pressure; longer gets forgotten.
  2. Send email. Subject names the thing, not the saving. Body: one paragraph, the offer stated plainly in the words legal and the owner approved, the expiry date visible as a date rather than a countdown, the terms on the same screen, one button.
  3. Set winback_wave = 3; add winback-wave-3; move to Wave 3 Sent.
  4. Wait 7 days. Condition: unredeemed and unexpired. Send one reminder stating the expiry date. One. There is no second reminder and no extension. An extended deadline teaches the list that deadlines are decorative.
  5. On expiry: expire the code server-side so it genuinely stops working, and move the record to Dormant Archive.
  6. On redemption: stamp reactivated_at, set reactivation_source = Wave 3, move to Won Back, continue to WF-W8.

Commercial guardrails to settle before this workflow is built: the nature and size of the offer are the client's decision and must be set against margin rather than against what feels compelling. The offer should be the last instrument used, never the first. Exclude anybody whose winback_reason indicates the problem is not price. Never offer returning customers better terms than loyal ones can get. It is the fastest way to teach your best customers to lapse deliberately. Confirm any promotional terms, expiry handling and advertising claims with the client's own counsel before launch.

WF-W7 · Re-Engagement Capture and Booking

Trigger: any click, reply, inbound call, chat message, or reason tap from a record in the Win-Back pipeline.

Actions, in order:

  1. Cancel every pending wave for this contact immediately. This is the step that gets missed, and missing it means someone who just replied receives the next scheduled blast anyway.
  2. Add winback-engaged; move to Re-Engaged; stamp the engagement time.
  3. Branch on value_tier. A tier → create a task for a named human to call within 2 hours and route the thread to them. B and C → hand to BO.
  4. BO's opener acknowledges the gap without making it awkward: "Good to hear from you, {{first_name}}. It's been a little while: are you after {{last_service_taken}} again, or something different this time?"
  5. Offer two specific times from the priority return calendar rather than a bare link. Named times convert far better than open availability on a reactivated contact.
  6. On booking: stamp referral-style attribution: that is, set reactivation_source to the wave that produced the engagement: add winback-booked, move to Booked, and run the hardened confirmation ladder, because a first booking after a long gap behaves like a new lead rather than a regular.
  7. On no booking after 2 conversational turns: hand to a human rather than persisting. BO's job ends where judgment begins.

Exit: booked; handed to a human; contact goes quiet for 14 days, in which case the card returns to Dormant Archive without further messaging.

WF-W8 · Won-Back Onboarding and Cycle Reset

Why it matters: reactivating a customer and then returning them to the same unmanaged state simply schedules the same loss again. The win-back is only finished when the mechanism that lost them is fixed.

Trigger: purchase or completed appointment on a record tagged winback-engaged or in Booked.

Actions:

  1. Stamp reactivated_at and last_purchase_at; set lapse_band = Active; add won-back; move to Won Back; recalculate avg_cycle_days including the long gap, flagged as an outlier so it does not distort the next band assignment.
  2. Clear winback_wave and winback_attempt_count for the next cycle, and close the card.
  3. Wait 1 day. Send a thank-you that does not sell: "Really glad to have you back, {{first_name}}. Anything you need, just reply to this. It comes straight to us."
  4. Wait 2 days. Run the satisfaction question. A won-back customer's second experience decides whether the reactivation was worth anything, and this is also the gate into the review and referral programs.
  5. At the point of service: queue the next appointment or reorder prompt before they leave. A booked next visit is the only reliable protection against a repeat lapse.
  6. Enroll them in the recall or reminder program for their primary_service, with the cadence set from their own avg_cycle_days.
  7. Create a task to review the lapse cause. Where winback_reason is populated, route it to whoever owns that process. Service issues to operations, price to the owner, forgetting to whoever owns recall. A reason that lands in a field and is never read is a reason wasted.

Exit: onboarding complete and recall enrollment confirmed.

WF-W9 · Sunset, Archive and Suppression

Why you need an ending: a reactivation program with no exit becomes permanent mail to people who will never buy, and permanently unengaged recipients are exactly what damages a sending domain. The discipline to stop is part of the build.

Trigger: all waves sent with no engagement; or any suppression event; or scheduled monthly sweep.

Actions:

  1. No engagement after Wave 3 and the single reminder → add winback-dormant, move to Dormant Archive, and remove the contact from all marketing audiences. Retain the record for reporting and for any future consented re-entry; retain nothing you cannot justify keeping.
  2. Hard bounce, spam complaint, STOP, or unsubscribe → suppress immediately across the relevant channel, add winback-suppressed, move to Suppressed, set do_not_winback = true. Make the suppression visible to email and SMS at once so one channel does not keep running.
  3. Re-entry rule: a dormant-archived contact may be considered for one future campaign no sooner than 12 months later, and only after fresh validation and re-permission. Enforce this with lapse_detected_at and winback_campaign_id, not with memory.
  4. Monthly sweep: flag any record that has sat in Hygiene Hold or Wave Queued for more than 30 days. These are usually a sign the throttle is set too low or a validation step is silently failing.
  5. Apply the retention policy: delete or anonymize archived records at the agreed interval automatically, rather than letting a decade of dead contacts accumulate.

Exit: terminal by design.

WF-W10 · Holdout Measurement, A-Tier Call Lists and Reporting

Why the holdout group exists: some lapsed customers come back on their own. Without a control group you will credit every one of those returns to the campaign, conclude it worked brilliantly, and never find out whether it did. The holdout is the only honest measurement in this build.

Trigger: scheduled weekly, plus a campaign-close report at 90 days.

Actions:

  1. Weekly A-tier call list. Build the list of A-tier records in Wave 1 Sent or later with no engagement, ordered by historic frequency, and assign to the human call blocks. Script: identify yourself, say it has been a while, ask whether they still need the service, offer two times, and, if nothing else, ask what changed. No pitch, no offer unless already approved for that record.
  2. Log every call outcome into winback_reason. Calls produce reasons at a far higher rate than any message, which makes this list valuable even when it produces no bookings.
  3. Weekly operations digest to the internal channel: records detected, held in hygiene, queued, sent per wave, bounce and complaint rates, engagement by wave, bookings, and the circuit-breaker status.
  4. 90-day campaign report to the owner: purchase rate in the contacted group versus the holdout_group; the difference is the campaign's actual effect. Then returns by wave, reason distribution, reactivation rate by value_tier and by primary_service, offer redemption rate, and, reported honestly, how many Wave 3 redemptions came from people whose reason was never price.
  5. Feed the reasons upstream. Produce a ranked list of lapse causes and route each to a named owner. If "forgot about us" dominates, the real fix is the recall program, and the next win-back campaign should be smaller because fewer people lapsed.
  6. Retire the campaign. Close winback_campaign_id, release the holdout group back into normal eligibility, and schedule the next run: quarterly for short-cycle businesses, twice a year for long-cycle ones. A continuous win-back campaign is just a mailing list with extra steps.

Exit: campaign closed and reported.

05

What changes

What is different afterwards

  • Lapsing becomes an event. The nightly sweep manufactures the trigger that the business never had, so a customer going quiet now produces a card, an owner and a sequence instead of silence.
  • "Lapsed" means something specific per customer. A monthly customer and an annual one are no longer judged against the same arbitrary number of days, which stops you chasing people who are not late and ignoring people who are long gone.
  • The list gets cleaned before it gets mailed. Validation, deduplication and re-permission run ahead of every wave, so the campaign does not cost you the deliverability your transactional mail depends on.
  • Sends go out in waves with a circuit breaker. The campaign can be stopped automatically by its own metrics rather than by someone noticing a problem a week later.
  • You find out why people left. The one-question reason survey converts a revenue exercise into a diagnosis, and the answers are routinely different from what the owner believed. Most businesses discover that forgetting, not price, is the leading cause.
  • Discounts stop being the first move. The offer is reserved for the branch where price is the stated problem, which protects margin and stops training the list to wait for deals.
  • Nobody gets chased forever. Three waves, one reminder, then archive and suppress. The program has an ending, which is what keeps it safe to run again next quarter.
  • Won-back customers get a next appointment. The build closes with recall enrollment, so the reactivation is not simply booking the same work again in a year.
  • The campaign's effect is measurable. The holdout group means you can state what the program caused rather than what coincided with it, which is the difference between a budget line that survives scrutiny and one that does not.

Metrics to watch

  • Incremental purchase rate against the holdout group. The headline number, and the only one that is honest. Gross reactivations will always look better and mean less.
  • Lapse rate by month: contacts crossing into Lapsed as a share of active customers. If the build is working upstream, this should fall, and the win-back audience should shrink over time. A shrinking audience is success, not decline.
  • Hygiene outcomes: share of the audience validated as Invalid or Risky, and share requiring re-permission. On a first run this is often a large fraction of the list, and it is the number that justifies the whole hygiene workflow.
  • Re-permission confirmation rate. Low rates are not a failure; they are an accurate measure of how much of your list was ever real.
  • Bounce rate and spam complaint rate per batch. Watch these per send, not per campaign, with thresholds wired to the circuit breaker. Complaints matter far more than bounces.
  • Inbox placement from the seed addresses, by provider. Open rates are unreliable; placement is the thing you are actually managing.
  • Engagement by wave: open, click and reply rates for Waves 1, 2 and 3 separately. Wave 2's tap rate is usually the highest in the campaign, which surprises people.
  • Reason capture rate and reason distribution. The strategic output. Review it with the owner and assign each reason to someone.
  • Reactivation rate by source: which wave, human call, or organic return produced each win-back. This tells you what to keep and what to cut next time.
  • Offer redemption rate, and redemptions by stated reason. If most redemptions come from people who never said price was the issue, the offer is buying customers you already had.
  • A-tier human call conversion compared with message-only conversion in the same tier. This comparison usually decides how the next campaign is staffed.
  • Second-lapse rate among won-back customers at one full cycle after reactivation. If it is high, WF-W8 is not doing its job and the recall enrollment is where to look.
  • Unsubscribe and preference-center usage. A healthy campaign generates meaningful "fewer messages" selections; if everyone chooses full unsubscribe instead, the preference center is too hard to find.
06

Before you start

Prerequisites

  • Clean, complete purchase history. last_purchase_at and purchase_count_lifetime are the spine of the build. If purchase history lives in a till, a practice system or a spreadsheet, get it into the contact record before anything else. A win-back campaign built on bad recency data will contact active customers and miss lapsed ones, and both failures are visible to the customer.
  • Agreed expected cycles per service, set with the client rather than guessed. This single table decides who the campaign talks to.
  • A defined do-not-contact list: deceased, disputes, complaints, legal matters, former staff, trade accounts, test records. Build it before the first send; discovering it afterwards is how a win-back email reaches a bereaved family.
  • Deduplicated contacts. Non-negotiable before a bulk send.
  • Approved offer terms, if an offer is in scope, with an expiry rule and exclusions. If terms are not signed off, launch Waves 1 and 2 only. They carry most of the reason-capture value and all of the reputational safety.
  • A named owner for the service-issue branch, available to call within hours. Asking why someone left and then not responding to "you let me down" is worse than never asking.
  • Realistic capacity. A successful campaign produces a bolus of bookings. Confirm there is availability to absorb it, or throttle harder.

Integrations and provisioning

  • Email authentication before anything else: SPF, DKIM and DMARC on the sending domain, verified and monitored. Non-negotiable for this build.
  • A separate sending subdomain for reactivation mail, isolated from transactional and live-customer mail, warmed over at least two weeks. If reputation is damaged, you want the damage contained to the subdomain that caused it.
  • Email validation on the whole audience before the first batch, and seed addresses across the major providers in every batch.
  • Phone validation to separate mobiles from landlines and dead numbers before any SMS or voice.
  • Source-of-truth sync for purchase data: Shopify, WooCommerce, Stripe, QuickBooks, Xero, or a practice or field-service system. Decide which system owns last_purchase_at and sync one way only.
  • Calendar sync (Google Calendar, Microsoft 365 or Outlook) so reactivated contacts can book immediately rather than waiting for a callback.
  • Slack or Microsoft Teams for the daily batch metrics and the circuit-breaker alert. This alert must reach a human quickly.
  • The existing business number for any SMS, and call recording configured for the human call blocks where permitted.
  • Branded short-link domain for reason-survey and booking links.
  • Reporting export (Google Sheets, BigQuery or Looker Studio) for the holdout comparison, which usually outgrows a native dashboard.

SMS registration, consent and timing

  • Complete A2P 10DLC brand and campaign registration before sending, and register this traffic honestly as marketing. A win-back message is promotional however gently it is worded, and mis-registering it as transactional is both inaccurate and a filtering risk. Submit samples that match what WF-W4 actually sends.
  • Consent must be documented and current. A purchase two years ago is not consent to be texted today. Where consent cannot be evidenced, or is older than the freshness rule, re-permission comes first, and re-permission requests carry no incentive, because an incentivized consent is a contaminated one.
  • Restrict SMS to the Cooling band and the A tier with consent inside 12 months. Everyone else is email. The complaint rate on cold SMS is not worth the incremental lift, and carrier filtering will punish it.
  • Quiet hours: 09:00–17:00 local for this build, narrower than the legal floor on purpose, Tuesday to Thursday for email, and never on a public holiday.
  • Honor STOP and unsubscribe mechanically on every channel, make suppression cross-channel, and ensure an opt-out sets do_not_winback so the person leaves the program rather than just the channel.
  • Offer "fewer" as well as "never". A prominent preference center measurably reduces complaints on reactivation campaigns, and complaints are what damage the domain.
  • Cap total contact. Three waves plus one reminder, maximum, enforced by winback_attempt_count in the field rather than by step counting, with a global 5-day gap from any other marketing message in the account.

Data protection and sensitive cases

  • Confirm your lawful basis for marketing to lapsed customers in each jurisdiction you operate in, and keep the evidence of consent. When, where, what wording, what channel. Rules differ sharply between territories and between email and SMS, and an eighteen-month-old record is exactly the case where the difference bites.
  • Honor access and erasure requests on archived records as readily as on active ones, and set a retention period for dormant contacts that you can defend and that runs automatically.
  • Handle the Life circumstances branch with care. Reactivation campaigns reach people who have been ill, bereaved, or in difficulty, and free-text answers may contain health or personal information you never asked for. Decide in advance who may read winback_reason_free_text, restrict it by role, and automate nothing on that branch: hand it to a person.
  • Maintain a deceased and bereavement suppression list and check it before every send. This is the single most damaging error a win-back campaign can make.
  • In healthcare and other regulated settings: get a signed business associate agreement covering the platform in place before real patient data enters it; keep every message clinically silent. Reference the location and the general service, never a condition, medication, department or result; and check whether recall-style outreach to former patients is restricted in your profession, because in several it is.
  • Where financial or insurance products are involved, promotional communications to former customers are frequently subject to their own disclosure and suitability rules.
  • None of the above is legal advice. Have the client's own counsel review the consent position, the re-permission wording, the offer terms, the retention schedule and any sector-specific marketing restrictions before the first wave goes out.

Audience size, cycle modeling and offer design are scoped per account. Book a call at bookings.appbo.io to review your purchase history and decide how large a first wave should be.

Field notes

Build it with us.

Every build on this page is something we configure, test and hand over with the SOPs your team needs to run it.

Book a call