# Organic Scoring (/docs/concepts/organic-scoring)



Every piece of content (organic or generated) gets an &#x2A;*`organic_score`*&#x2A; from
0 to 10. The score determines whether the content is eligible to be promoted as
an ad. The threshold for eligibility is &#x2A;*`organic_score >= 4.0`**
(`ELIGIBILITY_THRESHOLD = 4.0`).

Score is recomputed every 4 hours by the
[organic performance schedule](/docs/concepts/scheduler#global-cadence),
which runs per-project scoring workflows.

## Three pools [#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 [#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-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 [#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 [#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 [#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 [#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 [#where-to-see-the-score]

* [Creative library](/docs/paid-media/creative-library) — score column.
* Per-creative detail panel — score history.
* [UGC posts](/docs/ugc/posts) — score column.

## Next [#next]

* [Ad eligibility](/docs/concepts/ad-eligibility) — how scores feed adset selection.
* [Creative lifecycle](/docs/concepts/creative-lifecycle) — generated → live → fatigued → refreshed.
