Engine (automatic optimization)
The Engine is the arbitration engine for your campaigns. It opens from the Engine tab of the Ads page (/ads/arbitrage); the screen title is "Arbitration engine". This documentation page keeps its former address (copilot): the product used to be called "Copilot".
Since September 2026 there is only one engine: arbitration and the former "rules engine" were two places for the same thing. The client sees one Engine tab; the legacy engine stays reachable by the DURUM team while its rules are migrated (see The legacy engine).
Discovery plan
On the Discovery plan, the engine and ad rules run in simulation only: you see every decision and its reason, nothing is written to the ad networks. Apply mode requires a paid tier (error plan_free_no_autopilot).
What it does, and what it never does
The engine runs every hour on every enabled rule. It only makes two moves: shift budget and pause (or resume). On request it also refills an ad set that empties, from the Library. Never deletes. Every decision carries its reason, every applied decision can be undone, and every run re-reads the networks live and logs what changed by hand.
It judges on your DURUM.ai conversions, attributed by ID, hence comparable across networks. Four networks: Meta, Google Ads, TikTok and ChatGPT Ads. The engine writes where the budget lives (campaign, ad set, ChatGPT cap).
A rule in four questions
A rule reads the way a media buyer thinks.
Header: what the rule does
| Setting | Options |
|---|---|
| This rule does | Three independent switches: Redistribute budget, Cut ads, Feed from the library |
| Mode | Simulation (every run is logged, nothing is written to the networks) or Apply |
| Slack | Notify on Slack: one line per decision actually written, on your "Engine actions" channel |
1. Scope
A tree of networks → campaigns → ad sets, with checkboxes. Nothing ticked = the whole account. Every campaign says where its budget lives: campaign budget, ad set budget, ChatGPT cap or shared budget, by hand. Google campaigns that share one budget are ticked and arbitrated together, as a single node: you cannot pick just one. Paused campaigns with no spend are collapsed.
On every node, Exception opens settings specific to that node, different from its level; greyed values are inherited. Exceptions are listed in plain words under the tree.
2. Arbitration KPI and guard rails
- Arbitration KPI: the metric the engine optimizes, picked from the account's catalog: CPL, cost per event (booking, held booking, sale…), custom conversion, ROAS, CTR, CPC, CPM.
- Window (days): the period read to judge, 1 to 90 days.
- Account for the conversion delay: see below.
- Guard rails, which come before any arbitration on the objective: Minimum volume (at least N conversions of a metric over the window, whole scope), Maximum cost (never more than X per another metric), Minimum ROAS. A node that breaks a guard rail loses budget first; an ad that breaks it is cut (after the minimum spend).
3. How it judges: the ladder
Nobody types a dollar threshold: the scope computes its average on every run (total spend ÷ total conversions), and everything reads in multiples of that average. Guard rails are judged in order, the objective at the top: that is the ladder.
| Setting | Default | Role |
|---|---|---|
| Gate | 3 × the average | A spend: nothing is decided on a line before it has spent this multiple of the average cost. It never cuts before 3 × |
| Stop | 2 × the average | A cost: past the gate, a line above this multiple of the average cost is cut |
| The +1 rule | Yes | It never cuts if one more conversion would bring the line under the stop |
| Living threshold | Yes, bounded from 0.5 × to 2 × | A line's stop follows its yield on the next rung: an expensive line that converts better keeps its licence. Only applies with enough data |
| Dead zone | 8% | A budget is not written for a smaller gap: it avoids the yo-yo that shakes the network's learning |
The Absolute mode (amounts typed in the account currency) is the old mode: a typed amount ages. A rule written before the ladder stays absolute; a new rule judges in multiples.
4. Budget and split
- Envelope: Keep the current total of budgets, or an Amount per day. Monthly cap (0 = none).
- Hold the envelope on a target: the day's envelope follows a 30-day target, catches up when behind, brakes when ahead, between a floor and a cap (% of pace), with a smoothing in days.
- Split by level: the envelope goes down level by level, between networks, then between campaigns, then between ad sets. At each level: By results (the best on the objective gets more, within bounds), Equal shares, or Leave as is.
- Advanced settings per level: minimum and maximum share (networks, campaigns), floor and cap per day (ad sets), maximum step per run, learning (share guaranteed to a node with no data), Minimum conversions, Verdict threshold, confidence, and Pause when empty (ad set paused when no ad runs in it anymore).
5. Ad cuts
| Setting | Default | Role |
|---|---|---|
| Benefit of the doubt | Yes | Never cut if a conversion arrived in the last 24 h |
| Protect top N | 2 | Never cut |
| Resume | No | Puts an ad cut by the engine back online if its metric comes clearly back under the threshold |
Maximum cost, Minimum spend (40), No conversion | Absolute mode only | Carried by the ladder in multiples mode |
6. Feed from the Library
Nothing to set: one switch. When an ad set empties, the Library republishes: one cut, one republish, never a duplicate, always paused (an added ad is never active before its copy is reviewed). The angle is read from the Library (creative tags), from the ad names or from the ad set name; without a recognized angle, the engine publishes nothing in that ad set. Destination, button, page and UTMs are those of the ads already running in the ad set. The panel shows, per ad set in scope, the recognized angle and the number of ready creatives.
The verdict gate
Spend is directed neither to nor from a node until it has two things:
- enough conversions: Minimum conversions, default
5; - enough spend: Verdict threshold, default
3 ×the metric's reference cost (3 × the cost of a booking = we wait for 3 bookings' worth of spend).
Under the gate the node's budget is frozen and leaves the envelope; the reason shown says what is missing ("budget unchanged, not enough hindsight to decide: 2 bookings out of the 5 required"). Fewer than two judgeable nodes at the same level = no verdict, nothing moves. A broken guard rail comes before the gate. Ad-level cuts keep their own gate: an ad burning without converting does not need 5 conversions to be cut. Each level (networks, campaigns, ad sets) has its two values, adjustable; 0 disables the criterion.
Cuts first, verdict next
On every run, the engine cleans the ad set (underperforming ads cut) then measures it on what remains. A dead ad, cut on this run or before, no longer weighs on its ad set, its campaign or its network. Otherwise the ad set would pay for the whole window for money burned by an ad that no longer runs.
The conversion delay
On by default on every rule, including those written before it existed. The engine measures the delay curve of the account itself and shows it: "half of the sales arrive in under 9 d, nine out of ten in under 47 d". It then leaves out of the calculation the spend too recent to have converted, instead of penalizing an ad that just launched: the gate counts spend old enough to convert, weighted day by day. Without a reliable curve (fewer than ten observations), it judges raw spend and does not guess. Unticked, an ad launched yesterday is judged like an established one.
What the account knows: calibration
Under the KPI, a "What the account knows" card measures the scope for that metric: average cost, median per ad, median delay, 90% arrived by, suggested gate (3 × the average), suggested stop (2 × the average) and suggested window (the 90% delay, bounded from 7 to 90 days). A confidence level comes with the numbers: solid, thin or insufficient (no suggestion). The Use these numbers button switches the rule to multiples and sets the window. These numbers come from your account only, never from another client. Calibration decides nothing: it measures and suggests.
Simulate, save, enable
| Button | Effect |
|---|---|
| Simulate now | Computes the decisions over the window and shows them under the rule. Nothing is written to the networks |
| Save | Saves the rule |
| Enable / Disable | An enabled rule runs every hour, in its mode |
| Apply now | On an enabled rule in Apply mode: a run right away |
Every rule card carries its state: simulation, applied or disabled, its switches, its metric, its window, its envelope, and its last run (budgets, cuts, changes by hand). Nothing is written until the rule is in Apply mode and enabled.
Look before you apply
Simulate as much as you want. A rule left in simulation for a few hours already tells you which budgets it would move and which ads it would cut, with its reasons.
The rule in plain words
Under "What this rule will do", the rule is written in sentences, updated with every setting. For example: "Allocates the current total of budgets between ad sets toward the best cost per lead. Judges in order cost per lead: nothing before 3 × the average cost spent on the line, cuts above 2 × that cost, unless one more conversion would bring it under the stop, the stop following the line's yield. A budget is only written for a gap of at least 8%. No deletions, ever: only pauses and budgets, all undoable."
The result of a run
Every run shows:
- tiles: budgets, cuts, resumes, to publish, applied, unchanged;
- context chips: simulation, envelope, envelope held, the scope ("average → gate, stop"), maturity known or unknown, every guard rail with its value and target;
- the changes made by hand in the networks since the previous run (budget, status, new node);
- a table Level · Node · Decision · Before → after · Metric · Reason. The reason shows the ladder, rung by rung. Decisions without change are hidden by default ("Show the N unchanged").
Undo
Every applied decision carries an Undo button: the budget goes back to its previous value, the ad or ad set goes back online, and the undo is logged as a run of its own. The engine may take its decision again the next hour if the rule is still enabled in Apply mode.
Slack
When Notify on Slack is on for a rule, every applied run posts one line per decision actually written, in the account's language and currency, on the channel of the Engine actions category (otherwise the performance alerts channel):
Arbitration · My rule
• Meta · ad set Retirement Quebec: $120 → $150 per day · reason
• Meta · ad Retirement T2-I3 paused · reason
Undo in the app: Ads → Arbitration → Latest decisions.Never posted: simulations, decisions without change, a run already notified. A decision refused by the network is reported with its message. See also Alerts & Thresholds.
Safety
- Never deletes: the engine pauses and moves budgets; it deletes neither an ad, nor an ad set, nor a campaign.
- Simulation by default: a new rule is in simulation and disabled. Nothing is written until it is in Apply mode and enabled.
- Verified settings: an inconsistent rule is refused on save, with the list of errors.
- Verdict gate: no budget moves on a node without enough conversions and enough spend.
- Paused publishing: an ad republished by "Feed" is never active before its copy is reviewed.
- Networks re-read live: every run re-reads structure and spend, and logs changes made by hand.
- Everything undoable and traced: every applied decision has its Undo, every run is in the Journal.
The Journal
The Journal tab (/ads/historique) is the single log of your ads. It composes a feed, grouped by day, from everything that touches your ads:
| Filter | What it shows |
|---|---|
| Engine | Cut / Would have cut (simulation), Budget adjusted, Ad set paused, Undone, Engine error, Launched by the engine (with spend, leads, CPL, ad set) |
| Launches | Every launch, with its source (reserve, import, backfill, detected on Meta, by the engine) |
| Library | Imports ("N ads imported from Meta"), scoring ("N ads tagged and scored"), generated variants |
| In the app | Pauses and reactivations done in the app, undo requests, engine settings changed (rule enabled or disabled, simulation or armed), changes made by hand in the network |
| API and MCP | API calls (method, path, response code) |
| Syncs | Failed syncs, with the cause (request limit, lost access, error) |
| Sent to platforms | Events sent, refused or not sent (filter) to Meta, Google Ads, TikTok, ChatGPT Ads, LinkedIn, Snapchat, Whop |
Period: 7, 14, 30 or 90 days. Every engine action that is still reversible (applied, not already undone) carries its Undo button.
The Engine run details link (/ads/moteur/historique) opens the per-run history inherited from the legacy engine: totals (runs, applied, ads cut, budgets adjusted, ad sets paused, errors, last run), filters Rule, Period (7, 30, 90 or 180 days) and Show (Changes only, Ad cuts, Budget reallocations, Errors, All runs), with APPLIED or SIMULATION on every run.
The legacy engine
The Legacy engine tab (/ads/moteur, titled "Rules engine") is visible to the DURUM team only. It still runs every hour on the existing rules, while they are migrated to the Engine, then it will disappear.
What it still does: one rule per campaign (objective, 7-day window by default, target cost, cut above a cost, minimum spend before cut of 40, ad set floor budget, reallocation), three temperaments Cautious (cuts late, moves little), Balanced (recommended) and Aggressive (cuts fast, concentrates), simulation by default, arming by a human action, a plain-words sentence ("Cuts an ad at $90 / lead or above, after $45 spent. Plus-one grace: never cuts if one more conversion would bring the ad back on target. No deletions, ever: only reversible pauses."), and Latest engine actions (14 days) with Undo. Its applied cuts also appear in the Journal and in the Slack alert "An ad cut by the engine".
WARNING
Do not create a new rule in the legacy engine. Every new rule goes in the Engine tab.