Unknown Behavior

Case study · Lifecycle & growth

An engagement engine that decides who gets pushed, and when.

ZONA's retention runs on push, but blasting everyone burns the channel. I built the engine that runs nightly, decides per user rather than per blast, sends only through hard guardrails, and watches its own tap rates so the channel stays alive instead of training people to mute it.

01 · The problem

Blast notifications are a loan against retention.

Push is the cheapest way to pull someone back into a nightlife app, and the fastest way to lose them. Send the same blast to everyone often enough and the opt-outs and mutes pile up, which quietly kills the one channel that brings people back. The growth move is not sending more, it is deciding, per person, whether a message is worth the cost of sending at all.

That decision is too nuanced for a scheduled blast. It depends on who the user is, what they have already been sent, how they have responded, and whether tonight is even relevant to them. I wanted that judgment encoded, applied to every user every night, and held to guardrails I could trust.

02 · The work

Profile each user, gate every send, and let it self-correct.

The engine runs nightly on a schedule in Miami time. For each user in the program it builds a profile, evaluates the candidate triggers, and chooses the message that fits, rather than firing the same thing at the whole base.

Every candidate send passes through suppression gates before it is allowed out: a daily cap so no one is overloaded, a recency floor so messages are not stacked too close together, an open-rate backoff that eases off users who have stopped engaging, and a seven-day per-trigger cooldown so the same message cannot chase someone. What the engine declines to send is as important as what it sends.

I rolled it out cohort-gated, so the new engine drives one group while the rest stay on the existing model, which makes the change measurable and safe to expand. And it monitors itself: a nightly job recomputes each trigger's tap rate over a rolling window, so underperforming triggers surface and get paused instead of quietly burning the audience. The whole thing reports its run health, delivered counts, skip reasons, and failures, so it is observable rather than a black box.

03 · Outcome

A retention channel that's governed, not gambled.

Nightly Per-user decisions the engine runs on a schedule, Miami time, and decides per person
4 gates Guardrails before every send daily cap, recency floor, open-rate backoff, 7-day per-trigger cooldown
Per-trigger It watches itself tap-rate tracked nightly so weak triggers get paused, not repeated
Cohort-gated Rolled out safely shipped to a cohort, not blasted at the whole base at once

04 · Behind the work

How I think about it.

Most push systems optimize the wrong thing. They make it easier to send. The leverage is in restraint: the gates are the product, because they protect the channel that the whole retention strategy depends on. A muted user is gone for good, and no clever message wins them back.

The self-monitoring loop is the part I am proudest of. Tying each trigger to its own tap rate and pausing the losers means the system gets better without me babysitting it, and every decision about the channel is made on response data instead of instinct.