How the Optimizer Works
The decision system that pauses, launches, and scales ads. Inputs, outputs, guardrails, and what to expect during the learning phase.
The optimizer is the most consequential thing Layers does for you. It runs every 6 hours per ad layer (Meta, TikTok, Apple Search Ads), evaluates each campaign, adset/adgroup, ad, and keyword, and proposes actions such as:
- Pause an entity that's burning budget without converting.
- Adjust budget (up or down) on an entity with strong or weak unit economics.
- Adjust bid (Apple / TikTok keywords).
- Hold (no action) — the most common outcome, by design.
Proposed actions then pass through a guardrail approval stage; only approved actions are executed.
Inputs
For each entity, the optimizer reads:
| Input | Source |
|---|---|
| Spend (1d, 3d, 7d, 14d, 30d windows) | Platform metrics (meta_ad_level_daily_metrics, tiktok_ad_level_daily_metrics, apple_ads_*_daily_metrics) |
| Conversions / installs | Same tables |
| CPA | spend / installs per window |
| CTR, CPM, conversion rate | Platform metrics |
| Fatigue indicators | Frequency (Meta), trend of CPA across windows |
| Age | Days since entity creation |
| Creative pool | generated, ugc, or manual (used at selection time, not pause time) |
ads_content.organic_score is used when selecting new creatives to launch —
it does NOT pause already-running ads.
Decisions
The optimizer assigns each ad (and each adset, adgroup, campaign) one of the following classifications every cycle:
TOO_YOUNG— under 3 days old. Never paused.LEARNING_PHASE— platform reports the entity is still in learning. Never paused.TOP_PERFORMER— performance score ≥ 80. Never paused.HEALTHY— performance score ≥ 50. Never paused.UNDERPERFORMING— CPA materially above pool average, or low performance score.FATIGUED— CPA degraded over time, frequency high, sufficient spend.CRITICAL— >$50 spent with zero installs in 7d, or CPA > 2.5× pool average.
Only UNDERPERFORMING, FATIGUED, and CRITICAL entities are eligible for
pausing. Every decision is gated by the
guardrails.
Guardrails
Hard rules that gate every proposed action:
- Min age 3 days before any action on an entity.
- Min $5 spent before a pause action in the content-refresh disable step.
- Min 100 impressions before budget/bid changes.
- Never disable ads classified
TOP_PERFORMERorHEALTHY. - Never leave an adset/adgroup empty.
- Max 50% budget change per cycle, and never more than $100 absolute.
- Max 40 total actions and 20 pauses per cycle.
- Cooldowns between actions on the same entity: 48h for structural and budget changes, 24h for bid changes.
- Manual overrides win —
override = 'include'keeps a creative eligible regardless of score;override = 'exclude'forces ineligible.
These rules exist so the optimizer never bricks an ad account by pausing or rebalancing everything during a noisy day.
Why a low organic score doesn't pause running ads
A common confusion: the organic score affects which creatives are picked
for the next launch. It doesn't pause already-running ads. If a creative's
organic score decays below 4.0 while it's running, it stays running — the
optimizer is purely watching ad performance metrics (CPA, fatigue, CTR).
This intentional split prevents thrash: an ad with a great CPA but aging organic score wouldn't be killed mid-run.
See Organic scoring and Ad eligibility for the full picture.
Cycle cadence
| Layer | Optimizer interval | Emergency watchdog |
|---|---|---|
| Meta Ads | every 6 hours | every 2 hours |
| TikTok Ads | every 6 hours | every 2 hours |
| Apple Search Ads | every 6 hours (at :30) | every 2 hours |
The watchdog is a lightweight safety check that auto-pauses entities with catastrophic spend patterns (e.g., $50+ spent and 0 installs) between full optimizer cycles.
Reading optimizer decisions in the UI
Each optimizer run writes its proposals, approvals, and rejections (with
reasons) to the project's workflow-run history. Open the layer detail page
and look at the most recent ad-optimize run to see:
- Classifications assigned to each entity and the metrics that drove them.
- Proposed actions, and whether each was approved or rejected by guardrails.
- Reasons actions were rejected (e.g., "Entity too young (2d < 3d minimum)").
Pausing the layer
If you need a freeze (e.g., during a launch week, regulatory review, or system incident), use the Pause action on the layer's Danger zone. While paused, no scheduled commands run — the optimizer stops proposing or executing actions until you resume.
Next
- Safety guardrails in detail.
- Reading the dashboard.