RXed AI News

AI to the bone.
@RXed_EU
A weekend ↓ architecture v1.0 · 2026-08-13

The quiet customer detector: the regulars who stopped coming, and nobody noticed

The customers who quietly drifted away are the cheapest revenue you have - this finds them from your own booking history, ranks them by what they were worth, and holds back a tenth so you can measure whether contacting them actually worked

Setup: A weekend (~6-12 h) Running cost: $5-12/mo (software included) Time saved: none directly — no trustworthy reactivation figure exists. The 15-30% return rates, the 23-day payback and the 47:1 ROI in circulation all trace back to the blogs of companies selling win-back software, and none of them describes a control group - which matters here more than usual, because a large share of the people you message were returning anyway. None of those numbers are used. What is verifiable is the alternative's price: marketing-automation tiers carrying this feature start around $20-45/month at small list sizes and climb with contact count. Your own number comes from the held-back tenth, after one quarter After setup: You run it — the detection and the weekly list build themselves; nothing leaves the building until you have read the names and ticked them Data lives: Your server — Your customer list, their visit history and your private notes about them stay on your own box. This is the file you least want sitting in a marketing vendor's account, because it is not a copy of the business - at this size it more or less is the business.
Gristn8nOllamaListmonkDockerEmailCustomer serviceReporting
Built for small businesses in general — not a sector list.
Before you start
  • A customer history with dates - names, visit or purchase dates and amounts, two years minimum, because one year cannot show you an annual customer. If your bookings live only in a paper diary, that is the project, and this is the week after
  • Contact details attached to those names, and an honest count of how many rows actually have one. Half a list is a smaller opportunity than you think it is
  • The notes you already keep - moved away, was unhappy about the price, passed away. This is the raw material for the exclusion list, and if it does not exist, build the machine anyway but read every name yourself for the first three months
  • A decision, written down, on the longest gap you will still call normal, and whether your trade is seasonal. A garage is not a salon and a ski shop is neither
  • Whoever advises you on marketing consent, asked once and in writing, before the first send. The mechanics are in this blueprint; the permission is not, and SMS is a different regime from email in most places
  • A machine that stays on, with about 8 GB of RAM if the local model runs on the same box, plus restore-tested backups - you are now holding a customer list outside the system that generated it
  • The discipline to hold back a tenth of the list and send them nothing for a quarter. Skip this and you will never know whether any of it worked
What breaks first FAILS SILENTLY
the do-not-contact list goes stale, and the machine writes to someone who died, moved away or left angry. Nothing errors and the send report is green. You find out when a family member replies, or when the review appears. Re-read the exclusion column every quarter, treat any record with no note and no recent activity as unknown rather than contactable, and keep the weekly list short enough that a human actually reads the names.
Version history
v1.0 · 2026-08-13 — First release. Grist holds the customer table and the detection maths in readable formula columns, n8n runs the week and the caps, Listmonk sends and honours unsubscribes. The local model is fenced to reading free-text notes for do-not-contact reasons and is never allowed to decide who is lapsed. A randomised 10% holdout is built in, because every published reactivation rate is measured without one.

Every win-back number you will read online was measured without a control group. Hold back a tenth of the list, send them nothing, and in one quarter you will have your own number instead of a vendor's.

The architecture

Your booking or sales historyThe notes you already keep onpeopleeach customer measured against their own rhythm, notone rule for everybodyThe quiet customer detectorthe usual gap between their visits, flagged when they arewell past it, ranked by what they were worthA short weekly list you read in fiveminutesA do-not-contact list built from yourown notesOne message per person, at most oncea yearOne in ten held back on purpose, andsent nothingThe held-back tenth is the measurementcompare who came back in each group and the difference isyour own number, not a supplier'sThe arithmetic finds them. You still decide who is worth a message.
the same flow as text
[ Your booking / sales history ]  name · date · amount · free-text notes
        ▼  weekly export, or a direct read
[ Grist — the customer table ]
        │  own gap = median days between their visits (3+ visits only)
        │  overdue = days since last visit > own gap × 1.5
        │  fewer than 3 visits → fall back to the shop's median gap
        ▼
[ Ollama — the exclusion pass ]  reads your notes, not your numbers
        │  "moved to Spain" / "passed away" / "unhappy, comped" → exclude + reason
        ▼
[ n8n — weekly, Monday morning ]
        ├─ drop anyone messaged in the last 12 months
        ├─ rank by past spend, take the top 20–40
        ├─ randomly hold back 1 in 10 — they get nothing
        └─ the rest land in a review table as drafts
        ▼  you read the names. nothing sends until you tick.
[ Listmonk ]  sends, handles unsubscribes, keeps the suppression list
        ▼  30 days later, both groups checked against the book
[ Grist ]  returned: messaged 8/36 · held back 2/4  → your real uplift

