Organic Scoring
How Layers ranks creatives 0–10 to decide what becomes ad-eligible. Generated content, UGC, and manual content each have their own scoring pool.
Every piece of content (organic or generated) gets an organic_score from
0 to 10. The score determines whether the content is eligible to be promoted as
an ad. The threshold for eligibility is organic_score >= 4.0
(ELIGIBILITY_THRESHOLD = 4.0).
Score is recomputed every 4 hours by the organic performance schedule, which runs per-project scoring workflows.
Three pools
| Pool | Source | Default score | Decay / freshness |
|---|---|---|---|
generated | Layers AI generations | 7.0 | linear decay to floor 2.0 over 30 days |
ugc | Creator posts (via SIFT) | 0 (until views threshold met) | 90-day freshness window, up to +1.5 freshness bonus |
manual | Manually uploaded creatives | scored using the generated formula (default 7.0 with 30-day decay) | linear decay to floor 2.0 over 30 days |
Why three pools? Each kind of content has a different signal-to-noise ratio. A 14-day-old AI-generated video is rare and worth amplifying. A 14-day-old UGC video has accumulated real engagement metrics — you should score it on that, not on age alone.
Generated content scoring
score(t) = clamp(2.0, 10.0,
7.0 - 5.0 * (ageDays / 30) + adBoost
)
adBoost = min(3.0, totalSpend30Days / 33.3)In English:
- Default at creation: 7.0.
- Linear decay to a floor of 2.0 across 30 days. Without ad boost, a piece of generated content stays eligible (score >= 4.0) for ~18 days.
- Ad boost of up to +3.0 if it accumulates ad spend (capped at $100 of spend in the trailing 30 days = max boost).
- High-performing ads stay eligible indefinitely — floor 2.0 + max boost 3.0 = 5.0, which is above the 4.0 threshold.
UGC scoring
UGC scores are derived from real engagement. Inputs (combined with a base multiplier to produce the 0–10 output):
- Quality (weighted 45%) — engagement-rate percentile within the project's UGC pool.
- Reach (weighted 25%) — impressions percentile.
- Outperformance (weighted 30%) — how much the post beats the project's UGC baseline.
- Freshness bonus up to +1.5 within a 90-day window.
- Min 50 views — posts with fewer views aren't scored.
- Min 3 posts in the pool before scoring runs at all.
UGC below 4.0 is not ad-eligible. UGC that ages past 90 days loses the freshness bonus and typically falls below threshold.
Manual scoring
Content with scoring_pool = 'manual' is treated as generated content — it
starts at 7.0 and decays linearly to 2.0 over 30 days, with the same ad-spend
boost. If you want a manual creative to stay eligible regardless of
auto-score, set project_ads_content.override = 'include'.
Overrides
Two columns on project_ads_content give you escape hatches:
override = 'include'— bypass the 4.0 threshold; this ad is always eligible.override = 'exclude'— force ineligible regardless of score.override = null— auto-score governs.
Use overrides sparingly. They are applied per project (so a single piece of ads_content can be eligible in one project, excluded in another).
Safety failures
If a piece of content fails safety review (safetyFailed = true), score is
forced to 0 regardless of pool, decay, or boost. Safety failures cannot be
overridden — you must regenerate the content.
Score drift across versions
The scoring algorithm is versioned. Each ads_content.scoring_version
records which version produced its current score. When the algorithm
changes (weighting tweaks, pool-formula updates), every row is rescored
on the next cycle and scoring_version is bumped.
Where to see the score
- Creative library — score column.
- Per-creative detail panel — score history.
- UGC posts — score column.
Next
- Ad eligibility — how scores feed adset selection.
- Creative lifecycle — generated → live → fatigued → refreshed.