Next-Best-Action Policy
Turning scores into decisions under real constraints: capacity, contact fatigue, margin, cooldowns, and the explicit option of doing nothing.
The decision it encodes
Which action, if any, should this customer receive right now?
You have uplift estimates. A model says this customer is worth 4.1 points of retention if she gets the winback offer, 1.2 if she gets the feature nudge, and nothing measurable from the newsletter.
She is also eligible for three other campaigns this week, has already received two messages, sits under a four-contact monthly cap, and the winback offer costs five dollars of margin to serve. The email platform can send 200,000 messages before Friday and eligible demand is 340,000.
The score does not tell you what to do. Everything that decides what to do lives in the sentence after the score, and that is what this component is.
The decision it encodes
Which action, if any, should this customer receive right now?
The “if any” is not a formality. It is a candidate with a real value, and a policy that cannot choose it will contact everybody whose score is not negative.
Scores rank people. Constraints decide the plan
The objective is expected incremental value over the horizon the outcome contract names, and every term in it is already available if the components underneath this one exist: the per-state incremental effect from effects by state, margin from finance, cost from the channel. The full version nets more than the send: discount leakage to customers who would have paid, cannibalization of a purchase that would have happened anyway, the contact’s claim on a fatigue budget another action wanted, the expected opt-out cost, and the uncertainty in the effect estimate itself, which argues for shrinking a small segment’s score toward the average before ranking on it.
The constraints are where the work is.
| Constraint | What it does to the decision |
|---|---|
| Consent and suppression | Hard filter, applied first and never traded off. Not a cost term. |
| Channel capacity | Shared across every campaign, so one campaign spending it takes it from another. |
| Contact fatigue caps | A per-person budget over a rolling window, spent by whichever campaign gets there first. |
| Cooldowns | Per action or per theme, so the same offer does not arrive twice in a fortnight. |
| Cost to serve | Sets the break-even uplift. A free email and a five-dollar discount are different decisions. |
| Exclusivity | Two live tests that may not touch the same person, inherited from the registry. |
Consent is the only one that is a filter. The rest are budgets, and a budget that gets spent first-come-first-served is a budget nobody is allocating.
The break-even rule for a single action is settled elsewhere: contact when estimated uplift exceeds cost over margin, which is not the same as contacting everyone with positive uplift. Uplift Modeling in Practice works through why that distinction flips the sign of a program.
What that rule does not handle is a shared budget. When capacity binds, the question stops being whether this contact pays for itself and becomes whether it pays better than the contact it displaces.
Greedy per-person scoring quietly overspends
The natural implementation processes customers one at a time, picks each person’s best eligible action, and stops when capacity runs out. It is simple, it is what most systems do, and it allocates the budget to whoever the job happened to process first rather than to whoever was worth the most.
The fix is to treat capacity as a price. There is some threshold value at which the number of contacts worth making equals the number you can make. Find it, then contact everyone above it and nobody below. That threshold is the value of the marginal contact, and it is the number the organization is short of.
The no-action arm has to be a real candidate
Doing nothing has a value, and for a good part of any population it is the highest one. Sure things convert anyway, and a campaign spent on them buys nothing. Sleeping dogs convert unless you interrupt them.
A policy that treats no-action as what happens when no campaign qualifies will never learn this, because it never records a decision to leave someone alone and so has no evidence about it. Scoring the null action explicitly, and logging it as a decision like any other, is what makes leaving people alone something the system can get better at.
Some exploration is not optional
A policy that always takes its current best guess produces logs from which no other policy can be evaluated. Every alternative action has probability zero in the data, so nothing can be reweighted, and the only way to test a change is to ship it and wait.
Keeping a small amount of randomization, and writing down the probability each action carried, is what makes the loop close. Exposure and Decision Logging is where those probabilities land, and without them this component can act and cannot improve.
Maturity, honestly staged
Stage 1: one ranked list per campaign, with a break-even cut. Cost and margin enter the decision. Most programs never get here and cut at a decile instead.
Stage 2: shared fatigue and capacity budgets across campaigns. Contacts stop being allocated by job order. Requires a registry and a customer state model to be worth anything.
Stage 3: a threshold solved from capacity rather than picked. The marginal contact gets a value, and capacity arguments become quantitative.
Stage 4: explicit no-action scoring and logged exploration. The policy can learn that leaving people alone was right, and new policies can be evaluated before they ship.
Solving for the threshold Technical
With one shared capacity constraint, the allocation is a knapsack whose
continuous relaxation has a clean answer. Give each candidate action a net
value of uplift × margin − cost. Sort descending, take actions
until capacity is exhausted, and the value of the last one taken is the
threshold. Everything above it is worth doing, everything below is not, and
the threshold is the shadow price of a contact.
With several constraints at once, per-person caps as well as a channel total, the same idea generalizes to one price per constraint. Iterating between prices and assignments converges quickly in practice, and the prices are more useful than the assignment: they say which constraint is binding, which is the thing worth spending money to relax.
Two cautions. The relaxation assumes actions are divisible, which they are not, though with a large population the rounding is immaterial. And the threshold inherits every error in the uplift estimates, so a policy that solves the allocation exactly on bad scores is precise about the wrong plan. The scenario planner makes the same point at channel level.
Context
Best suited for
Programs where several campaigns compete for the same people and the same channel capacity, and where the cost of a contact is high enough that contacting everyone eligible is not viable.
Data requirements
- Uplift estimates per person and action, from a design that supports them rather than from a propensity model
- Cost to serve per action and margin per outcome, at a grain finance recognizes
- Contact history and channel capacity as live numbers rather than quarterly assumptions
- A logging path that records the chosen action, the alternatives, and the probability each carried
What changes by context
- Lifecycle-led
- The canonical setting: many campaigns, one contact budget, and a fatigue cap that several programs are quietly competing for. The shared budget is usually the binding constraint and almost never the one being optimized.
- B2C subscription
- Discount-bearing actions make the cost term large, so the break-even uplift sits high and the profitable population is much smaller than the positive-uplift population. This is where scoring the no-action candidate pays for itself.
- B2C ecommerce
- Cadence is fast and cooldowns matter more than capacity, since the failure is contacting the same person about the same category three times in a week rather than running out of sends.
When it breaks down
- No uplift estimates, only propensity scores. The policy will rank by likelihood to convert and systematically spend on people who needed nothing.
- Capacity that never binds and contacts that are effectively free, where the threshold collapses to zero and a ranked list is enough.
- Actions whose cost or margin nobody will state, since the break-even rule cannot be computed and the cut ends up arbitrary again.
- Organizations where campaign owners can bypass the policy, in which case it allocates only the traffic nobody wanted.