The detector is arithmetic. The model only reads notes. You do the sending decision.

Three containers on one box, and a deliberate split of responsibilities. Grist holds the truth and does the maths in formula columns you can actually see. n8n does the weekly timing and the list assembly. Listmonk does the one thing you should never hand-roll, which is sending mail to real people and honouring their unsubscribes. Keep them separate and you can swap any one of them without losing the customer table, which is the only part that is really yours.

The problem

A customer leaving does not look like anything. There is no cancellation, no complaint, no email. There is a Tuesday in March when they would normally have booked, and they didn't, and nothing happened, because nothing happening is exactly what an absence looks like. Eight months later you notice the name is not in the book any more and you cannot say when it stopped.

These are the cheapest customers you will ever get back. You already paid to acquire them, they already know where you are, they already trust the work. And the whole intervention is one message, sent at roughly the right moment, to the right forty people out of six hundred. The reason it does not happen in most small businesses is not that owners do not care. It is that the list does not exist. Working out who is overdue means comparing every customer against their own habit, and nobody does that by hand on a Sunday.

One honest note before the architecture, because this category is thick with numbers and thin with evidence. You will read that win-back campaigns reactivate 15–30% of dormant customers, that the payback is 23 days, that the return is 47:1. Every one of those figures I could trace back ends at the blog of a company selling win-back software, and not one of them describes a control group. That matters more here than in most places, because a large share of the people you message were coming back anyway. Message them, they return, and the software takes the credit. So this blueprint uses none of those numbers. What is verifiable is the price of the alternative — marketing-automation tiers that carry this feature start around $20–45/month at small list sizes and climb with your contact count — and your own arithmetic: your average ticket, times the customers who are genuinely overdue, times a return rate you should assume is 1 in 20 until your own data says otherwise. Do that sum before you build anything. If it comes out small, close the tab.

Tool choices — and why

Grist
(Apache-2.0, 11.5k stars, commit today — 13/08/2026) is the customer table and, more importantly, the place the detection logic lives in the open. Two things earn it the container. First, its formula columns are Python, so "median gap between this customer's visits" is one readable line rather than a query nobody can check. Second, and this is the part that matters for a business owner: you can look at the column, see the number, and disagree with it. A detection rule you cannot inspect is a detection rule you will eventually stop trusting and quietly ignore. A spreadsheet does this fine for the first year, right up until someone takes a copy "just to try something".
n8n
(Sustainable Use License, free for internal business use, 200.5k stars, commit today) runs the week. Scheduled trigger, read Grist, apply the caps, split off the holdout, write drafts back, wait for your tick, hand the approved rows to Listmonk, then a second scheduled job 30 days later to check who came back. It has a documented Grist node, so most of that is configuration. If you already run the no-show reminder engine or the review request engine from this library, this is the same instance doing another job.
Ollama
(MIT, 178.5k stars, commit today) has exactly one job, and it is a defensive one. Your notes field contains sentences like "moved to Spain, last visit before she left", "husband called, she passed away in March", "argued about the bill, comped it, not a good fit". A model reads those and sorts them into contactable or excluded-with-a-reason. It is not allowed anywhere near the question of who is lapsed — that is a median and a multiplication, and arithmetic does not hallucinate. Fencing it this way is the whole point: a wrong exclusion label is one line you read and correct in the review table, whereas a model that invented the overdue list would hand you a plausible set of names with no way to tell the good ones from the confident ones. A small 7–8B model handles this and runs on the same box.
Listmonk
(AGPL-3.0, 22.8k stars, commit today) sends. You could send from n8n over plain SMTP for twenty messages a week, and for a first pilot that is fine. What Listmonk buys you is the boring compliance machinery you must not build yourself: a working one-click unsubscribe, a suppression list that is actually honoured on the next campaign, bounce handling so you stop mailing dead addresses, and per-campaign delivery stats. It is one Go binary plus Postgres. The customer newsletter engine in this library runs on the same install.
Monthly cost
Software €0 for all four. One VPS at roughly €5–12/month runs Grist, n8n, Ollama and Listmonk together at this scale — give it 8 GB of RAM if the model is on the same box, or run Ollama on an office machine and let the VPS stay small. Email at 20–40 messages a week costs nothing through your own mailbox's SMTP or a transactional sender's free tier. SMS is the only real variable and it is optional: roughly €0.01–0.10 per message depending on country, so a forty-message week is under €4. Set that against $20–45/month, rising with your contact count, for a marketing suite that also keeps the list.

Setup outline

1. Do the arithmetic on paper first. Average ticket × the number of customers who look overdue × a return rate of 1 in 20. If that number does not justify a weekend, stop here — and that is a real outcome, not a failed one.
2. Export your customer history: name, contact, every visit date, every amount, and the notes field. Two years minimum, because one year cannot show you an annual customer. Load it into Grist.
3. Build the two formula columns. own_gap = the median of the differences between that customer's visit dates. days_since = today minus their last visit. Use the median, not the average — one long holiday or one house move drags an average sideways and quietly hides a genuinely lapsed regular.
4. Set the rule: overdue when days_since > own_gap × 1.5, and only for customers with three or more visits. Two visits is not a rhythm. For everyone below three, fall back to the median gap across your whole customer base for that service.
5. Calibrate against yourself, not against a blog. Sort by overdue and read the top twenty names. If you find yourself saying "no, he only ever comes at Christmas", the multiplier is too low. Move it until the list matches your own judgement. This step is the blueprint. Everything else is plumbing.
6. Build the exclusion pass. Run the notes field through the local model, one customer at a time, output a label and a one-line reason into its own column. Then read every single one of them yourself the first time. You are checking that it catches bereavements and complaints, and the cost of a miss here is not a bad metric, it is a phone call you will remember.
7. Add the caps in n8n: never message the same person twice in 12 months, never more than 40 in a week, and after two ignored win-backs mark them gone and stop forever. A machine with no upper bound turns a good idea into a nuisance in about six weeks.
8. Add the holdout. Randomly flag 1 in 10 of the eligible list as control and send them nothing. Record the flag — you need to know later who was in which group.
9. Write the drafts to a review table. Your tick is the only thing that sends. Run it in draft-only mode for two full weeks before a single message goes out.
10. Wire Listmonk, and set up SPF, DKIM and DMARC on the sending domain before the first real send. Ten minutes of DNS now, or a year of messages quietly landing in spam and a "nobody replies to these" conclusion that is wrong.
11. Thirty days after each batch, check both groups against the booking system and write the result back to Grist. Messaged: how many returned. Held back: how many returned. The difference between those two rates is the only honest number in this entire blueprint.

Pitfalls — the real ones

Without the holdout, you will measure the wrong thing and believe it
This is the failure that matters and it is invisible, because the wrong answer is flattering. Say 12% of the people you message come back. If 9% of the ones you ignored also came back, your machine bought you three percentage points, not twelve. Every discount you attached to those messages was pure margin given to people who were already walking through the door. Ten percent held back costs you almost nothing and is the difference between running a system and telling yourself a story about one.
The exclusion list is the safety-critical part, and it decays
Messaging someone who died is not a metric, it is a wound you open in a family and a story that gets told locally for years. Treat any record with no note and no recent activity as unknown rather than contactable, re-read the exclusion column every quarter, and keep the weekly list short enough that a human genuinely reads the names rather than scrolling past them.
The average will lie to you; the median will not
A customer who comes every 6 weeks, went away for 5 months once, and has come every 6 weeks since has an average gap of about 11 weeks. On the average they look fine at week 10. On the median they were overdue three weeks ago. Small detail, and it is most of the accuracy.
Discounting by reflex is the expensive habit
The first message should be a note, not an offer. Save any incentive for the second contact, to the people who ignored the first, and only after the holdout has told you the plain message does not work on its own. Once you train a customer base that going quiet produces 15% off, you have not won anyone back, you have taught your regulars to wait.
Permission is not a technical question and this blueprint does not answer it
The mechanics are here: a working unsubscribe in every message, a suppression list that is honoured, clear identification of who is writing. Whether you may message a past customer at all, and on which channel, depends on where you and they are and on how the relationship started. Ask whoever advises you on it, once, in writing, before the first send. SMS in particular is a different regime from email in most places.
Frequency-of-visit is not the same as value
Rank the list by what the customer was worth, not by how overdue they are, or your weekly forty will fill up with the cheapest, flakiest end of the book while the customer who spent €400 twice a year sits at position 300.
Seasonal businesses need a season-aware rule
If half your customers only appear between April and September, a flat multiplier flags your entire book every January. Compare like with like: same period last year, not the last N days.
The export goes stale silently
If you feed this from a weekly CSV and the export breaks, nothing errors — the table just stops moving, everyone slowly looks lapsed, and one Monday you generate a list of forty people who were in last week. Put the export date on the dashboard and refuse to build a list from data older than eight days.
You are now holding a customer list outside the system that made it
That is the point of the blueprint, and it comes with the duties: restore-tested backups, a real password on the box, and a deletion path for anyone who asks. There are blueprints in this library for both.

Verified repos

Grist — Apache-2.0, 11.5k stars, commit today (13/08/2026)
n8n — Sustainable Use License (free self-hosted internal use), 200.5k stars, commit today (13/08/2026)
Ollama — MIT, 178.5k stars, commit today (13/08/2026)
Listmonk — AGPL-3.0, 22.8k stars, commit today (13/08/2026)

Get the next blueprint as it publishes — free, practical, verified tooling only.

Subscribe · Want this audited or extended for your business? DM @RXed_EU